diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 000000000..f41ee865c --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,9 @@ +*.log +node_modules/ +public/ +.idea +drafts +yarn.lock +app/components/ui/SVG.js +*.DS_Store +.env diff --git a/frontend/.storybook/config.js b/frontend/.storybook/config.js new file mode 100644 index 000000000..fbe1a77cd --- /dev/null +++ b/frontend/.storybook/config.js @@ -0,0 +1,33 @@ +import { configure, addDecorator } from '@storybook/react'; +import { Provider } from 'react-redux'; +import store from '../app/store'; +import { MemoryRouter } from "react-router" + +const withProvider = (story) => ( + + { story() } + +) + +// const req = require.context('../app/components/ui', true, /\.stories\.js$/); +// const issues = require.context('../app/components/Session/Issues', true, /\.stories\.js$/); +// const bugFinder = require.context('../app/components/BugFinder', true, /\.stories\.js$/); + +addDecorator(withProvider); +addDecorator(story => {story()}); + +// function loadStories() { +// req.keys().forEach(filename => req(filename)); +// bugFinder.keys().forEach(filename => bugFinder(filename)); +// } + +// configure(loadStories, module); + + +configure( + [ + // require.context('../app', true, /\.stories\.mdx$/), + require.context('../app', true, /\.stories\.js$/), + ], + module +); \ No newline at end of file diff --git a/frontend/.storybook/preview-head.html b/frontend/.storybook/preview-head.html new file mode 100644 index 000000000..168f2db4a --- /dev/null +++ b/frontend/.storybook/preview-head.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/frontend/.storybook/webpack.config.js b/frontend/.storybook/webpack.config.js new file mode 100644 index 000000000..afd395809 --- /dev/null +++ b/frontend/.storybook/webpack.config.js @@ -0,0 +1,14 @@ +const pathAlias = require('../path-alias'); +const mainConfig = require('../webpack.config.js'); + +module.exports = async ({ config }) => { + var conf = mainConfig(); + config.resolve.alias = Object.assign(pathAlias, config.resolve.alias); // Path Alias + config.module.rules = conf.module.rules; + config.module.rules[0].use[0] = 'style-loader'; // instead of separated css + config.module.rules[1].use[0] = 'style-loader'; + config.plugins.push(conf.plugins[0]); // global React + config.plugins.push(conf.plugins[5]); + config.entry = config.entry.concat(conf.entry.slice(2)) // CSS entries + return config; +}; diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 000000000..1837339a8 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,18 @@ +# openreplay-ui +Openreplay prototype UI + +On new icon addition: +`npm run generate:icons` + + +## Documentation + +* [Redux](https://redux.js.org/) +* [Immutable](https://facebook.github.io/immutable-js/) +* [Ducks](https://github.com/erikras/ducks-modular-redux) +* [CSS Modules](https://github.com/css-modules/css-modules) + + +Labels in comments: +TEMP = temporary code +TODO = things to implement \ No newline at end of file diff --git a/frontend/app/Router.js b/frontend/app/Router.js new file mode 100644 index 000000000..3bdfc3c8f --- /dev/null +++ b/frontend/app/Router.js @@ -0,0 +1,151 @@ +import { Switch, Route, Redirect } from 'react-router'; +import { BrowserRouter, withRouter } from 'react-router-dom'; +import { connect } from 'react-redux'; +import { Notification } from 'UI'; +import { Loader } from 'UI'; +import { fetchUserInfo } from 'Duck/user'; +import withSiteIdUpdater from 'HOCs/withSiteIdUpdater'; +import Login from 'Components/Login/Login'; +import ForgotPassword from 'Components/ForgotPassword/ForgotPassword'; +import UpdatePassword from 'Components/UpdatePassword/UpdatePassword'; +import ClientPure from 'Components/Client/Client'; +import OnboardingPure from 'Components/Onboarding/Onboarding'; +import SessionPure from 'Components/Session/Session'; +import BugFinderPure from 'Components/BugFinder/BugFinder'; +import DashboardPure from 'Components/Dashboard/Dashboard'; +import ErrorsPure from 'Components/Errors/Errors'; +import Header from 'Components/Header/Header'; +// import ResultsModal from 'Shared/Results/ResultsModal'; +import FunnelDetails from 'Components/Funnels/FunnelDetails'; +import FunnelIssueDetails from 'Components/Funnels/FunnelIssueDetails'; + +import APIClient from './api_client'; +import * as routes from './routes'; +import Signup from './components/Signup/Signup'; + +const BugFinder = withSiteIdUpdater(BugFinderPure); +const Dashboard = withSiteIdUpdater(DashboardPure); +const Session = withSiteIdUpdater(SessionPure); +const Client = withSiteIdUpdater(ClientPure); +const Onboarding = withSiteIdUpdater(OnboardingPure); +const Errors = withSiteIdUpdater(ErrorsPure); +const Funnels = withSiteIdUpdater(FunnelDetails); +const FunnelIssue = withSiteIdUpdater(FunnelIssueDetails); +const withSiteId = routes.withSiteId; +const withObTab = routes.withObTab; + +const DASHBOARD_PATH = routes.dashboard(); +const SESSIONS_PATH = routes.sessions(); +const ERRORS_PATH = routes.errors(); +const ERROR_PATH = routes.error(); +const FUNNEL_PATH = routes.funnel(); +const FUNNEL_ISSUE_PATH = routes.funnelIssue(); +const SESSION_PATH = routes.session(); +const LIVE_SESSION_PATH = routes.liveSession(); +const LOGIN_PATH = routes.login(); +const SIGNUP_PATH = routes.signup(); +const FORGOT_PASSWORD = routes.forgotPassword(); +const CLIENT_PATH = routes.client(); +const ONBOARDING_PATH = routes.onboarding(); + +@withRouter +@connect((state) => { + const siteId = state.getIn([ 'user', 'siteId' ]); + const jwt = state.get('jwt'); + const changePassword = state.getIn([ 'user', 'account', 'changePassword' ]); + const userInfoLoading = state.getIn([ 'user', 'fetchUserInfoRequest', 'loading' ]); + return { + jwt, + siteId, + changePassword, + sites: state.getIn([ 'user', 'client', 'sites' ]), + isLoggedIn: jwt !== null && !changePassword, + loading: siteId === null || userInfoLoading, + email: state.getIn([ 'user', 'account', 'email' ]), + account: state.getIn([ 'user', 'account' ]), + organisation: state.getIn([ 'user', 'client', 'name' ]), + tenantId: state.getIn([ 'user', 'client', 'tenantId' ]), + }; +}, { + fetchUserInfo, +}) +class Router extends React.Component { + constructor(props) { + super(props); + if (props.isLoggedIn) { + Promise.all([props.fetchUserInfo()]) + .then(() => this.onLoginLogout()); + } + } + + componentDidUpdate(prevProps) { + if (prevProps.email !== this.props.email) { + this.onLoginLogout(); + } + } + + onLoginLogout() { + const { email, account, organisation } = this.props; + } + + render() { + const { isLoggedIn, jwt, siteId, sites, loading, changePassword, location } = this.props; + const siteIdList = sites.map(({ id }) => id).toJS(); + const hideHeader = location.pathname && location.pathname.includes('/session/'); + + return isLoggedIn ? + + {!hideHeader &&
} + + + + + + { + const client = new APIClient(jwt); + switch (location.pathname) { + case '/integrations/slack': + client.post('integrations/slack/add', { + code: location.search.split('=')[ 1 ], + state: tenantId, + }); + break; + } + return ; + } + } + /> + { siteIdList.length === 0 && + + } + + + + + + + + } /> + { routes.redirects.map(([ fr, to ]) => ( + + )) } + + + : + + + + + + ; + } +} + +export default () => ( + + + +); diff --git a/frontend/app/api_client.js b/frontend/app/api_client.js new file mode 100644 index 000000000..bbba3a246 --- /dev/null +++ b/frontend/app/api_client.js @@ -0,0 +1,108 @@ +import store from 'App/store'; + +import { queried } from './routes'; + +const siteIdRequiredPaths = [ + '/dashboard', + '/sessions', + '/events', + '/filters', + '/alerts', + '/targets', + '/metadata', + '/integrations/sentry/events', + '/integrations/slack/notify', + '/assignments', + '/integration/sources', + '/issue_types', + '/sample_rate', + '/flows', + '/rehydrations', + '/sourcemaps', + '/errors', + '/funnels' +]; + +const noStoringFetchPathStarts = [ + '/account/password', + '/password', + '/login' +]; + +// null? +export const clean = (obj, forbidenValues = [ undefined, '' ]) => { + const keys = Array.isArray(obj) + ? new Array(obj.length).fill().map((_, i) => i) + : Object.keys(obj); + const retObj = Array.isArray(obj) ? [] : {}; + keys.map(key => { + const value = obj[key]; + if (typeof value === 'object' && value !== null) { + retObj[key] = clean(value); + } else if (!forbidenValues.includes(value)) { + retObj[key] = value; + } + }); + + return retObj; +} + + +export default class APIClient { + constructor() { + const jwt = store.getState().get('jwt'); + const siteId = store.getState().getIn([ 'user', 'siteId' ]); + this.init = { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }; + if (jwt !== null) { + this.init.headers.Authorization = `Bearer ${ jwt }`; + } + this.siteId = siteId; + } + + fetch(path, params, options = { clean: true }) { + if (params !== undefined) { + const cleanedParams = options.clean ? clean(params) : params; + this.init.body = JSON.stringify(cleanedParams); + } + + + let fetch = window.fetch; + + let edp = window.ENV.API_EDP; + if ( + path !== '/targets_temp' && + !path.includes('/metadata/session_search') && + !path.includes('/watchdogs/rules') && + !!this.siteId && + siteIdRequiredPaths.some(sidPath => path.startsWith(sidPath)) + ) { + edp = `${ edp }/${ this.siteId }` + } + return fetch(edp + path, this.init); + } + + get(path, params, options) { + this.init.method = 'GET'; + return this.fetch(queried(path, params, options)); + } + + post(path, params, options) { + this.init.method = 'POST'; + return this.fetch(path, params); + } + + put(path, params, options) { + this.init.method = 'PUT'; + return this.fetch(path, params); + } + + delete(path, params, options) { + this.init.method = 'DELETE'; + return this.fetch(path, params); + } +} diff --git a/frontend/app/api_middleware.js b/frontend/app/api_middleware.js new file mode 100644 index 000000000..a29a22eb6 --- /dev/null +++ b/frontend/app/api_middleware.js @@ -0,0 +1,45 @@ +import APIClient from './api_client'; +import { UPDATE, DELETE } from './duck/jwt'; + +export default store => next => (action) => { + const { types, call, ...rest } = action; + if (!call) { + return next(action); + } + const [ REQUEST, SUCCESS, FAILURE ] = types; + next({ ...rest, type: REQUEST }); + const client = new APIClient(); + + return call(client) + .then(response => { + if (response.status === 403) { + next({ type: DELETE }); + } + return response.json() + }) + .then(json => json || {}) // TEMP TODO on server: no empty responces + .then(({ jwt, errors, data }) => { + if (errors) { + next({ type: FAILURE, errors, data }); + } else { + next({ type: SUCCESS, data, ...rest }); + } + if (jwt) { + next({ type: UPDATE, data: jwt }); + } + }) + .catch(() => { + return next({ type: FAILURE, errors: [ 'Connection error' ] }); + }); +}; + +function jwtExpired(token) { + try { + const base64Url = token.split('.')[ 1 ]; + const base64 = base64Url.replace('-', '+').replace('_', '/'); + const tokenObj = JSON.parse(window.atob(base64)); + return tokenObj.exp * 1000 < Date.now(); // exp in Unix time (sec) + } catch (e) { + return true; + } +} diff --git a/frontend/app/assets/favicon@1x.png b/frontend/app/assets/favicon@1x.png new file mode 100644 index 000000000..393d5d3cc Binary files /dev/null and b/frontend/app/assets/favicon@1x.png differ diff --git a/frontend/app/assets/favicon@2x.png b/frontend/app/assets/favicon@2x.png new file mode 100644 index 000000000..c99e774af Binary files /dev/null and b/frontend/app/assets/favicon@2x.png differ diff --git a/frontend/app/assets/favicon@3x.png b/frontend/app/assets/favicon@3x.png new file mode 100644 index 000000000..4d38be71c Binary files /dev/null and b/frontend/app/assets/favicon@3x.png differ diff --git a/frontend/app/assets/favicon@4x.png b/frontend/app/assets/favicon@4x.png new file mode 100644 index 000000000..19f3a4256 Binary files /dev/null and b/frontend/app/assets/favicon@4x.png differ diff --git a/frontend/app/assets/favicon@5x.png b/frontend/app/assets/favicon@5x.png new file mode 100644 index 000000000..81593e9e2 Binary files /dev/null and b/frontend/app/assets/favicon@5x.png differ diff --git a/frontend/app/assets/favicon@6x.png b/frontend/app/assets/favicon@6x.png new file mode 100644 index 000000000..dbf51e62c Binary files /dev/null and b/frontend/app/assets/favicon@6x.png differ diff --git a/frontend/app/assets/img/chrome-plugin.png b/frontend/app/assets/img/chrome-plugin.png new file mode 100644 index 000000000..7d55e902d Binary files /dev/null and b/frontend/app/assets/img/chrome-plugin.png differ diff --git a/frontend/app/assets/img/flags.png b/frontend/app/assets/img/flags.png new file mode 100644 index 000000000..0658bb8a3 Binary files /dev/null and b/frontend/app/assets/img/flags.png differ diff --git a/frontend/app/assets/img/flags_responsive.png b/frontend/app/assets/img/flags_responsive.png new file mode 100755 index 000000000..e93d295be Binary files /dev/null and b/frontend/app/assets/img/flags_responsive.png differ diff --git a/frontend/app/assets/img/funnel_intro.png b/frontend/app/assets/img/funnel_intro.png new file mode 100644 index 000000000..cbd028ea8 Binary files /dev/null and b/frontend/app/assets/img/funnel_intro.png differ diff --git a/frontend/app/assets/img/img-newsletter.png b/frontend/app/assets/img/img-newsletter.png new file mode 100644 index 000000000..44a6fb9d5 Binary files /dev/null and b/frontend/app/assets/img/img-newsletter.png differ diff --git a/frontend/app/assets/img/ios/iPad-5th.png b/frontend/app/assets/img/ios/iPad-5th.png new file mode 100644 index 000000000..fcda5dd78 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-5th.png differ diff --git a/frontend/app/assets/img/ios/iPad-5th@2x.png b/frontend/app/assets/img/ios/iPad-5th@2x.png new file mode 100644 index 000000000..f78ca7816 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-5th@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-7th.png b/frontend/app/assets/img/ios/iPad-7th.png new file mode 100644 index 000000000..fa0a8682f Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-7th.png differ diff --git a/frontend/app/assets/img/ios/iPad-7th@2x.png b/frontend/app/assets/img/ios/iPad-7th@2x.png new file mode 100644 index 000000000..f5527f5a6 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-7th@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-Air-2.png b/frontend/app/assets/img/ios/iPad-Air-2.png new file mode 100644 index 000000000..fcda5dd78 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Air-2.png differ diff --git a/frontend/app/assets/img/ios/iPad-Air-2@2x.png b/frontend/app/assets/img/ios/iPad-Air-2@2x.png new file mode 100644 index 000000000..f78ca7816 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Air-2@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-Air.png b/frontend/app/assets/img/ios/iPad-Air.png new file mode 100644 index 000000000..b34df26ba Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Air.png differ diff --git a/frontend/app/assets/img/ios/iPad-Air@2x.png b/frontend/app/assets/img/ios/iPad-Air@2x.png new file mode 100644 index 000000000..ef090e1c5 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Air@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-Mini-2.png b/frontend/app/assets/img/ios/iPad-Mini-2.png new file mode 100644 index 000000000..0e71c005b Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Mini-2.png differ diff --git a/frontend/app/assets/img/ios/iPad-Mini-2@2x.png b/frontend/app/assets/img/ios/iPad-Mini-2@2x.png new file mode 100644 index 000000000..cdfbca8a3 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Mini-2@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-Mini-3.png b/frontend/app/assets/img/ios/iPad-Mini-3.png new file mode 100644 index 000000000..a0afc2194 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Mini-3.png differ diff --git a/frontend/app/assets/img/ios/iPad-Mini-3@2x.png b/frontend/app/assets/img/ios/iPad-Mini-3@2x.png new file mode 100644 index 000000000..1848af8c9 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Mini-3@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-Mini-4.png b/frontend/app/assets/img/ios/iPad-Mini-4.png new file mode 100644 index 000000000..3081b3a06 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Mini-4.png differ diff --git a/frontend/app/assets/img/ios/iPad-Mini-4@2x.png b/frontend/app/assets/img/ios/iPad-Mini-4@2x.png new file mode 100644 index 000000000..0c403f55a Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-Mini-4@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-air-4.png b/frontend/app/assets/img/ios/iPad-air-4.png new file mode 100644 index 000000000..851233fb7 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-air-4.png differ diff --git a/frontend/app/assets/img/ios/iPad-air-4@2x.png b/frontend/app/assets/img/ios/iPad-air-4@2x.png new file mode 100644 index 000000000..7d3058902 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-air-4@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-pro-11-2020.png b/frontend/app/assets/img/ios/iPad-pro-11-2020.png new file mode 100644 index 000000000..b2901fc79 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-pro-11-2020.png differ diff --git a/frontend/app/assets/img/ios/iPad-pro-11-2020@2x.png b/frontend/app/assets/img/ios/iPad-pro-11-2020@2x.png new file mode 100644 index 000000000..68eb439eb Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-pro-11-2020@2x.png differ diff --git a/frontend/app/assets/img/ios/iPad-pro-12.9-2020.png b/frontend/app/assets/img/ios/iPad-pro-12.9-2020.png new file mode 100644 index 000000000..ca2920d1b Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-pro-12.9-2020.png differ diff --git a/frontend/app/assets/img/ios/iPad-pro-12.9-2020@2x.png b/frontend/app/assets/img/ios/iPad-pro-12.9-2020@2x.png new file mode 100644 index 000000000..a80488250 Binary files /dev/null and b/frontend/app/assets/img/ios/iPad-pro-12.9-2020@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-11-Pro-Max.png b/frontend/app/assets/img/ios/iPhone-11-Pro-Max.png new file mode 100644 index 000000000..107cacd56 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-11-Pro-Max.png differ diff --git a/frontend/app/assets/img/ios/iPhone-11-Pro-Max@2x.png b/frontend/app/assets/img/ios/iPhone-11-Pro-Max@2x.png new file mode 100644 index 000000000..301774303 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-11-Pro-Max@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-11-Pro.png b/frontend/app/assets/img/ios/iPhone-11-Pro.png new file mode 100644 index 000000000..6fc67b17a Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-11-Pro.png differ diff --git a/frontend/app/assets/img/ios/iPhone-11-Pro@2x.png b/frontend/app/assets/img/ios/iPhone-11-Pro@2x.png new file mode 100644 index 000000000..262310943 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-11-Pro@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-11.png b/frontend/app/assets/img/ios/iPhone-11.png new file mode 100644 index 000000000..307ae7a58 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-11.png differ diff --git a/frontend/app/assets/img/ios/iPhone-11@2x.png b/frontend/app/assets/img/ios/iPhone-11@2x.png new file mode 100644 index 000000000..1c9ba0837 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-11@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-12.png b/frontend/app/assets/img/ios/iPhone-12.png new file mode 100644 index 000000000..cd4b495f1 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-12.png differ diff --git a/frontend/app/assets/img/ios/iPhone-12@2x.png b/frontend/app/assets/img/ios/iPhone-12@2x.png new file mode 100644 index 000000000..6446cc93b Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-12@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-5S.png b/frontend/app/assets/img/ios/iPhone-5S.png new file mode 100644 index 000000000..c6dae9986 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-5S.png differ diff --git a/frontend/app/assets/img/ios/iPhone-5S@2x.png b/frontend/app/assets/img/ios/iPhone-5S@2x.png new file mode 100644 index 000000000..91935a857 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-5S@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-6.png b/frontend/app/assets/img/ios/iPhone-6.png new file mode 100644 index 000000000..865eea7b7 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-6.png differ diff --git a/frontend/app/assets/img/ios/iPhone-6@2x.png b/frontend/app/assets/img/ios/iPhone-6@2x.png new file mode 100644 index 000000000..0a8a79a12 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-6@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-6S.png b/frontend/app/assets/img/ios/iPhone-6S.png new file mode 100644 index 000000000..d28241bc0 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-6S.png differ diff --git a/frontend/app/assets/img/ios/iPhone-6S@2x.png b/frontend/app/assets/img/ios/iPhone-6S@2x.png new file mode 100644 index 000000000..90c6f8ca8 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-6S@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-6s-plus.png b/frontend/app/assets/img/ios/iPhone-6s-plus.png new file mode 100644 index 000000000..ac1e6df56 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-6s-plus.png differ diff --git a/frontend/app/assets/img/ios/iPhone-6s-plus@2x.png b/frontend/app/assets/img/ios/iPhone-6s-plus@2x.png new file mode 100644 index 000000000..d6589015a Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-6s-plus@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-7.png b/frontend/app/assets/img/ios/iPhone-7.png new file mode 100644 index 000000000..2ca4c633f Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-7.png differ diff --git a/frontend/app/assets/img/ios/iPhone-7@2x.png b/frontend/app/assets/img/ios/iPhone-7@2x.png new file mode 100644 index 000000000..fdb5389a0 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-7@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-8-plus.png b/frontend/app/assets/img/ios/iPhone-8-plus.png new file mode 100644 index 000000000..b38ebe62c Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-8-plus.png differ diff --git a/frontend/app/assets/img/ios/iPhone-8-plus@2x.png b/frontend/app/assets/img/ios/iPhone-8-plus@2x.png new file mode 100644 index 000000000..74dbfc3c8 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-8-plus@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-8.png b/frontend/app/assets/img/ios/iPhone-8.png new file mode 100644 index 000000000..9e51a42e5 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-8.png differ diff --git a/frontend/app/assets/img/ios/iPhone-8@2x.png b/frontend/app/assets/img/ios/iPhone-8@2x.png new file mode 100644 index 000000000..0eacc1912 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-8@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-SE.png b/frontend/app/assets/img/ios/iPhone-SE.png new file mode 100644 index 000000000..6eee3dd65 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-SE.png differ diff --git a/frontend/app/assets/img/ios/iPhone-SE@2x.png b/frontend/app/assets/img/ios/iPhone-SE@2x.png new file mode 100644 index 000000000..bd7fd92a8 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-SE@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-X.png b/frontend/app/assets/img/ios/iPhone-X.png new file mode 100644 index 000000000..fddbbb565 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-X.png differ diff --git a/frontend/app/assets/img/ios/iPhone-X@2x.png b/frontend/app/assets/img/ios/iPhone-X@2x.png new file mode 100644 index 000000000..dedab1391 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-X@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-XR.png b/frontend/app/assets/img/ios/iPhone-XR.png new file mode 100644 index 000000000..d78fa0ef5 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-XR.png differ diff --git a/frontend/app/assets/img/ios/iPhone-XR@2x.png b/frontend/app/assets/img/ios/iPhone-XR@2x.png new file mode 100644 index 000000000..9ee161f39 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-XR@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-XS-max.png b/frontend/app/assets/img/ios/iPhone-XS-max.png new file mode 100644 index 000000000..6275162e3 Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-XS-max.png differ diff --git a/frontend/app/assets/img/ios/iPhone-XS-max@2x.png b/frontend/app/assets/img/ios/iPhone-XS-max@2x.png new file mode 100644 index 000000000..aae2c369e Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-XS-max@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-XS.png b/frontend/app/assets/img/ios/iPhone-XS.png new file mode 100644 index 000000000..1e0b7b85c Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-XS.png differ diff --git a/frontend/app/assets/img/ios/iPhone-XS@2x.png b/frontend/app/assets/img/ios/iPhone-XS@2x.png new file mode 100644 index 000000000..1738a712e Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-XS@2x.png differ diff --git a/frontend/app/assets/img/ios/iPhone-se-2.png b/frontend/app/assets/img/ios/iPhone-se-2.png new file mode 100644 index 000000000..b00ad5a8c Binary files /dev/null and b/frontend/app/assets/img/ios/iPhone-se-2.png differ diff --git a/frontend/app/assets/img/ios/iphone-se-2@2x.png b/frontend/app/assets/img/ios/iphone-se-2@2x.png new file mode 100644 index 000000000..0ab1fdb71 Binary files /dev/null and b/frontend/app/assets/img/ios/iphone-se-2@2x.png differ diff --git a/frontend/app/assets/img/widgets/application_activity.png b/frontend/app/assets/img/widgets/application_activity.png new file mode 100644 index 000000000..4794b6c87 Binary files /dev/null and b/frontend/app/assets/img/widgets/application_activity.png differ diff --git a/frontend/app/assets/img/widgets/errors.png b/frontend/app/assets/img/widgets/errors.png new file mode 100644 index 000000000..d560a7b7b Binary files /dev/null and b/frontend/app/assets/img/widgets/errors.png differ diff --git a/frontend/app/assets/img/widgets/missing_resources.png b/frontend/app/assets/img/widgets/missing_resources.png new file mode 100644 index 000000000..1a4b6131d Binary files /dev/null and b/frontend/app/assets/img/widgets/missing_resources.png differ diff --git a/frontend/app/assets/img/widgets/most_Impactful_errors.png b/frontend/app/assets/img/widgets/most_Impactful_errors.png new file mode 100644 index 000000000..f59d16e0a Binary files /dev/null and b/frontend/app/assets/img/widgets/most_Impactful_errors.png differ diff --git a/frontend/app/assets/img/widgets/na.png b/frontend/app/assets/img/widgets/na.png new file mode 100644 index 000000000..b8548d527 Binary files /dev/null and b/frontend/app/assets/img/widgets/na.png differ diff --git a/frontend/app/assets/img/widgets/negative_feedback.png b/frontend/app/assets/img/widgets/negative_feedback.png new file mode 100644 index 000000000..6179a6e42 Binary files /dev/null and b/frontend/app/assets/img/widgets/negative_feedback.png differ diff --git a/frontend/app/assets/img/widgets/page_metrics.png b/frontend/app/assets/img/widgets/page_metrics.png new file mode 100644 index 000000000..cfbcf515a Binary files /dev/null and b/frontend/app/assets/img/widgets/page_metrics.png differ diff --git a/frontend/app/assets/img/widgets/performance.png b/frontend/app/assets/img/widgets/performance.png new file mode 100644 index 000000000..efc3b2966 Binary files /dev/null and b/frontend/app/assets/img/widgets/performance.png differ diff --git a/frontend/app/assets/img/widgets/processed_sessions.png b/frontend/app/assets/img/widgets/processed_sessions.png new file mode 100644 index 000000000..50f8c3c28 Binary files /dev/null and b/frontend/app/assets/img/widgets/processed_sessions.png differ diff --git a/frontend/app/assets/img/widgets/recent_frustrations.png b/frontend/app/assets/img/widgets/recent_frustrations.png new file mode 100644 index 000000000..5f277e243 Binary files /dev/null and b/frontend/app/assets/img/widgets/recent_frustrations.png differ diff --git a/frontend/app/assets/img/widgets/user_activity.png b/frontend/app/assets/img/widgets/user_activity.png new file mode 100644 index 000000000..5473fda0e Binary files /dev/null and b/frontend/app/assets/img/widgets/user_activity.png differ diff --git a/frontend/app/assets/index.html b/frontend/app/assets/index.html new file mode 100644 index 000000000..3147d2337 --- /dev/null +++ b/frontend/app/assets/index.html @@ -0,0 +1,21 @@ + + + + OpenReplay + + + + + + + + + + + + + + +
+ + diff --git a/frontend/app/assets/logo-white.svg b/frontend/app/assets/logo-white.svg new file mode 100644 index 000000000..d941bea3e --- /dev/null +++ b/frontend/app/assets/logo-white.svg @@ -0,0 +1,9 @@ + + + Group + + + + + + \ No newline at end of file diff --git a/frontend/app/assets/marvel-device.css b/frontend/app/assets/marvel-device.css new file mode 100644 index 000000000..48a56a543 --- /dev/null +++ b/frontend/app/assets/marvel-device.css @@ -0,0 +1 @@ +.marvel-device{display:inline-block;position:relative;-webkit-box-sizing:content-box !important;box-sizing:content-box !important}.marvel-device .screen{width:100%;position:relative;height:100%;z-index:3;background:white;overflow:hidden;display:block;border-radius:1px;-webkit-box-shadow:0 0 0 3px #111;box-shadow:0 0 0 3px #111}.marvel-device .top-bar,.marvel-device .bottom-bar{height:3px;background:black;width:100%;display:block}.marvel-device .middle-bar{width:3px;height:4px;top:0px;left:90px;background:black;position:absolute}.marvel-device.iphone8{width:375px;height:667px;padding:105px 24px;background:#d9dbdc;border-radius:56px;-webkit-box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.2);box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.2)}.marvel-device.iphone8:before{width:calc(100% - 12px);height:calc(100% - 12px);position:absolute;top:6px;content:'';left:6px;border-radius:50px;background:#f8f8f8;z-index:1}.marvel-device.iphone8:after{width:calc(100% - 16px);height:calc(100% - 16px);position:absolute;top:8px;content:'';left:8px;border-radius:48px;-webkit-box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.1),inset 0 0 6px 3px #fff;box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.1),inset 0 0 6px 3px #fff;z-index:2}.marvel-device.iphone8 .home{border-radius:100%;width:68px;height:68px;position:absolute;left:50%;margin-left:-34px;bottom:22px;z-index:3;background:#303233;background:linear-gradient(135deg, #303233 0%, #b5b7b9 50%, #f0f2f2 69%, #303233 100%)}.marvel-device.iphone8 .home:before{background:#f8f8f8;position:absolute;content:'';border-radius:100%;width:calc(100% - 8px);height:calc(100% - 8px);top:4px;left:4px}.marvel-device.iphone8 .top-bar{height:14px;background:#bfbfc0;position:absolute;top:68px;left:0}.marvel-device.iphone8 .bottom-bar{height:14px;background:#bfbfc0;position:absolute;bottom:68px;left:0}.marvel-device.iphone8 .sleep{position:absolute;top:190px;right:-4px;width:4px;height:66px;border-radius:0px 2px 2px 0px;background:#d9dbdc}.marvel-device.iphone8 .volume{position:absolute;left:-4px;top:188px;z-index:0;height:66px;width:4px;border-radius:2px 0px 0px 2px;background:#d9dbdc}.marvel-device.iphone8 .volume:before{position:absolute;left:2px;top:-78px;height:40px;width:2px;border-radius:2px 0px 0px 2px;background:inherit;content:'';display:block}.marvel-device.iphone8 .volume:after{position:absolute;left:0px;top:82px;height:66px;width:4px;border-radius:2px 0px 0px 2px;background:inherit;content:'';display:block}.marvel-device.iphone8 .camera{background:#3c3d3d;width:12px;height:12px;position:absolute;top:24px;left:50%;margin-left:-6px;border-radius:100%;z-index:3}.marvel-device.iphone8 .sensor{background:#3c3d3d;width:16px;height:16px;position:absolute;top:49px;left:134px;z-index:3;border-radius:100%}.marvel-device.iphone8 .speaker{background:#292728;width:70px;height:6px;position:absolute;top:54px;left:50%;margin-left:-35px;border-radius:6px;z-index:3}.marvel-device.iphone8.gold{background:#f9e7d3}.marvel-device.iphone8.gold .top-bar,.marvel-device.iphone8.gold .bottom-bar{background:white}.marvel-device.iphone8.gold .sleep,.marvel-device.iphone8.gold .volume{background:#f9e7d3}.marvel-device.iphone8.gold .home{background:#cebba9;background:linear-gradient(135deg, #cebba9 0%, #f9e7d3 50%, #cebba9 100%)}.marvel-device.iphone8.black{background:#464646;-webkit-box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.7);box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.7)}.marvel-device.iphone8.black:before{background:#080808}.marvel-device.iphone8.black:after{-webkit-box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.1),inset 0 0 6px 3px #212121;box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.1),inset 0 0 6px 3px #212121}.marvel-device.iphone8.black .top-bar,.marvel-device.iphone8.black .bottom-bar{background:#212121}.marvel-device.iphone8.black .volume,.marvel-device.iphone8.black .sleep{background:#464646}.marvel-device.iphone8.black .camera{background:#080808}.marvel-device.iphone8.black .home{background:#080808;background:linear-gradient(135deg, #080808 0%, #464646 50%, #080808 100%)}.marvel-device.iphone8.black .home:before{background:#080808}.marvel-device.iphone8.landscape{padding:24px 105px;height:375px;width:667px}.marvel-device.iphone8.landscape .sleep{top:100%;border-radius:0px 0px 2px 2px;right:190px;height:4px;width:66px}.marvel-device.iphone8.landscape .volume{width:66px;height:4px;top:-4px;left:calc(100% - 188px - 66px);border-radius:2px 2px 0px 0px}.marvel-device.iphone8.landscape .volume:before{width:40px;height:2px;top:2px;right:-78px;left:auto;border-radius:2px 2px 0px 0px}.marvel-device.iphone8.landscape .volume:after{left:-82px;width:66px;height:4px;top:0;border-radius:2px 2px 0px 0px}.marvel-device.iphone8.landscape .top-bar{width:14px;height:100%;left:calc(100% - 68px - 14px);top:0}.marvel-device.iphone8.landscape .bottom-bar{width:14px;height:100%;left:68px;top:0}.marvel-device.iphone8.landscape .home{top:50%;margin-top:-34px;margin-left:0;left:22px}.marvel-device.iphone8.landscape .sensor{top:134px;left:calc(100% - 49px - 16px)}.marvel-device.iphone8.landscape .speaker{height:70px;width:6px;left:calc(100% - 54px - 6px);top:50%;margin-left:0px;margin-top:-35px}.marvel-device.iphone8.landscape .camera{left:calc(100% - 32px);top:50%;margin-left:0px;margin-top:-5px}.marvel-device.iphone8plus{width:414px;height:736px;padding:112px 26px;background:#d9dbdc;border-radius:56px;-webkit-box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.2);box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.2)}.marvel-device.iphone8plus:before{width:calc(100% - 12px);height:calc(100% - 12px);position:absolute;top:6px;content:'';left:6px;border-radius:50px;background:#f8f8f8;z-index:1}.marvel-device.iphone8plus:after{width:calc(100% - 16px);height:calc(100% - 16px);position:absolute;top:8px;content:'';left:8px;border-radius:48px;-webkit-box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.1),inset 0 0 6px 3px #fff;box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.1),inset 0 0 6px 3px #fff;z-index:2}.marvel-device.iphone8plus .home{border-radius:100%;width:68px;height:68px;position:absolute;left:50%;margin-left:-34px;bottom:24px;z-index:3;background:#303233;background:linear-gradient(135deg, #303233 0%, #b5b7b9 50%, #f0f2f2 69%, #303233 100%)}.marvel-device.iphone8plus .home:before{background:#f8f8f8;position:absolute;content:'';border-radius:100%;width:calc(100% - 8px);height:calc(100% - 8px);top:4px;left:4px}.marvel-device.iphone8plus .top-bar{height:14px;background:#bfbfc0;position:absolute;top:68px;left:0}.marvel-device.iphone8plus .bottom-bar{height:14px;background:#bfbfc0;position:absolute;bottom:68px;left:0}.marvel-device.iphone8plus .sleep{position:absolute;top:190px;right:-4px;width:4px;height:66px;border-radius:0px 2px 2px 0px;background:#d9dbdc}.marvel-device.iphone8plus .volume{position:absolute;left:-4px;top:188px;z-index:0;height:66px;width:4px;border-radius:2px 0px 0px 2px;background:#d9dbdc}.marvel-device.iphone8plus .volume:before{position:absolute;left:2px;top:-78px;height:40px;width:2px;border-radius:2px 0px 0px 2px;background:inherit;content:'';display:block}.marvel-device.iphone8plus .volume:after{position:absolute;left:0px;top:82px;height:66px;width:4px;border-radius:2px 0px 0px 2px;background:inherit;content:'';display:block}.marvel-device.iphone8plus .camera{background:#3c3d3d;width:12px;height:12px;position:absolute;top:29px;left:50%;margin-left:-6px;border-radius:100%;z-index:3}.marvel-device.iphone8plus .sensor{background:#3c3d3d;width:16px;height:16px;position:absolute;top:54px;left:154px;z-index:3;border-radius:100%}.marvel-device.iphone8plus .speaker{background:#292728;width:70px;height:6px;position:absolute;top:59px;left:50%;margin-left:-35px;border-radius:6px;z-index:3}.marvel-device.iphone8plus.gold{background:#f9e7d3}.marvel-device.iphone8plus.gold .top-bar,.marvel-device.iphone8plus.gold .bottom-bar{background:white}.marvel-device.iphone8plus.gold .sleep,.marvel-device.iphone8plus.gold .volume{background:#f9e7d3}.marvel-device.iphone8plus.gold .home{background:#cebba9;background:linear-gradient(135deg, #cebba9 0%, #f9e7d3 50%, #cebba9 100%)}.marvel-device.iphone8plus.black{background:#464646;-webkit-box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.7);box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.7)}.marvel-device.iphone8plus.black:before{background:#080808}.marvel-device.iphone8plus.black:after{-webkit-box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.1),inset 0 0 6px 3px #212121;box-shadow:inset 0 0 3px 0 rgba(0,0,0,0.1),inset 0 0 6px 3px #212121}.marvel-device.iphone8plus.black .top-bar,.marvel-device.iphone8plus.black .bottom-bar{background:#212121}.marvel-device.iphone8plus.black .volume,.marvel-device.iphone8plus.black .sleep{background:#464646}.marvel-device.iphone8plus.black .camera{background:#080808}.marvel-device.iphone8plus.black .home{background:#080808;background:linear-gradient(135deg, #080808 0%, #464646 50%, #080808 100%)}.marvel-device.iphone8plus.black .home:before{background:#080808}.marvel-device.iphone8plus.landscape{padding:26px 112px;height:414px;width:736px}.marvel-device.iphone8plus.landscape .sleep{top:100%;border-radius:0px 0px 2px 2px;right:190px;height:4px;width:66px}.marvel-device.iphone8plus.landscape .volume{width:66px;height:4px;top:-4px;left:calc(100% - 188px - 66px);border-radius:2px 2px 0px 0px}.marvel-device.iphone8plus.landscape .volume:before{width:40px;height:2px;top:2px;right:-78px;left:auto;border-radius:2px 2px 0px 0px}.marvel-device.iphone8plus.landscape .volume:after{left:-82px;width:66px;height:4px;top:0;border-radius:2px 2px 0px 0px}.marvel-device.iphone8plus.landscape .top-bar{width:14px;height:100%;left:calc(100% - 68px - 14px);top:0}.marvel-device.iphone8plus.landscape .bottom-bar{width:14px;height:100%;left:68px;top:0}.marvel-device.iphone8plus.landscape .home{top:50%;margin-top:-34px;margin-left:0;left:24px}.marvel-device.iphone8plus.landscape .sensor{top:154px;left:calc(100% - 54px - 16px)}.marvel-device.iphone8plus.landscape .speaker{height:70px;width:6px;left:calc(100% - 59px - 6px);top:50%;margin-left:0px;margin-top:-35px}.marvel-device.iphone8plus.landscape .camera{left:calc(100% - 29px);top:50%;margin-left:0px;margin-top:-5px}.marvel-device.iphone5s,.marvel-device.iphone5c{padding:105px 22px;background:#2c2b2c;width:320px;height:568px;border-radius:50px}.marvel-device.iphone5s:before,.marvel-device.iphone5c:before{width:calc(100% - 8px);height:calc(100% - 8px);position:absolute;top:4px;content:'';left:4px;border-radius:46px;background:#1e1e1e;z-index:1}.marvel-device.iphone5s .sleep,.marvel-device.iphone5c .sleep{position:absolute;top:-4px;right:60px;width:60px;height:4px;border-radius:2px 2px 0px 0px;background:#282727}.marvel-device.iphone5s .volume,.marvel-device.iphone5c .volume{position:absolute;left:-4px;top:180px;z-index:0;height:27px;width:4px;border-radius:2px 0px 0px 2px;background:#282727}.marvel-device.iphone5s .volume:before,.marvel-device.iphone5c .volume:before{position:absolute;left:0px;top:-75px;height:35px;width:4px;border-radius:2px 0px 0px 2px;background:inherit;content:'';display:block}.marvel-device.iphone5s .volume:after,.marvel-device.iphone5c .volume:after{position:absolute;left:0px;bottom:-64px;height:27px;width:4px;border-radius:2px 0px 0px 2px;background:inherit;content:'';display:block}.marvel-device.iphone5s .camera,.marvel-device.iphone5c .camera{background:#3c3d3d;width:10px;height:10px;position:absolute;top:32px;left:50%;margin-left:-5px;border-radius:5px;z-index:3}.marvel-device.iphone5s .sensor,.marvel-device.iphone5c .sensor{background:#3c3d3d;width:10px;height:10px;position:absolute;top:60px;left:160px;z-index:3;margin-left:-32px;border-radius:5px}.marvel-device.iphone5s .speaker,.marvel-device.iphone5c .speaker{background:#292728;width:64px;height:10px;position:absolute;top:60px;left:50%;margin-left:-32px;border-radius:5px;z-index:3}.marvel-device.iphone5s.landscape,.marvel-device.iphone5c.landscape{padding:22px 105px;height:320px;width:568px}.marvel-device.iphone5s.landscape .sleep,.marvel-device.iphone5c.landscape .sleep{right:-4px;top:calc(100% - 120px);height:60px;width:4px;border-radius:0px 2px 2px 0px}.marvel-device.iphone5s.landscape .volume,.marvel-device.iphone5c.landscape .volume{width:27px;height:4px;top:-4px;left:calc(100% - 180px);border-radius:2px 2px 0px 0px}.marvel-device.iphone5s.landscape .volume:before,.marvel-device.iphone5c.landscape .volume:before{width:35px;height:4px;top:0px;right:-75px;left:auto;border-radius:2px 2px 0px 0px}.marvel-device.iphone5s.landscape .volume:after,.marvel-device.iphone5c.landscape .volume:after{bottom:0px;left:-64px;z-index:999;height:4px;width:27px;border-radius:2px 2px 0px 0px}.marvel-device.iphone5s.landscape .sensor,.marvel-device.iphone5c.landscape .sensor{top:160px;left:calc(100% - 60px);margin-left:0px;margin-top:-32px}.marvel-device.iphone5s.landscape .speaker,.marvel-device.iphone5c.landscape .speaker{height:64px;width:10px;left:calc(100% - 60px);top:50%;margin-left:0px;margin-top:-32px}.marvel-device.iphone5s.landscape .camera,.marvel-device.iphone5c.landscape .camera{left:calc(100% - 32px);top:50%;margin-left:0px;margin-top:-5px}.marvel-device.iphone5s .home{border-radius:36px;width:68px;-webkit-box-shadow:inset 0 0 0 4px #2c2b2c;box-shadow:inset 0 0 0 4px #2c2b2c;height:68px;position:absolute;left:50%;margin-left:-34px;bottom:19px;z-index:3}.marvel-device.iphone5s .top-bar{top:70px;position:absolute;left:0}.marvel-device.iphone5s .bottom-bar{bottom:70px;position:absolute;left:0}.marvel-device.iphone5s.landscape .home{left:19px;bottom:50%;margin-bottom:-34px;margin-left:0px}.marvel-device.iphone5s.landscape .top-bar{left:70px;top:0px;width:3px;height:100%}.marvel-device.iphone5s.landscape .bottom-bar{right:70px;left:auto;bottom:0px;width:3px;height:100%}.marvel-device.iphone5s.silver{background:#bcbcbc}.marvel-device.iphone5s.silver:before{background:#fcfcfc}.marvel-device.iphone5s.silver .volume,.marvel-device.iphone5s.silver .sleep{background:#d6d6d6}.marvel-device.iphone5s.silver .top-bar,.marvel-device.iphone5s.silver .bottom-bar{background:#eaebec}.marvel-device.iphone5s.silver .home{-webkit-box-shadow:inset 0 0 0 4px #bcbcbc;box-shadow:inset 0 0 0 4px #bcbcbc}.marvel-device.iphone5s.gold{background:#f9e7d3}.marvel-device.iphone5s.gold:before{background:#fcfcfc}.marvel-device.iphone5s.gold .volume,.marvel-device.iphone5s.gold .sleep{background:#f9e7d3}.marvel-device.iphone5s.gold .top-bar,.marvel-device.iphone5s.gold .bottom-bar{background:white}.marvel-device.iphone5s.gold .home{-webkit-box-shadow:inset 0 0 0 4px #f9e7d3;box-shadow:inset 0 0 0 4px #f9e7d3}.marvel-device.iphone5c{background:white;-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,0.2);box-shadow:0 1px 2px 0 rgba(0,0,0,0.2)}.marvel-device.iphone5c .top-bar,.marvel-device.iphone5c .bottom-bar{display:none}.marvel-device.iphone5c .home{background:#242324;border-radius:36px;width:68px;height:68px;z-index:3;position:absolute;left:50%;margin-left:-34px;bottom:19px}.marvel-device.iphone5c .home:after{width:20px;height:20px;border:1px solid rgba(255,255,255,0.1);border-radius:4px;position:absolute;display:block;content:'';top:50%;left:50%;margin-top:-11px;margin-left:-11px}.marvel-device.iphone5c.landscape .home{left:19px;bottom:50%;margin-bottom:-34px;margin-left:0px}.marvel-device.iphone5c .volume,.marvel-device.iphone5c .sleep{background:#dddddd}.marvel-device.iphone5c.red{background:#f96b6c}.marvel-device.iphone5c.red .volume,.marvel-device.iphone5c.red .sleep{background:#ed5758}.marvel-device.iphone5c.yellow{background:#f2dc60}.marvel-device.iphone5c.yellow .volume,.marvel-device.iphone5c.yellow .sleep{background:#e5ce4c}.marvel-device.iphone5c.green{background:#97e563}.marvel-device.iphone5c.green .volume,.marvel-device.iphone5c.green .sleep{background:#85d94d}.marvel-device.iphone5c.blue{background:#33a2db}.marvel-device.iphone5c.blue .volume,.marvel-device.iphone5c.blue .sleep{background:#2694cd}.marvel-device.iphone4s{padding:129px 27px;width:320px;height:480px;background:#686868;border-radius:54px}.marvel-device.iphone4s:before{content:'';width:calc(100% - 8px);height:calc(100% - 8px);position:absolute;top:4px;left:4px;z-index:1;border-radius:50px;background:#1e1e1e}.marvel-device.iphone4s .top-bar{top:60px;position:absolute;left:0}.marvel-device.iphone4s .bottom-bar{bottom:90px;position:absolute;left:0}.marvel-device.iphone4s .camera{background:#3c3d3d;width:10px;height:10px;position:absolute;top:72px;left:134px;z-index:3;margin-left:-5px;border-radius:100%}.marvel-device.iphone4s .speaker{background:#292728;width:64px;height:10px;position:absolute;top:72px;left:50%;z-index:3;margin-left:-32px;border-radius:5px}.marvel-device.iphone4s .sensor{background:#292728;width:40px;height:10px;position:absolute;top:36px;left:50%;z-index:3;margin-left:-20px;border-radius:5px}.marvel-device.iphone4s .home{background:#242324;border-radius:100%;width:72px;height:72px;z-index:3;position:absolute;left:50%;margin-left:-36px;bottom:30px}.marvel-device.iphone4s .home:after{width:20px;height:20px;border:1px solid rgba(255,255,255,0.1);border-radius:4px;position:absolute;display:block;content:'';top:50%;left:50%;margin-top:-11px;margin-left:-11px}.marvel-device.iphone4s .sleep{position:absolute;top:-4px;right:60px;width:60px;height:4px;border-radius:2px 2px 0px 0px;background:#4D4D4D}.marvel-device.iphone4s .volume{position:absolute;left:-4px;top:160px;height:27px;width:4px;border-radius:2px 0px 0px 2px;background:#4D4D4D}.marvel-device.iphone4s .volume:before{position:absolute;left:0px;top:-70px;height:35px;width:4px;border-radius:2px 0px 0px 2px;background:inherit;content:'';display:block}.marvel-device.iphone4s .volume:after{position:absolute;left:0px;bottom:-64px;height:27px;width:4px;border-radius:2px 0px 0px 2px;background:inherit;content:'';display:block}.marvel-device.iphone4s.landscape{padding:27px 129px;height:320px;width:480px}.marvel-device.iphone4s.landscape .bottom-bar{left:90px;bottom:0px;height:100%;width:3px}.marvel-device.iphone4s.landscape .top-bar{left:calc(100% - 60px);top:0px;height:100%;width:3px}.marvel-device.iphone4s.landscape .camera{top:134px;left:calc(100% - 72px);margin-left:0}.marvel-device.iphone4s.landscape .speaker{top:50%;margin-left:0;margin-top:-32px;left:calc(100% - 72px);width:10px;height:64px}.marvel-device.iphone4s.landscape .sensor{height:40px;width:10px;left:calc(100% - 36px);top:50%;margin-left:0;margin-top:-20px}.marvel-device.iphone4s.landscape .home{left:30px;bottom:50%;margin-left:0;margin-bottom:-36px}.marvel-device.iphone4s.landscape .sleep{height:60px;width:4px;right:-4px;top:calc(100% - 120px);border-radius:0px 2px 2px 0px}.marvel-device.iphone4s.landscape .volume{top:-4px;left:calc(100% - 187px);height:4px;width:27px;border-radius:2px 2px 0px 0px}.marvel-device.iphone4s.landscape .volume:before{right:-70px;left:auto;top:0px;width:35px;height:4px;border-radius:2px 2px 0px 0px}.marvel-device.iphone4s.landscape .volume:after{width:27px;height:4px;bottom:0px;left:-64px;border-radius:2px 2px 0px 0px}.marvel-device.iphone4s.silver{background:#bcbcbc}.marvel-device.iphone4s.silver:before{background:#fcfcfc}.marvel-device.iphone4s.silver .home{background:#fcfcfc;-webkit-box-shadow:inset 0 0 0 1px #bcbcbc;box-shadow:inset 0 0 0 1px #bcbcbc}.marvel-device.iphone4s.silver .home:after{border:1px solid rgba(0,0,0,0.2)}.marvel-device.iphone4s.silver .volume,.marvel-device.iphone4s.silver .sleep{background:#d6d6d6}.marvel-device.nexus5{padding:50px 15px 50px 15px;width:320px;height:568px;background:#1e1e1e;border-radius:20px}.marvel-device.nexus5:before{border-radius:600px / 50px;background:inherit;content:'';top:0;position:absolute;height:103.1%;width:calc(100% - 26px);top:50%;left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.marvel-device.nexus5 .top-bar{width:calc(100% - 8px);height:calc(100% - 6px);position:absolute;top:3px;left:4px;border-radius:20px;background:#181818}.marvel-device.nexus5 .top-bar:before{border-radius:600px / 50px;background:inherit;content:'';top:0;position:absolute;height:103.0%;width:calc(100% - 26px);top:50%;left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.marvel-device.nexus5 .bottom-bar{display:none}.marvel-device.nexus5 .sleep{width:3px;position:absolute;left:-3px;top:110px;height:100px;background:inherit;border-radius:2px 0px 0px 2px}.marvel-device.nexus5 .volume{width:3px;position:absolute;right:-3px;top:70px;height:45px;background:inherit;border-radius:0px 2px 2px 0px}.marvel-device.nexus5 .camera{background:#3c3d3d;width:10px;height:10px;position:absolute;top:18px;left:50%;z-index:3;margin-left:-5px;border-radius:100%}.marvel-device.nexus5 .camera:before{background:#3c3d3d;width:6px;height:6px;content:'';display:block;position:absolute;top:2px;left:-100px;z-index:3;border-radius:100%}.marvel-device.nexus5.landscape{padding:15px 50px 15px 50px;height:320px;width:568px}.marvel-device.nexus5.landscape:before{width:103.1%;height:calc(100% - 26px);border-radius:50px / 600px}.marvel-device.nexus5.landscape .top-bar{left:3px;top:4px;height:calc(100% - 8px);width:calc(100% - 6px)}.marvel-device.nexus5.landscape .top-bar:before{width:103%;height:calc(100% - 26px);border-radius:50px / 600px}.marvel-device.nexus5.landscape .sleep{height:3px;width:100px;left:calc(100% - 210px);top:-3px;border-radius:2px 2px 0px 0px}.marvel-device.nexus5.landscape .volume{height:3px;width:45px;right:70px;top:100%;border-radius:0px 0px 2px 2px}.marvel-device.nexus5.landscape .camera{top:50%;left:calc(100% - 18px);margin-left:0;margin-top:-5px}.marvel-device.nexus5.landscape .camera:before{top:-100px;left:2px}.marvel-device.s5{padding:60px 18px;border-radius:42px;width:320px;height:568px;background:#bcbcbc}.marvel-device.s5:before,.marvel-device.s5:after{width:calc(100% - 52px);content:'';display:block;height:26px;background:inherit;position:absolute;border-radius:500px / 40px;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.marvel-device.s5:before{top:-7px}.marvel-device.s5:after{bottom:-7px}.marvel-device.s5 .bottom-bar{display:none}.marvel-device.s5 .top-bar{border-radius:37px;width:calc(100% - 10px);height:calc(100% - 10px);top:5px;left:5px;background:radial-gradient(rgba(0,0,0,0.02) 20%, transparent 60%) 0 0,radial-gradient(rgba(0,0,0,0.02) 20%, transparent 60%) 3px 3px;background-color:white;background-size:4px 4px;background-position:center;z-index:2;position:absolute}.marvel-device.s5 .top-bar:before,.marvel-device.s5 .top-bar:after{width:calc(100% - 48px);content:'';display:block;height:26px;background:inherit;position:absolute;border-radius:500px / 40px;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.marvel-device.s5 .top-bar:before{top:-7px}.marvel-device.s5 .top-bar:after{bottom:-7px}.marvel-device.s5 .sleep{width:3px;position:absolute;left:-3px;top:100px;height:100px;background:#cecece;border-radius:2px 0px 0px 2px}.marvel-device.s5 .speaker{width:68px;height:8px;position:absolute;top:20px;display:block;z-index:3;left:50%;margin-left:-34px;background-color:#bcbcbc;background-position:top left;border-radius:4px}.marvel-device.s5 .sensor{display:block;position:absolute;top:20px;right:110px;background:#3c3d3d;border-radius:100%;width:8px;height:8px;z-index:3}.marvel-device.s5 .sensor:after{display:block;content:'';position:absolute;top:0px;right:12px;background:#3c3d3d;border-radius:100%;width:8px;height:8px;z-index:3}.marvel-device.s5 .camera{display:block;position:absolute;top:24px;right:42px;background:black;border-radius:100%;width:10px;height:10px;z-index:3}.marvel-device.s5 .camera:before{width:4px;height:4px;background:#3c3d3d;border-radius:100%;position:absolute;content:'';top:50%;left:50%;margin-top:-2px;margin-left:-2px}.marvel-device.s5 .home{position:absolute;z-index:3;bottom:17px;left:50%;width:70px;height:20px;background:white;border-radius:18px;display:block;margin-left:-35px;border:2px solid black}.marvel-device.s5.landscape{padding:18px 60px;height:320px;width:568px}.marvel-device.s5.landscape:before,.marvel-device.s5.landscape:after{height:calc(100% - 52px);width:26px;border-radius:40px / 500px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.marvel-device.s5.landscape:before{top:50%;left:-7px}.marvel-device.s5.landscape:after{top:50%;left:auto;right:-7px}.marvel-device.s5.landscape .top-bar:before,.marvel-device.s5.landscape .top-bar:after{width:26px;height:calc(100% - 48px);border-radius:40px / 500px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.marvel-device.s5.landscape .top-bar:before{right:-7px;top:50%;left:auto}.marvel-device.s5.landscape .top-bar:after{left:-7px;top:50%;right:auto}.marvel-device.s5.landscape .sleep{height:3px;width:100px;left:calc(100% - 200px);top:-3px;border-radius:2px 2px 0px 0px}.marvel-device.s5.landscape .speaker{height:68px;width:8px;left:calc(100% - 20px);top:50%;margin-left:0;margin-top:-34px}.marvel-device.s5.landscape .sensor{right:20px;top:calc(100% - 110px)}.marvel-device.s5.landscape .sensor:after{left:-12px;right:0px}.marvel-device.s5.landscape .camera{top:calc(100% - 42px);right:24px}.marvel-device.s5.landscape .home{width:20px;height:70px;bottom:50%;margin-bottom:-35px;margin-left:0;left:17px}.marvel-device.s5.black{background:#1e1e1e}.marvel-device.s5.black .speaker{background:black}.marvel-device.s5.black .sleep{background:#1e1e1e}.marvel-device.s5.black .top-bar{background:radial-gradient(rgba(0,0,0,0.05) 20%, transparent 60%) 0 0,radial-gradient(rgba(0,0,0,0.05) 20%, transparent 60%) 3px 3px;background-color:#2c2b2c;background-size:4px 4px}.marvel-device.s5.black .home{background:#2c2b2c}.marvel-device.lumia920{padding:80px 35px 125px 35px;background:#ffdd00;width:320px;height:533px;border-radius:40px / 3px}.marvel-device.lumia920 .bottom-bar{display:none}.marvel-device.lumia920 .top-bar{width:calc(100% - 24px);height:calc(100% - 32px);position:absolute;top:16px;left:12px;border-radius:24px;background:black;z-index:1}.marvel-device.lumia920 .top-bar:before{background:#1e1e1e;display:block;content:'';width:calc(100% - 4px);height:calc(100% - 4px);top:2px;left:2px;position:absolute;border-radius:22px}.marvel-device.lumia920 .volume{width:3px;position:absolute;top:130px;height:100px;background:#1e1e1e;right:-3px;border-radius:0px 2px 2px 0px}.marvel-device.lumia920 .volume:before{width:3px;position:absolute;top:190px;content:'';display:block;height:50px;background:inherit;right:0px;border-radius:0px 2px 2px 0px}.marvel-device.lumia920 .volume:after{width:3px;position:absolute;top:460px;content:'';display:block;height:50px;background:inherit;right:0px;border-radius:0px 2px 2px 0px}.marvel-device.lumia920 .camera{background:#3c3d3d;width:10px;height:10px;position:absolute;top:34px;right:130px;z-index:5;border-radius:5px}.marvel-device.lumia920 .speaker{background:#292728;width:64px;height:10px;position:absolute;top:38px;left:50%;margin-left:-32px;border-radius:5px;z-index:3}.marvel-device.lumia920.landscape{padding:35px 80px 35px 125px;height:320px;width:568px;border-radius:2px / 100px}.marvel-device.lumia920.landscape .top-bar{height:calc(100% - 24px);width:calc(100% - 32px);left:16px;top:12px}.marvel-device.lumia920.landscape .volume{height:3px;right:130px;width:100px;top:100%;border-radius:0px 0px 2px 2px}.marvel-device.lumia920.landscape .volume:before{height:3px;right:190px;top:0px;width:50px;border-radius:0px 0px 2px 2px}.marvel-device.lumia920.landscape .volume:after{height:3px;right:430px;top:0px;width:50px;border-radius:0px 0px 2px 2px}.marvel-device.lumia920.landscape .camera{right:30px;top:calc(100% - 140px)}.marvel-device.lumia920.landscape .speaker{width:10px;height:64px;top:50%;margin-left:0;margin-top:-32px;left:calc(100% - 48px)}.marvel-device.lumia920.black{background:black}.marvel-device.lumia920.white{background:white;-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,0.2);box-shadow:0 1px 2px 0 rgba(0,0,0,0.2)}.marvel-device.lumia920.blue{background:#00acdd}.marvel-device.lumia920.red{background:#CC3E32}.marvel-device.htc-one{padding:72px 25px 100px 25px;width:320px;height:568px;background:#bebebe;border-radius:34px}.marvel-device.htc-one:before{content:'';display:block;width:calc(100% - 4px);height:calc(100% - 4px);position:absolute;top:2px;left:2px;background:#adadad;border-radius:32px}.marvel-device.htc-one:after{content:'';display:block;width:calc(100% - 8px);height:calc(100% - 8px);position:absolute;top:4px;left:4px;background:#eeeeee;border-radius:30px}.marvel-device.htc-one .top-bar{width:calc(100% - 4px);height:635px;position:absolute;background:#424242;top:50px;z-index:1;left:2px}.marvel-device.htc-one .top-bar:before{content:'';position:absolute;width:calc(100% - 4px);height:100%;position:absolute;background:black;top:0px;z-index:1;left:2px}.marvel-device.htc-one .bottom-bar{display:none}.marvel-device.htc-one .speaker{height:16px;width:216px;display:block;position:absolute;top:22px;z-index:2;left:50%;margin-left:-108px;background:radial-gradient(#343434 25%, transparent 50%) 0 0,radial-gradient(#343434 25%, transparent 50%) 4px 4px;background-size:4px 4px;background-position:top left}.marvel-device.htc-one .speaker:after{content:'';height:16px;width:216px;display:block;position:absolute;top:676px;z-index:2;left:50%;margin-left:-108px;background:inherit}.marvel-device.htc-one .camera{display:block;position:absolute;top:18px;right:38px;background:#3c3d3d;border-radius:100%;width:24px;height:24px;z-index:3}.marvel-device.htc-one .camera:before{width:8px;height:8px;background:black;border-radius:100%;position:absolute;content:'';top:50%;left:50%;margin-top:-4px;margin-left:-4px}.marvel-device.htc-one .sensor{display:block;position:absolute;top:29px;left:60px;background:#3c3d3d;border-radius:100%;width:8px;height:8px;z-index:3}.marvel-device.htc-one .sensor:after{display:block;content:'';position:absolute;top:0px;right:12px;background:#3c3d3d;border-radius:100%;width:8px;height:8px;z-index:3}.marvel-device.htc-one.landscape{padding:25px 72px 25px 100px;height:320px;width:568px}.marvel-device.htc-one.landscape .top-bar{height:calc(100% - 4px);width:635px;left:calc(100% - 685px);top:2px}.marvel-device.htc-one.landscape .speaker{width:16px;height:216px;left:calc(100% - 38px);top:50%;margin-left:0px;margin-top:-108px}.marvel-device.htc-one.landscape .speaker:after{width:16px;height:216px;left:calc(100% - 692px);top:50%;margin-left:0;margin-top:-108px}.marvel-device.htc-one.landscape .camera{right:18px;top:calc(100% - 38px)}.marvel-device.htc-one.landscape .sensor{left:calc(100% - 29px);top:60px}.marvel-device.htc-one.landscape .sensor :after{right:0;top:-12px}.marvel-device.ipad{width:576px;height:768px;padding:90px 25px;background:#242324;border-radius:44px}.marvel-device.ipad:before{width:calc(100% - 8px);height:calc(100% - 8px);position:absolute;content:'';display:block;top:4px;left:4px;border-radius:40px;background:#1e1e1e}.marvel-device.ipad .camera{background:#3c3d3d;width:10px;height:10px;position:absolute;top:44px;left:50%;margin-left:-5px;border-radius:100%}.marvel-device.ipad .top-bar,.marvel-device.ipad .bottom-bar{display:none}.marvel-device.ipad .home{background:#242324;border-radius:36px;width:50px;height:50px;position:absolute;left:50%;margin-left:-25px;bottom:22px}.marvel-device.ipad .home:after{width:15px;height:15px;margin-top:-8px;margin-left:-8px;border:1px solid rgba(255,255,255,0.1);border-radius:4px;position:absolute;display:block;content:'';top:50%;left:50%}.marvel-device.ipad.landscape{height:576px;width:768px;padding:25px 90px}.marvel-device.ipad.landscape .camera{left:calc(100% - 44px);top:50%;margin-left:0;margin-top:-5px}.marvel-device.ipad.landscape .home{top:50%;left:22px;margin-left:0;margin-top:-25px}.marvel-device.ipad.silver{background:#bcbcbc}.marvel-device.ipad.silver:before{background:#fcfcfc}.marvel-device.ipad.silver .home{background:#fcfcfc;-webkit-box-shadow:inset 0 0 0 1px #bcbcbc;box-shadow:inset 0 0 0 1px #bcbcbc}.marvel-device.ipad.silver .home:after{border:1px solid rgba(0,0,0,0.2)}.marvel-device.macbook{width:960px;height:600px;padding:44px 44px 76px;margin:0 auto;background:#bebebe;border-radius:34px}.marvel-device.macbook:before{width:calc(100% - 8px);height:calc(100% - 8px);position:absolute;content:'';display:block;top:4px;left:4px;border-radius:30px;background:#1e1e1e}.marvel-device.macbook .top-bar{width:calc(100% + 2 * 70px);height:40px;position:absolute;content:'';display:block;top:680px;left:-70px;border-bottom-left-radius:90px 18px;border-bottom-right-radius:90px 18px;background:#bebebe;-webkit-box-shadow:inset 0px -4px 13px 3px rgba(34,34,34,0.6);box-shadow:inset 0px -4px 13px 3px rgba(34,34,34,0.6)}.marvel-device.macbook .top-bar:before{width:100%;height:24px;content:'';display:block;top:0;left:0;background:#f0f0f0;border-bottom:2px solid #aaa;border-radius:5px;position:relative}.marvel-device.macbook .top-bar:after{width:16%;height:14px;content:'';display:block;top:0;background:#ddd;position:absolute;margin-left:auto;margin-right:auto;left:0;right:0;border-radius:0 0 20px 20px;-webkit-box-shadow:inset 0px -3px 10px #999;box-shadow:inset 0px -3px 10px #999}.marvel-device.macbook .bottom-bar{background:transparent;width:calc(100% + 2 * 70px);height:26px;position:absolute;content:'';display:block;top:680px;left:-70px}.marvel-device.macbook .bottom-bar:before,.marvel-device.macbook .bottom-bar:after{height:calc(100% - 2px);width:80px;content:'';display:block;top:0;position:absolute}.marvel-device.macbook .bottom-bar:before{left:0;background:#f0f0f0;background:-webkit-gradient(linear, left top, right top, from(#747474), color-stop(5%, #c3c3c3), color-stop(14%, #ebebeb), color-stop(41%, #979797), color-stop(80%, #f0f0f0), color-stop(100%, #f0f0f0), to(#f0f0f0));background:linear-gradient(to right, #747474 0%, #c3c3c3 5%, #ebebeb 14%, #979797 41%, #f0f0f0 80%, #f0f0f0 100%, #f0f0f0 100%)}.marvel-device.macbook .bottom-bar:after{right:0;background:#f0f0f0;background:-webkit-gradient(linear, left top, right top, from(#f0f0f0), color-stop(0%, #f0f0f0), color-stop(20%, #f0f0f0), color-stop(59%, #979797), color-stop(86%, #ebebeb), color-stop(95%, #c3c3c3), to(#747474));background:linear-gradient(to right, #f0f0f0 0%, #f0f0f0 0%, #f0f0f0 20%, #979797 59%, #ebebeb 86%, #c3c3c3 95%, #747474 100%)}.marvel-device.macbook .camera{background:#3c3d3d;width:10px;height:10px;position:absolute;top:20px;left:50%;margin-left:-5px;border-radius:100%}.marvel-device.macbook .home{display:none}.marvel-device.iphone-x{width:375px;height:812px;padding:26px;background:#fdfdfd;-webkit-box-shadow:inset 0 0 11px 0 black;box-shadow:inset 0 0 11px 0 black;border-radius:66px}.marvel-device.iphone-x .overflow{width:100%;height:100%;position:absolute;top:0;left:0;border-radius:66px;overflow:hidden}.marvel-device.iphone-x .shadow{border-radius:100%;width:90px;height:90px;position:absolute;background:radial-gradient(ellipse at center, rgba(0,0,0,0.6) 0%, rgba(255,255,255,0) 60%)}.marvel-device.iphone-x .shadow--tl{top:-20px;left:-20px}.marvel-device.iphone-x .shadow--tr{top:-20px;right:-20px}.marvel-device.iphone-x .shadow--bl{bottom:-20px;left:-20px}.marvel-device.iphone-x .shadow--br{bottom:-20px;right:-20px}.marvel-device.iphone-x:before{width:calc(100% - 10px);height:calc(100% - 10px);position:absolute;top:5px;content:'';left:5px;border-radius:61px;background:black;z-index:1}.marvel-device.iphone-x .inner-shadow{width:calc(100% - 20px);height:calc(100% - 20px);position:absolute;top:10px;overflow:hidden;left:10px;border-radius:56px;-webkit-box-shadow:inset 0 0 15px 0 rgba(255,255,255,0.66);box-shadow:inset 0 0 15px 0 rgba(255,255,255,0.66);z-index:1}.marvel-device.iphone-x .inner-shadow:before{-webkit-box-shadow:inset 0 0 20px 0 #FFFFFF;box-shadow:inset 0 0 20px 0 #FFFFFF;width:100%;height:116%;position:absolute;top:-8%;content:'';left:0;border-radius:200px / 112px;z-index:2}.marvel-device.iphone-x .screen{border-radius:40px;-webkit-box-shadow:none;box-shadow:none}.marvel-device.iphone-x .top-bar,.marvel-device.iphone-x .bottom-bar{width:100%;position:absolute;height:8px;background:rgba(0,0,0,0.1);left:0}.marvel-device.iphone-x .top-bar{top:80px}.marvel-device.iphone-x .bottom-bar{bottom:80px}.marvel-device.iphone-x .volume,.marvel-device.iphone-x .volume:before,.marvel-device.iphone-x .volume:after,.marvel-device.iphone-x .sleep{width:3px;background:#b5b5b5;position:absolute}.marvel-device.iphone-x .volume{left:-3px;top:116px;height:32px}.marvel-device.iphone-x .volume:before{height:62px;top:62px;content:'';left:0}.marvel-device.iphone-x .volume:after{height:62px;top:140px;content:'';left:0}.marvel-device.iphone-x .sleep{height:96px;top:200px;right:-3px}.marvel-device.iphone-x .camera{width:6px;height:6px;top:9px;border-radius:100%;position:absolute;left:154px;background:#0d4d71}.marvel-device.iphone-x .speaker{height:6px;width:60px;left:50%;position:absolute;top:9px;margin-left:-30px;background:#171818;border-radius:6px}.marvel-device.iphone-x .notch{position:absolute;width:210px;height:30px;top:26px;left:108px;z-index:4;background:black;border-bottom-left-radius:24px;border-bottom-right-radius:24px}.marvel-device.iphone-x .notch:before,.marvel-device.iphone-x .notch:after{content:'';height:8px;position:absolute;top:0;width:8px}.marvel-device.iphone-x .notch:after{background:radial-gradient(circle at bottom left, transparent 0, transparent 70%, black 70%, black 100%);left:-8px}.marvel-device.iphone-x .notch:before{background:radial-gradient(circle at bottom right, transparent 0, transparent 70%, black 70%, black 100%);right:-8px}.marvel-device.iphone-x.landscape{height:375px;width:812px}.marvel-device.iphone-x.landscape .top-bar,.marvel-device.iphone-x.landscape .bottom-bar{width:8px;height:100%;top:0}.marvel-device.iphone-x.landscape .top-bar{left:80px}.marvel-device.iphone-x.landscape .bottom-bar{right:80px;bottom:auto;left:auto}.marvel-device.iphone-x.landscape .volume,.marvel-device.iphone-x.landscape .volume:before,.marvel-device.iphone-x.landscape .volume:after,.marvel-device.iphone-x.landscape .sleep{height:3px}.marvel-device.iphone-x.landscape .inner-shadow:before{height:100%;width:116%;left:-8%;top:0;border-radius:112px / 200px}.marvel-device.iphone-x.landscape .volume{bottom:-3px;top:auto;left:116px;width:32px}.marvel-device.iphone-x.landscape .volume:before{width:62px;left:62px;top:0}.marvel-device.iphone-x.landscape .volume:after{width:62px;left:140px;top:0}.marvel-device.iphone-x.landscape .sleep{width:96px;left:200px;top:-3px;right:auto}.marvel-device.iphone-x.landscape .camera{left:9px;bottom:154px;top:auto}.marvel-device.iphone-x.landscape .speaker{width:6px;height:60px;left:9px;top:50%;margin-top:-30px;margin-left:0}.marvel-device.iphone-x.landscape .notch{height:210px;width:30px;left:26px;bottom:108px;top:auto;border-top-right-radius:24px;border-bottom-right-radius:24px;border-bottom-left-radius:0}.marvel-device.iphone-x.landscape .notch:before,.marvel-device.iphone-x.landscape .notch:after{left:0}.marvel-device.iphone-x.landscape .notch:after{background:radial-gradient(circle at bottom right, transparent 0, transparent 70%, black 70%, black 100%);bottom:-8px;top:auto}.marvel-device.iphone-x.landscape .notch:before{background:radial-gradient(circle at top right, transparent 0, transparent 70%, black 70%, black 100%);top:-8px}.marvel-device.note8{width:400px;height:822px;background:black;border-radius:34px;padding:45px 10px}.marvel-device.note8 .overflow{width:100%;height:100%;position:absolute;top:0;left:0;border-radius:34px;overflow:hidden}.marvel-device.note8 .speaker{height:8px;width:56px;left:50%;position:absolute;top:25px;margin-left:-28px;background:#171818;z-index:1;border-radius:8px}.marvel-device.note8 .camera{height:18px;width:18px;left:86px;position:absolute;top:18px;background:#212b36;z-index:1;border-radius:100%}.marvel-device.note8 .camera:before{content:'';height:8px;width:8px;left:-22px;position:absolute;top:5px;background:#212b36;z-index:1;border-radius:100%}.marvel-device.note8 .sensors{height:10px;width:10px;left:120px;position:absolute;top:22px;background:#1d233b;z-index:1;border-radius:100%}.marvel-device.note8 .sensors:before{content:'';height:10px;width:10px;left:18px;position:absolute;top:0;background:#1d233b;z-index:1;border-radius:100%}.marvel-device.note8 .more-sensors{height:16px;width:16px;left:285px;position:absolute;top:18px;background:#33244a;-webkit-box-shadow:0 0 0 2px rgba(255,255,255,0.1);box-shadow:0 0 0 2px rgba(255,255,255,0.1);z-index:1;border-radius:100%}.marvel-device.note8 .more-sensors:before{content:'';height:11px;width:11px;left:40px;position:absolute;top:4px;background:#214a61;z-index:1;border-radius:100%}.marvel-device.note8 .sleep{width:2px;height:56px;background:black;position:absolute;top:288px;right:-2px}.marvel-device.note8 .volume{width:2px;height:120px;background:black;position:absolute;top:168px;left:-2px}.marvel-device.note8 .volume:before{content:'';top:168px;width:2px;position:absolute;left:0;background:black;height:56px}.marvel-device.note8 .inner{width:100%;height:calc(100% - 8px);position:absolute;top:2px;content:'';left:0px;border-radius:34px;border-top:2px solid #9fa0a2;border-bottom:2px solid #9fa0a2;background:black;z-index:1;-webkit-box-shadow:inset 0 0 6px 0 rgba(255,255,255,0.5);box-shadow:inset 0 0 6px 0 rgba(255,255,255,0.5)}.marvel-device.note8 .shadow{-webkit-box-shadow:inset 0 0 60px 0 white,inset 0 0 30px 0 rgba(255,255,255,0.5),0 0 20px 0 white,0 0 20px 0 rgba(255,255,255,0.5);box-shadow:inset 0 0 60px 0 white,inset 0 0 30px 0 rgba(255,255,255,0.5),0 0 20px 0 white,0 0 20px 0 rgba(255,255,255,0.5);height:101%;position:absolute;top:-0.5%;content:'';width:calc(100% - 20px);left:10px;border-radius:38px;z-index:5;pointer-events:none}.marvel-device.note8 .screen{border-radius:14px;-webkit-box-shadow:none;box-shadow:none}.marvel-device.note8.landscape{height:400px;width:822px;padding:10px 45px}.marvel-device.note8.landscape .speaker{height:56px;width:8px;top:50%;margin-top:-28px;margin-left:0;right:25px;left:auto}.marvel-device.note8.landscape .camera{top:86px;right:18px;left:auto}.marvel-device.note8.landscape .camera:before{top:-22px;left:5px}.marvel-device.note8.landscape .sensors{top:120px;right:22px;left:auto}.marvel-device.note8.landscape .sensors:before{top:18px;left:0}.marvel-device.note8.landscape .more-sensors{top:285px;right:18px;left:auto}.marvel-device.note8.landscape .more-sensors:before{top:40px;left:4px}.marvel-device.note8.landscape .sleep{bottom:-2px;top:auto;right:288px;width:56px;height:2px}.marvel-device.note8.landscape .volume{width:120px;height:2px;top:-2px;right:168px;left:auto}.marvel-device.note8.landscape .volume:before{right:168px;left:auto;top:0;width:56px;height:2px}.marvel-device.note8.landscape .inner{height:100%;width:calc(100% - 8px);left:2px;top:0;border-top:0;border-bottom:0;border-left:2px solid #9fa0a2;border-right:2px solid #9fa0a2}.marvel-device.note8.landscape .shadow{width:101%;height:calc(100% - 20px);left:-0.5%;top:10px} diff --git a/frontend/app/components/Alerts/AlertForm.js b/frontend/app/components/Alerts/AlertForm.js new file mode 100644 index 000000000..deb0fa405 --- /dev/null +++ b/frontend/app/components/Alerts/AlertForm.js @@ -0,0 +1,332 @@ +import React from 'react' +import { Button, Dropdown, Form, Input, SegmentSelection, Checkbox, Message, Link, Icon } from 'UI'; +import { alertMetrics as metrics } from 'App/constants'; +import { alertConditions as conditions } from 'App/constants'; +import { client, CLIENT_TABS } from 'App/routes'; +import { connect } from 'react-redux'; +import stl from './alertForm.css'; +import DropdownChips from './DropdownChips'; +import { validateEmail } from 'App/validate'; +import cn from 'classnames'; + +const thresholdOptions = [ + { text: '15 minutes', value: 15 }, + { text: '30 minutes', value: 30 }, + { text: '1 hour', value: 60 }, + { text: '2 hours', value: 120 }, + { text: '4 hours', value: 240 }, + { text: '1 day', value: 1440 }, +]; + +const changeOptions = [ + { text: 'change', value: 'change' }, + { text: '% change', value: 'percent' }, +]; + +const Circle = ({ text }) => ( +
{text}
+) + +const Section = ({ index, title, description, content }) => ( +
+
+ +
+ {title} + { description &&
{description}
} +
+
+ +
+ {content} +
+
+) + +const integrationsRoute = client(CLIENT_TABS.INTEGRATIONS); + +const AlertForm = props => { + const { instance, slackChannels, webhooks, loading, onDelete, deleting } = props; + const write = ({ target: { value, name } }) => props.edit({ [ name ]: value }) + const writeOption = (e, { name, value }) => props.edit({ [ name ]: value }); + const onChangeOption = (e, { checked, name }) => props.edit({ [ name ]: checked }) + + const writeQueryOption = (e, { name, value }) => { + const { query } = instance; + props.edit({ query: { ...query, [name] : value } }); + } + + const writeQuery = ({ target: { value, name } }) => { + const { query } = instance; + props.edit({ query: { ...query, [name] : value } }); + } + + const metric = (instance && instance.query.left) ? metrics.find(i => i.value === instance.query.left) : null; + const unit = metric ? metric.unit : ''; + const isThreshold = instance.detectionMethod === 'threshold'; + + + return ( +
props.onSubmit(instance)} id="alert-form"> +
+ +
+
+ +
+ {isThreshold && 'Eg. Alert me if memory.avg is greater than 500mb over the past 4 hours.'} + {!isThreshold && 'Eg. Alert me if % change of memory.avg is greater than 10% over the past 4 hours compared to the previous 4 hours.'} +
+
+
+ } + /> + +
+ +
+ {!isThreshold && ( +
+ + +
+ )} + +
+ + +
+ +
+ +
+ + { unit && ( + + )} + { !unit && ( + + )} +
+
+ +
+ + +
+ {!isThreshold && ( +
+ + +
+ )} +
+ } + /> + +
+ +
+
+ + + +
+ + { instance.slack && ( +
+ +
+ props.edit({ 'slackInput': selected })} + /> +
+
+ )} + + {instance.email && ( +
+ +
+ props.edit({ 'emailInput': selected })} + /> +
+
+ )} + + + {instance.webhook && ( +
+ + props.edit({ 'webhookInput': selected })} + /> +
+ )} +
+ } + /> + + + +
+
+ +
+ +
+
+ {instance.exists() && ( + + )} +
+
+ + ) +} + +export default connect(state => ({ + instance: state.getIn(['alerts', 'instance']), + loading: state.getIn(['alerts', 'saveRequest', 'loading']), + deleting: state.getIn(['alerts', 'removeRequest', 'loading']) +}))(AlertForm) diff --git a/frontend/app/components/Alerts/AlertItem.js b/frontend/app/components/Alerts/AlertItem.js new file mode 100644 index 000000000..a70935331 --- /dev/null +++ b/frontend/app/components/Alerts/AlertItem.js @@ -0,0 +1,55 @@ +import React from 'react' +import cn from 'classnames'; +import stl from './alertItem.css'; +import AlertTypeLabel from './AlertTypeLabel'; + +const AlertItem = props => { + const { alert, onEdit, active } = props; + + const getThreshold = threshold => { + if (threshold === 15) return '15 Minutes'; + if (threshold === 30) return '30 Minutes'; + if (threshold === 60) return '1 Hour'; + if (threshold === 120) return '2 Hours'; + if (threshold === 240) return '4 Hours'; + if (threshold === 1440) return '1 Day'; + } + + const getNotifyChannel = alert => { + let str = ''; + if (alert.slack) + str = 'Slack'; + if (alert.email) + str += (str === '' ? '' : ' and ')+ 'Email'; + if (alert.webhool) + str += (str === '' ? '' : ' and ')+ 'Webhook'; + if (str === '') + return 'OpenReplay'; + + return str; + } + + const isThreshold = alert.detectionMethod === 'threshold'; + + return ( +
+ +
{alert.name}
+
+ {alert.detectionMethod === 'threshold' && ( +
When {alert.metric.text} is {alert.condition.text} {alert.query.right} {alert.metric.unit} over the past {getThreshold(alert.currentPeriod)}, notify me on {getNotifyChannel(alert)}.
+ )} + + {alert.detectionMethod === 'change' && ( +
When the {alert.options.change} of {alert.metric.text} is {alert.condition.text} {alert.query.right} {alert.metric.unit} over the past {getThreshold(alert.currentPeriod)} compared to the previous {getThreshold(alert.previousPeriod)}, notify me on {getNotifyChannel(alert)}.
+ )} +
+
+ ) +} + +export default AlertItem diff --git a/frontend/app/components/Alerts/AlertTypeLabel.js b/frontend/app/components/Alerts/AlertTypeLabel.js new file mode 100644 index 000000000..b10e34d84 --- /dev/null +++ b/frontend/app/components/Alerts/AlertTypeLabel.js @@ -0,0 +1,13 @@ +import React from 'react' +import cn from 'classnames' +import stl from './alertTypeLabel.css' + +function AlertTypeLabel({ filterKey, type = '' }) { + return ( +
+ { type } +
+ ) +} + +export default AlertTypeLabel diff --git a/frontend/app/components/Alerts/Alerts.js b/frontend/app/components/Alerts/Alerts.js new file mode 100644 index 000000000..aaa99b7a2 --- /dev/null +++ b/frontend/app/components/Alerts/Alerts.js @@ -0,0 +1,100 @@ +import React, { useEffect, useState } from 'react' +import AlertsList from './AlertsList' +import { SlideModal, IconButton } from 'UI'; +import { init, edit, save, remove } from 'Duck/alerts'; +import { fetchList as fetchWebhooks } from 'Duck/webhook'; +import AlertForm from './AlertForm'; +import { connect } from 'react-redux'; +import { setShowAlerts } from 'Duck/dashboard'; +import { EMAIL, SLACK, WEBHOOK } from 'App/constants/schedule'; +import { confirm } from 'UI/Confirmation'; + +const Alerts = props => { + const { webhooks, setShowAlerts } = props; + const [showForm, setShowForm] = useState(false); + + useEffect(() => { + props.fetchWebhooks(); + }, []) + + const slackChannels = webhooks.filter(hook => hook.type === SLACK).map(({ webhookId, name }) => ({ value: webhookId, text: name })).toJS(); + const hooks = webhooks.filter(hook => hook.type === WEBHOOK).map(({ webhookId, name }) => ({ value: webhookId, text: name })).toJS(); + + const saveAlert = instance => { + const wasUpdating = instance.exists(); + props.save(instance).then(() => { + if (!wasUpdating) { + toggleForm(null, false); + } + }) + } + + const onDelete = async (instance) => { + if (await confirm({ + header: 'Confirm', + confirmButton: 'Yes, Delete', + confirmation: `Are you sure you want to permanently delete this alert?` + })) { + props.remove(instance.alertId).then(() => { + toggleForm(null, false); + }); + } + } + + const toggleForm = (instance, state) => { + if (instance) { + props.init(instance) + } + return setShowForm(state ? state : !showForm); + } + + return ( +
+ + { 'Alerts' } + toggleForm({}, true) } + /> +
+ } + isDisplayed={ true } + onClose={ () => { + toggleForm({}, false); + setShowAlerts(false); + } } + size="small" + content={ + { + toggleForm(alert, true) + }} + /> + } + detailContent={ + showForm && ( + toggleForm({}, false) } + onDelete={onDelete} + /> + ) + } + /> +
+ ) +} + +export default connect(state => ({ + webhooks: state.getIn(['webhooks', 'list']), + instance: state.getIn(['alerts', 'instance']), +}), { init, edit, save, remove, fetchWebhooks, setShowAlerts })(Alerts) diff --git a/frontend/app/components/Alerts/AlertsList.js b/frontend/app/components/Alerts/AlertsList.js new file mode 100644 index 000000000..21fbce249 --- /dev/null +++ b/frontend/app/components/Alerts/AlertsList.js @@ -0,0 +1,56 @@ +import React, { useEffect, useState } from 'react' +import { Loader, NoContent, Input } from 'UI'; +import AlertItem from './AlertItem' +import { fetchList, init } from 'Duck/alerts'; +import { connect } from 'react-redux'; +import { getRE } from 'App/utils'; + +const AlertsList = props => { + const { loading, list, instance, onEdit } = props; + const [query, setQuery] = useState('') + + useEffect(() => { + props.fetchList() + }, []) + + const filterRE = getRE(query, 'i'); + const _filteredList = list.filter(({ name, query: { left } }) => filterRE.test(name) || filterRE.test(left)); + + return ( +
+
+ setQuery(value)} + /> +
+ + +
+ {_filteredList.map(a => ( +
+ onEdit(a.toData())} + /> +
+ ))} +
+
+
+
+ ) +} + +export default connect(state => ({ + list: state.getIn(['alerts', 'list']).sort((a, b ) => b.createdAt - a.createdAt), + instance: state.getIn(['alerts', 'instance']), + loading: state.getIn(['alerts', 'loading']) +}), { fetchList, init })(AlertsList) diff --git a/frontend/app/components/Alerts/DropdownChips/DropdownChips.js b/frontend/app/components/Alerts/DropdownChips/DropdownChips.js new file mode 100644 index 000000000..38bb51948 --- /dev/null +++ b/frontend/app/components/Alerts/DropdownChips/DropdownChips.js @@ -0,0 +1,79 @@ +import React from 'react' +import { Dropdown, TagBadge } from 'UI'; + +const DropdownChips = ({ + textFiled = false, + validate = null, + placeholder = '', + selected = [], + options = [], + badgeClassName = 'lowercase', + onChange = () => null, + ...props +}) => { + const onRemove = id => { + onChange(selected.filter(i => i !== id)) + } + + const onSelect = (e, { name, value }) => { + const newSlected = selected.concat(value); + onChange(newSlected) + }; + + const onKeyPress = e => { + const val = e.target.value; + if (e.key !== 'Enter' || selected.includes(val)) return; + if (validate && !validate(val)) return; + + const newSlected = selected.concat(val); + e.target.value = ''; + onChange(newSlected); + e.preventDefault(); + e.stopPropagation(); + } + + const _options = options.filter(item => !selected.includes(item.value)) + + const renderBadge = item => { + const val = typeof item === 'string' ? item : item.value; + const text = typeof item === 'string' ? item : item.text; + return ( + onRemove(val) } + outline={ true } + /> + ) + } + + return ( +
+ {textFiled ? ( + + ) : ( + + )} +
+ { + textFiled ? + selected.map(renderBadge) : + options.filter(i => selected.includes(i.value)).map(renderBadge) + } +
+
+ ) +} + +export default DropdownChips diff --git a/frontend/app/components/Alerts/DropdownChips/index.js b/frontend/app/components/Alerts/DropdownChips/index.js new file mode 100644 index 000000000..9b4fbefff --- /dev/null +++ b/frontend/app/components/Alerts/DropdownChips/index.js @@ -0,0 +1 @@ +export { default } from './DropdownChips' \ No newline at end of file diff --git a/frontend/app/components/Alerts/Notifications/ListItem/ListItem.js b/frontend/app/components/Alerts/Notifications/ListItem/ListItem.js new file mode 100644 index 000000000..4ffe87e44 --- /dev/null +++ b/frontend/app/components/Alerts/Notifications/ListItem/ListItem.js @@ -0,0 +1,33 @@ +import React from 'react'; +import { Button } from 'UI'; +import stl from './listItem.css'; +import cn from 'classnames'; +import AlertTypeLabel from '../../AlertTypeLabel'; + +const ListItem = ({ alert, onClear, loading, onNavigate }) => { + return ( +
+
+
{alert.createdAt && alert.createdAt.toFormat('LLL dd, yyyy, hh:mm a')}
+
+ +
+
+ + +
+

+ {alert.title} +

+
{alert.description}
+
+
+ ) +} + +export default ListItem diff --git a/frontend/app/components/Alerts/Notifications/ListItem/index.js b/frontend/app/components/Alerts/Notifications/ListItem/index.js new file mode 100644 index 000000000..741aed270 --- /dev/null +++ b/frontend/app/components/Alerts/Notifications/ListItem/index.js @@ -0,0 +1 @@ +export { default } from './ListItem'; diff --git a/frontend/app/components/Alerts/Notifications/ListItem/listItem.css b/frontend/app/components/Alerts/Notifications/ListItem/listItem.css new file mode 100644 index 000000000..8472a777c --- /dev/null +++ b/frontend/app/components/Alerts/Notifications/ListItem/listItem.css @@ -0,0 +1,7 @@ +.wrapper { + padding: 15px; +} + +.viewed { + background-color: $gray-lightest; +} \ No newline at end of file diff --git a/frontend/app/components/Alerts/Notifications/Notifications.js b/frontend/app/components/Alerts/Notifications/Notifications.js new file mode 100644 index 000000000..7332b8a85 --- /dev/null +++ b/frontend/app/components/Alerts/Notifications/Notifications.js @@ -0,0 +1,144 @@ +import React from 'react'; +import stl from './notifications.css'; +import ListItem from './ListItem'; +import { connect } from 'react-redux'; +import { Button, SlideModal, Icon, Popup, NoContent, SegmentSelection } from 'UI'; +import { fetchList, setViewed, setLastRead, clearAll } from 'Duck/notifications'; +import withToggle from 'Components/hocs/withToggle'; +import { withRouter } from 'react-router-dom'; +import { fetchList as fetchAlerts, init as initAlert } from 'Duck/alerts'; +import cn from 'classnames'; + +const AUTOREFRESH_INTERVAL = 5 * 60 * 1000; + +@withToggle('visible', 'toggleVisisble') +@withRouter +class Notifications extends React.Component { + state = { alertType: '' }; + + constructor(props) { + super(props); + props.fetchList(); + setInterval(() => { + props.fetchList(); + }, AUTOREFRESH_INTERVAL); + } + + writeOption = (e, { name, value }) => this.setState({ [ name ]: value }); + + navigateToUrl = notification => { // TODO should be able to open the alert edit form + if (notification.options.source === 'ALERT') { + const { initAlert } = this.props; + this.props.fetchAlerts().then(function() { + const { alerts } = this.props; + const alert = alerts.find(i => i.alertId === notification.options.sourceId) + initAlert(alert.toJS()); + }.bind(this)); + } + } + + onClearAll = () => { + const { notifications } = this.props; + const firstItem = notifications.first(); + this.props.clearAll({ endTimestamp: firstItem.createdAt.ts }); + } + + onClear = notification => { + this.props.setViewed(notification.notificationId) + } + + toggleModal = () => { + this.props.toggleVisisble(!this.props.visible); + } + + render() { + const { notifications, visible, loading, clearing, clearingAll } = this.props; + const { alertType } = this.state; + const unReadNotificationsCount = notifications.filter(({viewed}) => !viewed).size + + const filteredList = alertType === '' ? + notifications : + notifications.filter(i => i.filterKey === alertType); + + return ( +
+ +
+ { unReadNotificationsCount } +
+ +
+ } + content={ `Alerts` } + size="tiny" + inverted + position="top center" + /> + +
Alerts
+ { unReadNotificationsCount > 0 && ( +
+ +
+ )} + + } + right + isDisplayed={ visible } + onClose={ visible && this.toggleModal } + bgColor="white" + size="small" + content={ +
+ + { + filteredList.map(item => ( +
+ this.onClear(item)} + loading={clearing} + /> +
+ )) + } +
+
+ } + /> + + ); + } +} + +export default connect(state => ({ + notifications: state.getIn(['notifications', 'list']), + loading: state.getIn(['notifications', 'fetchRequest', 'loading']), + clearing: state.getIn(['notifications', 'setViewed', 'loading']), + clearingAll: state.getIn(['notifications', 'clearAll', 'loading']), + alerts: state.getIn(['alerts', 'list']), +}), { fetchList, setLastRead, setViewed, clearAll, fetchAlerts, initAlert })(Notifications); \ No newline at end of file diff --git a/frontend/app/components/Alerts/Notifications/index.js b/frontend/app/components/Alerts/Notifications/index.js new file mode 100644 index 000000000..7b9d9ad12 --- /dev/null +++ b/frontend/app/components/Alerts/Notifications/index.js @@ -0,0 +1 @@ +export { default } from './Notifications'; \ No newline at end of file diff --git a/frontend/app/components/Alerts/Notifications/notifications.css b/frontend/app/components/Alerts/Notifications/notifications.css new file mode 100644 index 000000000..3e4101502 --- /dev/null +++ b/frontend/app/components/Alerts/Notifications/notifications.css @@ -0,0 +1,39 @@ +.wrapper { + position: relative; + background-color: white; +} + +.button { + position: relative; + cursor: pointer; + display: flex; + align-items: center; + padding: 0 15px; + height: 50px; + transition: all 0.3s; + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + + &[data-active=true] { + background-color: $gray-lightest; + } +} + +.counter { + position: absolute; + top: 8px; + left: 24px; + background-color: $red; + color: white; + font-size: 9px; + min-width: 16px; + height: 16px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + padding: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/Alerts/alertForm.css b/frontend/app/components/Alerts/alertForm.css new file mode 100644 index 000000000..e9eff4af3 --- /dev/null +++ b/frontend/app/components/Alerts/alertForm.css @@ -0,0 +1,28 @@ +.wrapper { + height: 100vh; + position: relative; +} + +.content { + height: calc(100vh - 102px); + overflow-y: auto; + + &::-webkit-scrollbar { + width: 2px; + } + + &::-webkit-scrollbar-thumb { + background: transparent; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &:hover { + &::-webkit-scrollbar-track { + background: #f3f3f3; + } + &::-webkit-scrollbar-thumb { + background: $gray-medium; + } + } +} diff --git a/frontend/app/components/Alerts/alertItem.css b/frontend/app/components/Alerts/alertItem.css new file mode 100644 index 000000000..fe26fe57e --- /dev/null +++ b/frontend/app/components/Alerts/alertItem.css @@ -0,0 +1,9 @@ +.wrapper { + &:hover { + background-color: $active-blue; + } + + &.active { + background-color: $active-blue; + } +} diff --git a/frontend/app/components/Alerts/alertTypeLabel.css b/frontend/app/components/Alerts/alertTypeLabel.css new file mode 100644 index 000000000..62ed31460 --- /dev/null +++ b/frontend/app/components/Alerts/alertTypeLabel.css @@ -0,0 +1,11 @@ +.wrapper { + background-color: white; + color: $gray-dark; + border: solid thin $gray-light; +} + +.alert { + background: #C3E9EA; + color: #32888C; + border: none; +} diff --git a/frontend/app/components/Alerts/alerts.stories.js b/frontend/app/components/Alerts/alerts.stories.js new file mode 100644 index 000000000..781a7e734 --- /dev/null +++ b/frontend/app/components/Alerts/alerts.stories.js @@ -0,0 +1,130 @@ +import { storiesOf } from '@storybook/react'; +import { List } from 'immutable'; +import Alert from 'Types/alert'; +import Notification from 'Types/notification'; +import Alerts from '.'; +import Notifications from './Notifications'; +import AlertsList from './AlertsList'; +import AlertForm from './AlertForm'; + +const list = [ + { + "alertId": 2, + "projectId": 1, + "name": "new alert", + "description": null, + "active": true, + "threshold": 240, + "detectionMethod": "threshold", + "query": { + "left": "avgPageLoad", + "right": 1.0, + "operator": ">=" + }, + "createdAt": 1591893324078, + "options": { + "message": [ + { + "type": "slack", + "value": "51" + }, + ], + "LastNotification": 1592929583000, + "renotifyInterval": 120 + } + }, + { + "alertId": 14, + "projectId": 1, + "name": "alert 19.06", + "description": null, + "active": true, + "threshold": 30, + "detectionMethod": "threshold", + "query": { + "left": "avgPageLoad", + "right": 3000.0, + "operator": ">=" + }, + "createdAt": 1592579750935, + "options": { + "message": [ + { + "type": "slack", + "value": "51" + } + ], + "renotifyInterval": 120 + } + }, + { + "alertId": 15, + "projectId": 1, + "name": "notify every 60min", + "description": null, + "active": true, + "threshold": 30, + "detectionMethod": "threshold", + "query": { + "left": "avgPageLoad", + "right": 1.0, + "operator": ">=" + }, + "createdAt": 1592848779604, + "options": { + "message": [ + { + "type": "slack", + "value": "51" + }, + ], + "LastNotification": 1599135058000, + "renotifyInterval": 60 + } + }, + { + "alertId": 21, + "projectId": 1, + "name": "always notify", + "description": null, + "active": true, + "threshold": 30, + "detectionMethod": "threshold", + "query": { + "left": "avgPageLoad", + "right": 1.0, + "operator": ">=" + }, + "createdAt": 1592849011350, + "options": { + "message": [ + { + "type": "slack", + "value": "51" + } + ], + "LastNotification": 1599135058000, + "renotifyInterval": 10 + } + } +] + +const notifications = List([ + { title: 'test', type: 'change', createdAt: 1591893324078, description: 'Lorem ipusm'}, + { title: 'test', type: 'threshold', createdAt: 1591893324078, description: 'Lorem ipusm'}, + { title: 'test', type: 'threshold', createdAt: 1591893324078, description: 'Lorem ipusm'}, + { title: 'test', type: 'threshold', createdAt: 1591893324078, description: 'Lorem ipusm'}, +]) +storiesOf('Alerts', module) + .add('Alerts', () => ( + + )) + .add('List', () => ( + + )) + .add('AlertForm', () => ( + + )) + .add('AlertNotifications', () => ( + + )) diff --git a/frontend/app/components/Alerts/index.js b/frontend/app/components/Alerts/index.js new file mode 100644 index 000000000..4f6a6f772 --- /dev/null +++ b/frontend/app/components/Alerts/index.js @@ -0,0 +1 @@ +export { default } from './Alerts' \ No newline at end of file diff --git a/frontend/app/components/Announcements/Announcements.js b/frontend/app/components/Announcements/Announcements.js new file mode 100644 index 000000000..6da12b118 --- /dev/null +++ b/frontend/app/components/Announcements/Announcements.js @@ -0,0 +1,105 @@ +import React from 'react'; +import stl from './announcements.css'; +import ListItem from './ListItem'; +import { connect } from 'react-redux'; +import { SlideModal, Icon, NoContent, Popup } from 'UI'; +import { fetchList, setLastRead } from 'Duck/announcements'; +import withToggle from 'Components/hocs/withToggle'; +import { withRouter } from 'react-router-dom'; + +@withToggle('visible', 'toggleVisisble') +@withRouter +class Announcements extends React.Component { + constructor(props) { + super(props); + props.fetchList(); + } + + navigateToUrl = url => { + if (url) { + if (url.startsWith(window.ENV.ORIGIN)) { + const { history } = this.props; + var path = new URL(url).pathname + if (path.includes('/metrics')) { + const { siteId, sites } = this.props; + const activeSite = sites.find(s => s.id == siteId); + history.push(`/${activeSite.id + path}`); + } else { + history.push(path) + } + } else { + window.open(url, "_blank") + } + this.toggleModal() + } + } + + toggleModal = () => { + if (!this.props.visible) { + const { setLastRead, fetchList } = this.props; + fetchList().then(() => { setTimeout(() => { setLastRead() }, 5000); }); + } + this.props.toggleVisisble(!this.props.visible); + } + + render() { + const { announcements, visible, loading } = this.props; + const unReadNotificationsCount = announcements.filter(({viewed}) => !viewed).size + + return ( +
+ +
+ { unReadNotificationsCount } +
+ +
+ } + content={ `Announcements` } + size="tiny" + inverted + position="top center" + /> + + + + { + announcements.map(item => ( + + )) + } + + + } + /> + + ); + } +} + +export default connect(state => ({ + announcements: state.getIn(['announcements', 'list']), + loading: state.getIn(['announcements', 'fetchList', 'loading']), + siteId: state.getIn([ 'user', 'siteId' ]), + sites: state.getIn([ 'site', 'list' ]), +}), { fetchList, setLastRead })(Announcements); \ No newline at end of file diff --git a/frontend/app/components/Announcements/ListItem/ListItem.js b/frontend/app/components/Announcements/ListItem/ListItem.js new file mode 100644 index 000000000..1c28cd135 --- /dev/null +++ b/frontend/app/components/Announcements/ListItem/ListItem.js @@ -0,0 +1,31 @@ +import React from 'react'; +import { Button, Label } from 'UI'; +import stl from './listItem.css'; + +const ListItem = ({ announcement, onButtonClick }) => { + return ( +
+
+
{announcement.createdAt && announcement.createdAt.toFormat('LLL dd, yyyy')}
+ +
+ {announcement.imageUrl && + + } +
+

{announcement.title}

+
{announcement.description}
+ {announcement.buttonUrl && + + } +
+
+ ) +} + +export default ListItem diff --git a/frontend/app/components/Announcements/ListItem/index.js b/frontend/app/components/Announcements/ListItem/index.js new file mode 100644 index 000000000..741aed270 --- /dev/null +++ b/frontend/app/components/Announcements/ListItem/index.js @@ -0,0 +1 @@ +export { default } from './ListItem'; diff --git a/frontend/app/components/Announcements/ListItem/listItem.css b/frontend/app/components/Announcements/ListItem/listItem.css new file mode 100644 index 000000000..5bc3a44c8 --- /dev/null +++ b/frontend/app/components/Announcements/ListItem/listItem.css @@ -0,0 +1,5 @@ +.wrapper { + background-color: white; + margin-bottom: 20px; + padding: 15px; +} \ No newline at end of file diff --git a/frontend/app/components/Announcements/announcements.css b/frontend/app/components/Announcements/announcements.css new file mode 100644 index 000000000..58cc5d0ec --- /dev/null +++ b/frontend/app/components/Announcements/announcements.css @@ -0,0 +1,39 @@ +.wrapper { + position: relative; +} + +.button { + position: relative; + cursor: pointer; + display: flex; + align-items: center; + padding: 0 15px; + height: 50px; + transition: all 0.3s; + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + + &[data-active=true] { + background-color: $gray-lightest; + } +} + +.counter { + position: absolute; + top: 8px; + left: 24px; + background-color: red; + color: white; + font-size: 9px; + font-weight: 300; + min-width: 16px; + height: 16px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + padding: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/Announcements/index.js b/frontend/app/components/Announcements/index.js new file mode 100644 index 000000000..faeffcfcd --- /dev/null +++ b/frontend/app/components/Announcements/index.js @@ -0,0 +1 @@ +export { default } from './Announcements'; \ No newline at end of file diff --git a/frontend/app/components/BugFinder/AlertManager/AlertForm.js b/frontend/app/components/BugFinder/AlertManager/AlertForm.js new file mode 100644 index 000000000..26da182ab --- /dev/null +++ b/frontend/app/components/BugFinder/AlertManager/AlertForm.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { Input, Dropdown, Button } from 'UI'; +import styles from './alertForm.css'; + +const periodOptions = [ + { + text: '1 Week', + value: 'week', + }, + { + text: '1 Month', + value: 'month', + }, +]; + +const AlertForm = ({ + alert, write, onSave, loading, onCancel = null, +}) => ( +
+
+

{'Title'}

+ +
+ +
+

{'Threshold'}

+ +
+ +
+

{'For Next'}

+ +
+ +
+); + +export default AlertForm; diff --git a/frontend/app/components/BugFinder/AlertManager/AlertManager.js b/frontend/app/components/BugFinder/AlertManager/AlertManager.js new file mode 100644 index 000000000..207405e32 --- /dev/null +++ b/frontend/app/components/BugFinder/AlertManager/AlertManager.js @@ -0,0 +1,57 @@ +import { connect } from 'react-redux'; +import { Icon, SlideModal } from 'UI'; +import withToggle from 'HOCs/withToggle'; +import { save, edit } from 'Duck/alerts'; + +import styles from './alertManager.css'; +import AlertForm from './AlertForm'; + +@connect(state => ({ + alert: state.getIn([ 'alerts', 'instance' ]), + loading: state.getIn([ 'alerts', 'saveRequest', 'loading' ]), + filter: state.getIn([ 'filters', 'appliedFilter' ]), +}), { + save, + edit, +}) +@withToggle('isModalDisplayed', 'toggleModal') +export default class AlertManager extends React.PureComponent { + write = (e, { name, value }) => { + this.props.edit({ [ name ]: value }); + } + + save = () => { + const { toggleModal, alert, filter } = this.props; + this.props.save(alert.set('filter', filter)) + .then(toggleModal); + } + + render() { + const { + isModalDisplayed, alert, toggleModal, loading, + } = this.props; + return ( + +
+ +
+ + + + } + /> +
+ ); + } +} diff --git a/frontend/app/components/BugFinder/AlertManager/alertForm.css b/frontend/app/components/BugFinder/AlertManager/alertForm.css new file mode 100644 index 000000000..2f2210a3a --- /dev/null +++ b/frontend/app/components/BugFinder/AlertManager/alertForm.css @@ -0,0 +1,9 @@ +.formGroup { + margin-bottom: 15px; + + & .label { + font-size: 14px; + margin: 0; + margin-bottom: 5px; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/AlertManager/alertManager.css b/frontend/app/components/BugFinder/AlertManager/alertManager.css new file mode 100644 index 000000000..776db10b8 --- /dev/null +++ b/frontend/app/components/BugFinder/AlertManager/alertManager.css @@ -0,0 +1,20 @@ +.wrapper { + padding: 20px; +} + +.button { + padding: 5px 10px; + cursor: pointer; + display: flex; + align-items: center; +} + +.formGroup { + margin-bottom: 15px; + + & .label { + font-size: 14px; + margin: 0; + margin-bottom: 5px; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/AlertManager/index.js b/frontend/app/components/BugFinder/AlertManager/index.js new file mode 100644 index 000000000..93e26da4c --- /dev/null +++ b/frontend/app/components/BugFinder/AlertManager/index.js @@ -0,0 +1 @@ +export { default } from './AlertManager'; diff --git a/frontend/app/components/BugFinder/Attributes/ActiveLabel.js b/frontend/app/components/BugFinder/Attributes/ActiveLabel.js new file mode 100644 index 000000000..eeed1ea4c --- /dev/null +++ b/frontend/app/components/BugFinder/Attributes/ActiveLabel.js @@ -0,0 +1,10 @@ +import React from 'react'; +import stl from './activeLabel.css'; + +const ActiveLabel = ({ item, onRemove }) => { + return ( +
onRemove(item) }>{ item.text }
+ ); +}; + +export default ActiveLabel; diff --git a/frontend/app/components/BugFinder/Attributes/AttributeItem.js b/frontend/app/components/BugFinder/Attributes/AttributeItem.js new file mode 100644 index 000000000..bc4e45d41 --- /dev/null +++ b/frontend/app/components/BugFinder/Attributes/AttributeItem.js @@ -0,0 +1,92 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { operatorOptions } from 'Types/filter'; +import { Icon } from 'UI'; +import { editAttribute, removeAttribute, applyFilter, fetchFilterOptions } from 'Duck/filters'; +import { debounce } from 'App/utils'; +import { KEYS } from 'Types/filter/customFilter'; +import stl from './attributeItem.css' +import AttributeValueField from './AttributeValueField'; +import OperatorDropdown from './OperatorDropdown'; +import CustomFilters from '../CustomFilters'; +import FilterSelectionButton from '../FilterSelectionButton'; + +const DEFAULT = null; + +@connect(state => ({ + loadingFilterOptions: state.getIn([ 'filters', 'fetchFilterOptions', 'loading' ]), + filterOptions: state.getIn([ 'filters', 'filterOptions' ]), +}), { + editAttribute, + removeAttribute, + applyFilter, + fetchFilterOptions +}) + +class AttributeItem extends React.PureComponent { + applyFilter = debounce(this.props.applyFilter, 1000) + fetchFilterOptionsDebounce = debounce(this.props.fetchFilterOptions, 500) + + onFilterChange = (e, { name, value }) => { + const { index } = this.props; + this.props.editAttribute(index, name, value); + this.applyFilter(); + } + + removeFilter = () => { + const { index } = this.props; + this.props.removeAttribute(index) + this.applyFilter(); + } + + handleSearchChange = (e, { searchQuery }) => { + const { filter } = this.props; + this.fetchFilterOptionsDebounce(filter, searchQuery); + } + + render() { + const { filter, options, index, loadingFilterOptions, filterOptions } = this.props; + const _operatorOptions = operatorOptions(filter); + + let filterLabel = filter.label; + if (filter.type === KEYS.METADATA) + filterLabel = filter.key; + + return ( +
+ } + showFilters={ true } + filterType="filter" + /> + { filter.type !== KEYS.DURATION && + + } + { + !filter.hasNoValue && + + } + +
+ +
+
+ ); + } +} + +export default AttributeItem; diff --git a/frontend/app/components/BugFinder/Attributes/AttributeValueField.js b/frontend/app/components/BugFinder/Attributes/AttributeValueField.js new file mode 100644 index 000000000..440eadec0 --- /dev/null +++ b/frontend/app/components/BugFinder/Attributes/AttributeValueField.js @@ -0,0 +1,172 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import cn from 'classnames'; +import stl from './attributeItem.css' +import { Dropdown } from 'semantic-ui-react'; +import { LinkStyledInput, CircularLoader } from 'UI'; +import { KEYS } from 'Types/filter/customFilter'; +import Event, { TYPES } from 'Types/filter/event'; +import CustomFilter from 'Types/filter/customFilter'; +import { setActiveKey, addCustomFilter, removeCustomFilter, applyFilter } from 'Duck/filters'; +import DurationFilter from '../DurationFilter/DurationFilter'; +import AutoComplete from '../AutoComplete'; + +const DEFAULT = null; + +const getHeader = (type) => { + if (type === 'LOCATION') return 'Path'; + + return type; +} + +@connect(null, { + setActiveKey, + addCustomFilter, + removeCustomFilter, + applyFilter, +}) +class AttributeValueField extends React.PureComponent { + state = { + minDuration: this.props.filter.minDuration, + maxDuration: this.props.filter.maxDuration, + } + + onValueChange = (e, { name: key, value }) => { + this.props.addCustomFilter(key, value); + }; + + onDurationChange = (durationValues) => { + this.setState(durationValues); + } + + isAutoComplete = (type) => { + switch (type) { + case TYPES.METADATA: + case TYPES.CLICK: + case TYPES.CONSOLE: + case TYPES.GRAPHQL: + case TYPES.FETCH: + case TYPES.STATEACTION: + case TYPES.USERID: + case TYPES.USERANONYMOUSID: + case TYPES.REVID: + case TYPES.GRAPHQL: + case TYPES.CUSTOM: + case TYPES.LOCATION: + case TYPES.VIEW: + case TYPES.INPUT: + case 'metadata': + return true; + } + + return false; + } + + handleClose = (e) => { + const { filter, onChange } = this.props; + if (filter.key === KEYS.DURATION) { + const { maxDuration, minDuration, key } = filter; + if (maxDuration || minDuration) return; + if (maxDuration !== this.state.maxDuration || + minDuration !== this.state.minDuration) { + onChange(e, { name: 'value', value: [this.state.minDuration, this.state.maxDuration] }); + } + } + } + + renderField() { + const { filter, onChange } = this.props; + + if (filter.key === KEYS.DURATION) { + const { maxDuration, minDuration } = this.state; + return ( + + ); + } + + const { options = [], handleSearchChange, loading } = this.props; + return ( + 0 || options.size > 0} + onChange={ onChange } + onSearchChange={handleSearchChange} + icon={ null } + noResultsMessage={loading ?
+ +
: 'No results found.'} + /> + ) + } + + optionMapping = (values) => { + const { filter } = this.props; + if ([KEYS.USER_DEVICE, KEYS.USER_OS, KEYS.USER_BROWSER, KEYS.REFERRER, KEYS.PLATFORM].indexOf(filter.type) !== -1) { + return values.map(item => ({ type: TYPES.METADATA, value: item })).map(CustomFilter); + } else { + return values.map(Event); + } + } + + getParams = filter => { + const params = {}; + + if (filter.type === TYPES.METADATA) { + params.key = filter.key + } + + params.type = filter.type + if (filter.type === TYPES.ERROR && filter.source) { + params.source = filter.source + } + return params; + } + + render() { + const { filter, onChange, onTargetChange } = this.props; + const _showAutoComplete = this.isAutoComplete(filter.type); + const _params = _showAutoComplete ? this.getParams(filter) : {}; + let _optionsEndpoint= '/events/search'; + + return ( + + { _showAutoComplete ? + { getHeader(filter.type) } } + fullWidth={ (filter.type === TYPES.CONSOLE || filter.type === TYPES.LOCATION || filter.type === TYPES.CUSTOM) && filter.value } + /> + : this.renderField() + } + { filter.type === 'INPUT' && + + } + + ); + } +} + +export default AttributeValueField; diff --git a/frontend/app/components/BugFinder/Attributes/Attributes.js b/frontend/app/components/BugFinder/Attributes/Attributes.js new file mode 100644 index 000000000..060731969 --- /dev/null +++ b/frontend/app/components/BugFinder/Attributes/Attributes.js @@ -0,0 +1,71 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { countries } from 'App/constants'; +import { KEYS } from 'Types/filter/customFilter'; +import { addAttribute } from 'Duck/filters'; +import AttributeItem from './AttributeItem'; +import ListHeader from '../ListHeader'; +import logger from 'App/logger'; + +const DEFAULT = null; +const DEFAULT_OPTION = { text: 'Any', value: DEFAULT }; +const toOptions = (values, mapper) => (values ? values + .map(({value}) => ({ + text: mapper ? mapper[ value ] : value, + value, + })) + .toJS() : [ DEFAULT_OPTION ]); + +const countryOptions = Object.keys(countries).map(i => ({ text: countries[i], value: i })); + +@connect(state => ({ + filters: state.getIn([ 'filters', 'appliedFilter', 'filters' ]), + filterValues: state.get('filterValues'), + filterOptions: state.getIn([ 'filters', 'filterOptions' ]), +}), { + addAttribute, +}) +class Attributes extends React.PureComponent { + getOptions = filter => { + const { filterValues, filterOptions } = this.props; + + if (filter.key === KEYS.USER_COUNTRY) { + logger.log('Filters: country') + return countryOptions; + } + + if (filter.key === KEYS.METADATA) { + logger.log('Filters: metadata ' + filter.key) + const options = filterValues.get(filter.key); + return options && options.size ? toOptions(options) : []; + } + + logger.log('Filters: general filters ' + filter.key) + const options = filterOptions.get(filter.key) + return options && options.size ? toOptions(options.filter(i => !!i)) : [] + } + render() { + const { filters } = this.props; + return ( + <> + { filters.size > 0 && +
+
+ { + filters.map((filter, index) => ( + + )) + } +
+ } + + ); + } +} + +export default Attributes; diff --git a/frontend/app/components/BugFinder/Attributes/OperatorDropdown.js b/frontend/app/components/BugFinder/Attributes/OperatorDropdown.js new file mode 100644 index 000000000..4d2ba0d54 --- /dev/null +++ b/frontend/app/components/BugFinder/Attributes/OperatorDropdown.js @@ -0,0 +1,19 @@ +import React from 'react'; +import cn from 'classnames'; +import { Dropdown, Icon } from 'UI'; +import stl from './attributeItem.css' + +const OperatorDropdown = ({ options, value, onChange }) => { + return ( + } + /> + ); +}; + +export default OperatorDropdown; diff --git a/frontend/app/components/BugFinder/Attributes/activeLabel.css b/frontend/app/components/BugFinder/Attributes/activeLabel.css new file mode 100644 index 000000000..283fed288 --- /dev/null +++ b/frontend/app/components/BugFinder/Attributes/activeLabel.css @@ -0,0 +1,9 @@ +.wrapper { + padding: 3px 8px; + background-color: $gray-lightest; + border-radius: 10px; + margin-right: 5px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05) inset; + font-size: 13px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/Attributes/attributeItem.css b/frontend/app/components/BugFinder/Attributes/attributeItem.css new file mode 100644 index 000000000..72c908bd9 --- /dev/null +++ b/frontend/app/components/BugFinder/Attributes/attributeItem.css @@ -0,0 +1,130 @@ +@import 'icons.css'; + +.wrapper { + display: flex; + align-items: center; + padding: 8px 15px; + background-color: white; + border-bottom: solid thin $gray-lightest; + &:last-child { + border-bottom: solid thin transparent; + } + + &:hover { + background-color: $active-blue; + & .actions { + opacity: 1; + transition: all 0.2s; + } + } + + & > div:not(:last-child) { + margin-right: 10px; + } + + & .label { + font-weight: 600; + min-width: 80px; + } + + & .filterDropdown { + /* height: 28px !important; */ + padding: 0 5px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + font-weight: 400; + min-width: 280px !important; + max-width: 75% !important; + flex-wrap: wrap; + padding: 1.9px !important; + background-color: rgba(255, 255, 255, 0.8) !important; + padding-left: 5px !important; + + & a { + background-color: $gray-lightest !important; + box-shadow: none !important; + border-radius: 10px !important; + white-space: nowrap !important; + margin: 0 !important; + margin-right: 5px !important; + margin-bottom: 2px !important; + font-size: 13px !important; + font-weight: 400; + display: flex !important; + align-items: center !important; + padding: 3px 5px !important; + + & i::before { + display: none; + } + & i::after { + content: '' !important; + @mixin icon close, $gray-dark, 12px; + } + } + + & input { + padding: 6px !important; + margin: 0 !important; + color: $gray-medium !important; + } + + & .delete.icon { + padding: 0 !important; + display: none; + } + } +} + +.operatorDropdown { + font-weight: 400; + height: 28px; + min-width: 60px; + display: flex !important; + align-items: center; + justify-content: space-between; + padding: 0 8px !important; + font-size: 13px; + background-color: rgba(255, 255, 255, 0.8) !important; + border: solid thin rgba(34, 36, 38, 0.15) !important; + border-radius: 4px !important; + color: $gray-darkest !important; + font-size: 14px !important; + &.ui.basic.button { + box-shadow: 0 0 0 1px rgba(62, 170, 175,36,38,.35) inset, 0 0 0 0 rgba(62, 170, 175,.15) inset !important; + } +} + +.button { + width: 25px; + height: 25px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + margin-left: 10px; +} + +.actions { + margin-left: auto; + opacity: 0; + transition: all 0.4s; +} + +.inputValue { + height: 28px !important; + width: 180px; + color: $gray-medium !important; +} + +.header { + margin-bottom: 10px; + font-size: 13px; + color: #596764; + white-space: nowrap; + text-transform: uppercase; + font-weight: normal; + letter-spacing: 0.1em; + text-align: left; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/Attributes/index.js b/frontend/app/components/BugFinder/Attributes/index.js new file mode 100644 index 000000000..023362198 --- /dev/null +++ b/frontend/app/components/BugFinder/Attributes/index.js @@ -0,0 +1 @@ +export { default } from './Attributes'; diff --git a/frontend/app/components/BugFinder/AutoComplete/AutoComplete.js b/frontend/app/components/BugFinder/AutoComplete/AutoComplete.js new file mode 100644 index 000000000..7c22584a9 --- /dev/null +++ b/frontend/app/components/BugFinder/AutoComplete/AutoComplete.js @@ -0,0 +1,168 @@ +import React from 'react'; +import APIClient from 'App/api_client'; +import cn from 'classnames'; +import { Input } from 'UI'; +import { debounce } from 'App/utils'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import stl from './autoComplete.css'; +import FilterItem from '../CustomFilters/FilterItem'; + +const TYPE_TO_SEARCH_MSG = "Start typing to search..."; +const NO_RESULTS_MSG = "No results found."; +const SOME_ERROR_MSG = "Some error occured."; +const defaultValueToText = value => value; +const defaultOptionMapping = (values, valueToText) => values.map(value => ({ text: valueToText(value), value })); + +const hiddenStyle = { + whiteSpace: 'pre-wrap', + opacity: 0, position: 'fixed', left: '-3000px' +}; + +let pasted = false; +let changed = false; + +class AutoComplete extends React.PureComponent { + static defaultProps = { + method: 'GET', + params: {}, + } + + state = { + values: [], + noResultsMessage: TYPE_TO_SEARCH_MSG, + ddOpen: false, + query: this.props.value, + loading: false, + error: false + } + + componentWillReceiveProps(newProps) { + if (this.props.value !== newProps.value) { + this.setState({ query: newProps.value}); + } + } + + onClickOutside = () => { + this.setState({ ddOpen: false }); + } + + requestValues = (q) => { + const { params, endpoint, method } = this.props; + this.setState({ + loading: true, + error: false, + }); + return new APIClient()[ method.toLowerCase() ](endpoint, { ...params, q }) + .then(response => response.json()) + .then(({ errors, data }) => { + if (errors) { + this.setError(); + } else { + this.setState({ + ddOpen: true, + values: data, + loading: false, + noResultsMessage: NO_RESULTS_MSG, + }); + } + }) + .catch(this.setError); + } + + debouncedRequestValues = debounce(this.requestValues, 1000) + + setError = () => this.setState({ + loading: false, + error: true, + noResultsMessage: SOME_ERROR_MSG, + }) + + + onInputChange = (e, { name, value }) => { + changed = true; + this.setState({ query: value, updated: true }) + const _value = value.trim(); + if (_value !== '' && _value !== ' ') { + this.debouncedRequestValues(_value) + } + } + + onBlur = ({ target: { value } }) => { + // to avoid sending unnecessary request on focus in/out without changing + if (!changed && !pasted) return; + + value = pasted ? this.hiddenInput.value : value; + const { onSelect, name } = this.props; + if (value !== this.props.value) { + const _value = value.trim(); + onSelect(null, {name, value: _value}); + } + + changed = false; + pasted = false; + } + + onItemClick = (e, item) => { + e.stopPropagation(); + e.preventDefault(); + const { onSelect, name } = this.props; + + this.setState({ query: item.value, ddOpen: false}) + onSelect(e, {name, ...item.toJS()}); + } + + render() { + const { ddOpen, query, loading, values } = this.state; + const { + optionMapping = defaultOptionMapping, + valueToText = defaultValueToText, + placeholder = 'Type to search...', + headerText = '', + fullWidth = false + } = this.props; + + const options = optionMapping(values, valueToText) + + return ( + + this.setState({ddOpen: true})} + value={ query } + icon="search" + loading={ loading } + autoFocus={ true } + type="search" + placeholder={ placeholder } + onPaste={(e) => { + const text = e.clipboardData.getData('Text'); + this.hiddenInput.value = text; + pasted = true; // to use only the hidden input + } } + /> + + { ddOpen && options.length > 0 && +
+ { headerText && headerText } + { + options.map(item => ( + this.onItemClick(e, item) } + /> + )) + } +
+ } +
+ ); + } +} + +export default AutoComplete; diff --git a/frontend/app/components/BugFinder/AutoComplete/DropdownItem.js b/frontend/app/components/BugFinder/AutoComplete/DropdownItem.js new file mode 100644 index 000000000..a8275a14d --- /dev/null +++ b/frontend/app/components/BugFinder/AutoComplete/DropdownItem.js @@ -0,0 +1,10 @@ +import React from 'react'; +import stl from './dropdownItem.css'; + +const DropdownItem = ({ value, onSelect }) => { + return ( +
{ value }
+ ); +}; + +export default DropdownItem; diff --git a/frontend/app/components/BugFinder/AutoComplete/autoComplete.css b/frontend/app/components/BugFinder/AutoComplete/autoComplete.css new file mode 100644 index 000000000..79439f51c --- /dev/null +++ b/frontend/app/components/BugFinder/AutoComplete/autoComplete.css @@ -0,0 +1,30 @@ +.menu { + border-radius: 0 0 3px 3px; + box-shadow: 0 2px 10px 0 $gray-light; + padding: 20px; + background-color: white; + max-height: 350px; + overflow-y: auto; + position: absolute; + top: 28px; + left: 0; + width: 500px; + z-index: 99; +} + +.searchInput { + & input { + font-size: 13px !important; + padding: 5px !important; + color: $gray-darkest !important; + font-size: 14px !important; + background-color: rgba(255, 255, 255, 0.8) !important; + } + height: 28px !important; + width: 280px; + color: $gray-darkest !important; +} + +.fullWidth { + width: 100% !important; +} diff --git a/frontend/app/components/BugFinder/AutoComplete/dropdownItem.css b/frontend/app/components/BugFinder/AutoComplete/dropdownItem.css new file mode 100644 index 000000000..f5646a470 --- /dev/null +++ b/frontend/app/components/BugFinder/AutoComplete/dropdownItem.css @@ -0,0 +1,11 @@ +.wrapper { + padding: 8px; + border-bottom: solid thin rgba(0, 0, 0, 0.05); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + &:hover { + background-color: $active-blue; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/AutoComplete/index.js b/frontend/app/components/BugFinder/AutoComplete/index.js new file mode 100644 index 000000000..fa63241a4 --- /dev/null +++ b/frontend/app/components/BugFinder/AutoComplete/index.js @@ -0,0 +1 @@ +export { default } from './AutoComplete'; \ No newline at end of file diff --git a/frontend/app/components/BugFinder/BugFinder.js b/frontend/app/components/BugFinder/BugFinder.js new file mode 100644 index 000000000..b9b784ab6 --- /dev/null +++ b/frontend/app/components/BugFinder/BugFinder.js @@ -0,0 +1,175 @@ +import cn from 'classnames'; +import { connect } from 'react-redux'; +import withPageTitle from 'HOCs/withPageTitle'; +import { + fetchFavoriteList as fetchFavoriteSessionList +} from 'Duck/sessions'; +import { countries } from 'App/constants'; +import { applyFilter, clearEvents } from 'Duck/filters'; +import { fetchList as fetchFunnelsList } from 'Duck/funnels'; +import { defaultFilters, preloadedFilters } from 'Types/filter'; +import { KEYS } from 'Types/filter/customFilter'; +import EventFilter from './EventFilter'; +import SessionList from './SessionList'; +import FunnelList from 'Components/Funnels/FunnelList'; +import stl from './bugFinder.css'; +import { fetchList as fetchSiteList } from 'Duck/site'; +import withLocationHandlers from "HOCs/withLocationHandlers"; +import { fetch as fetchFilterVariables } from 'Duck/sources'; +import { fetchList as fetchIntegrationVariables, fetchSources } from 'Duck/customField'; +import { RehydrateSlidePanel } from './WatchDogs/components'; +import { setActiveTab } from 'Duck/sessions'; +import SessionsMenu from './SessionsMenu/SessionsMenu'; +import SessionFlowList from './SessionFlowList/SessionFlowList'; +import { LAST_7_DAYS } from 'Types/app/period'; +import { resetFunnel } from 'Duck/funnels'; +import { resetFunnelFilters } from 'Duck/funnelFilters' +import NoSessionsMessage from '../shared/NoSessionsMessage'; + +const AUTOREFRESH_INTERVAL = 10 * 60 * 1000; + +const weakEqual = (val1, val2) => { + if (!!val1 === false && !!val2 === false) return true; + if (!val1 !== !val2) return false; + return `${ val1 }` === `${ val2 }`; +} + +@withLocationHandlers() +@connect(state => ({ + shouldAutorefresh: state.getIn([ 'filters', 'appliedFilter', 'events' ]).size === 0, + filter: state.getIn([ 'filters', 'appliedFilter' ]), + showLive: state.getIn([ 'user', 'account', 'appearance', 'sessionsLive' ]), + variables: state.getIn([ 'customFields', 'list' ]), + sources: state.getIn([ 'customFields', 'sources' ]), + filterValues: state.get('filterValues'), + activeTab: state.getIn([ 'sessions', 'activeTab' ]), + favoriteList: state.getIn([ 'sessions', 'favoriteList' ]), + currentProjectId: state.getIn([ 'user', 'siteId' ]), + sites: state.getIn([ 'site', 'list' ]), + watchdogs: state.getIn(['watchdogs', 'list']), + activeFlow: state.getIn([ 'filters', 'activeFlow' ]), +}), { + fetchFavoriteSessionList, + applyFilter, + fetchFilterVariables, + fetchIntegrationVariables, + fetchSources, + clearEvents, + setActiveTab, + fetchSiteList, + fetchFunnelsList, + resetFunnel, + resetFunnelFilters +}) +@withPageTitle("Sessions - OpenReplay") +export default class BugFinder extends React.PureComponent { + state = {showRehydratePanel: false} + constructor(props) { + super(props); + // props.fetchFavoriteSessionList(); + // TODO should cache the response + props.fetchSources().then(() => { + defaultFilters[6] = { + category: 'Collaboration', + type: 'CUSTOM', + keys: this.props.sources.filter(({type}) => type === 'collaborationTool').map(({ label, key }) => ({ type: 'CUSTOM', source: key, label: label, key, icon: 'integrations/' + key, isFilter: false })).toJS() + }; + defaultFilters[7] = { + category: 'Logging Tools', + type: 'ERROR', + keys: this.props.sources.filter(({type}) => type === 'logTool').map(({ label, key }) => ({ type: 'ERROR', source: key, label: label, key, icon: 'integrations/' + key, isFilter: false })).toJS() + }; + }); + // TODO should cache the response + props.fetchIntegrationVariables().then(() => { + defaultFilters[5] = { + category: 'Metadata', + type: 'custom', + keys: this.props.variables.map(({ key }) => ({ type: 'METADATA', key, label: key, icon: 'filters/metadata', isFilter: true })).toJS() + }; + }); + + this.props.resetFunnel(); + this.props.resetFunnelFilters(); + + this.autorefreshIntervalId = setInterval(() => { + if (this.props.shouldAutorefresh) { + props.applyFilter(); + } + }, AUTOREFRESH_INTERVAL); + + props.fetchFunnelsList(LAST_7_DAYS) + } + + toggleRehydratePanel = () => { + this.setState({ showRehydratePanel: !this.state.showRehydratePanel }) + } + + fetchPreloadedFilters = () => { + this.props.fetchFilterVariables('filterValues').then(function() { + const { filterValues } = this.props; + const keys = [ + {key: KEYS.USER_OS, label: 'OS'}, + {key: KEYS.USER_BROWSER, label: 'Browser'}, + {key: KEYS.USER_DEVICE, label: 'Device'}, + {key: KEYS.REFERRER, label: 'Referrer'}, + {key: KEYS.USER_COUNTRY, label: 'Country'}, + ] + if (filterValues && filterValues.size != 0) { + keys.forEach(({key, label}) => { + const _keyFilters = filterValues.get(key) + if (key === KEYS.USER_COUNTRY) { + preloadedFilters.push(_keyFilters.map(item => ({label, type: key, key, value: item, actualValue: countries[item], isFilter: true}))); + } else { + preloadedFilters.push(_keyFilters.map(item => ({label, type: key, key, value: item, isFilter: true}))); + } + }) + } + }.bind(this)); + } + + componentWillUnmount() { + clearInterval(this.autorefreshIntervalId); + } + + setActiveTab = tab => { + this.props.setActiveTab(tab); + + } + + render() { + const { activeFlow, activeTab } = this.props; + const { showRehydratePanel } = this.state; + + return ( +
+
+
+ +
+
+ +
+ +
+ {activeFlow && activeFlow.type === 'flows' ? + + : + + } +
+
+ this.setState({ showRehydratePanel: false })} + /> +
+ ); + } +} diff --git a/frontend/app/components/BugFinder/CustomFilters/CustomFilters.js b/frontend/app/components/BugFinder/CustomFilters/CustomFilters.js new file mode 100644 index 000000000..5add05ef4 --- /dev/null +++ b/frontend/app/components/BugFinder/CustomFilters/CustomFilters.js @@ -0,0 +1,28 @@ +import React, { useCallback, useState } from 'react'; +import { connect } from 'react-redux'; +import { addEvent, applyFilter, setActiveKey, addAttribute } from 'Duck/filters'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import FilterModal from './FilterModal'; + +export default React.memo(function CustomFilters({ + index, + buttonComponent, + filterType, +}) { + const [ displayed, setDisplayed ] = useState(false); + const close = useCallback(() => setDisplayed(false), []); + const toggle = useCallback(() => setDisplayed(d => !d), []); + + return ( + +
{ buttonComponent || 'Add Step' }
+ + +
+ ); +}) \ No newline at end of file diff --git a/frontend/app/components/BugFinder/CustomFilters/FilterItem.js b/frontend/app/components/BugFinder/CustomFilters/FilterItem.js new file mode 100644 index 000000000..e929a53c4 --- /dev/null +++ b/frontend/app/components/BugFinder/CustomFilters/FilterItem.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { Icon } from 'UI'; +import stl from './filterItem.css'; +import cn from 'classnames'; + +const FilterItem = ({ className = '', icon, label, onClick }) => { + return ( +
+ + { label } +
+ ); +}; + +export default FilterItem; diff --git a/frontend/app/components/BugFinder/CustomFilters/FilterModal.js b/frontend/app/components/BugFinder/CustomFilters/FilterModal.js new file mode 100644 index 000000000..74902cf31 --- /dev/null +++ b/frontend/app/components/BugFinder/CustomFilters/FilterModal.js @@ -0,0 +1,213 @@ +import React from 'react'; +import cn from 'classnames'; +import { List } from 'immutable'; +import { connect } from 'react-redux'; +import { getRE } from 'App/utils'; +import { defaultFilters, preloadedFilters } from 'Types/filter'; +import { TYPES } from 'Types/filter/event'; +import CustomFilter, { KEYS } from 'Types/filter/customFilter'; +import { applyFilter, setActiveKey, addEvent, removeEvent, setFilterOption, changeEvent, addAttribute, removeAttribute } from 'Duck/filters'; +import { NoContent, CircularLoader } from 'UI'; +import { debounce } from 'App/utils'; +import FilterItem from './FilterItem'; +import logger from 'App/logger'; + +import stl from './filterModal.css'; + +const customFilterAutoCompleteKeys = ['METADATA', KEYS.CLICK, KEYS.USER_BROWSER, KEYS.USER_OS, KEYS.USER_DEVICE, KEYS.REFERRER] + +@connect(state => ({ + filter: state.getIn([ 'filters', 'appliedFilter' ]), + customFilters: state.getIn([ 'filters', 'customFilters' ]), + variables: state.getIn([ 'customFields', 'list' ]), + sources: state.getIn([ 'customFields', 'sources' ]), +}), { + applyFilter, + setActiveKey, + addEvent, + removeEvent, + addAttribute, + removeAttribute, + setFilterOption +}) +export default class FilterModal extends React.PureComponent { + state = { query: '' } + applyFilter = debounce(this.props.applyFilter, 300); + + onFilterClick = (filter, apply) => { + const key = filter.key || filter.type; + if (customFilterAutoCompleteKeys.includes(key)) { + this.props.setFilterOption(key, filter.value ? [{value: filter.value[0], type: key}] : []) + } + this.addFilter(filter); + if (apply || filter.hasNoValue) { + this.applyFilter(); + } + } + + renderFilterItem(type, filter) { + return ( + this.onFilterClick(filter) } + /> + ); + } + + addFilter = (filter) => { + const { index, filterType, filter: { filters } } = this.props; + this.props.close(); + + if (filter.isFilter || filter.type === 'METADATA') { + logger.log('Adding Filter', filter) + const _index = filterType === 'filter' ? index : undefined; // should add new one if coming from events + const _in = filters.findIndex(e => e.type === 'USERID'); + this.props.addAttribute(filter, _in >= 0 ? _in : _index); + } else { + logger.log('Adding Event', filter) + const _index = filterType === 'event' ? index : undefined; // should add new one if coming from fitlers + this.props.addEvent(filter, false, _index); + } + + if (filterType === 'event' && filter.isFilter) { // selected a filter from events + this.props.removeEvent(index); + } + + if (filterType === 'filter' && !filter.isFilter) { // selected an event from filters + this.props.removeAttribute(index); + } + }; + + renderList(type, list) { + const blocks = []; + for (let j = 0; j < list.length; j++) { + blocks.push( +
+ { list[ j ] && this.renderFilterItem(type, list[ j ]) } +
+ ); + } + return blocks; + } + + test = (value = '') => getRE(this.props.searchQuery, 'i').test(value); + + renderEventDropdownItem = filter => ( + this.onFilterClick(filter, true) } + /> + ) + + renderEventDropdownPartFromList = (list, headerText) => (list.size > 0 && +
+
{ headerText }
+ { list.map(this.renderEventDropdownItem) } +
+ ) + + renderEventDropdownPart = (type, headerText) => { + const searched = this.props.searchedEvents + .filter(e => e.type === type) + .filter(({ value, target }) => !this.props.loading || this.test(value) || this.test(target && target.label)); + + return this.renderEventDropdownPartFromList(searched, headerText) + }; + + renderStaticFiltersDropdownPart = (type, headerText, appliedFilterKeys) => { + if (appliedFilterKeys && appliedFilterKeys.includes(type)) return; + const staticFilters = List(preloadedFilters) + .filter(e => e.type === type) + .filter(({ value, actualValue }) => this.test(actualValue || value)) + .map(CustomFilter); + + return this.renderEventDropdownPartFromList(staticFilters, headerText) + }; + + render() { + const { + displayed, + customFilters, + filter, + loading = false, + searchedEvents, + searchQuery = '', + } = this.props; + const { query } = this.state; + const reg = getRE(query, 'i'); + + const _appliedFilterKeys = filter.filters.map(({type}) => type).toJS(); + const filteredList = defaultFilters.map(cat => { + let _keys = []; + if (query.length === 0 && cat.type === 'custom') { // default show limited custom fields + _keys = cat.keys.slice(0, 9).filter(({key}) => reg.test(key)) + } else { + _keys = cat.keys.filter(({key}) => reg.test(key)); + } + return { + ...cat, + keys: _keys + .filter(({key, filterKey}) => !_appliedFilterKeys.includes(filterKey) && !customFilters.has(filterKey || key) && !filter.get(filterKey || key)) + } + }).filter(cat => cat.keys.length > 0); + + const staticFilters = preloadedFilters + .filter(({ value, actualValue }) => !this.props.loading && this.test(actualValue || value)) + + return (!displayed ? null : +
+ { loading && +
+ } + + +
+ { searchQuery && + + {this.renderEventDropdownPart(TYPES.USERID, 'User Id')} + {this.renderEventDropdownPart(TYPES.METADATA, 'Metadata')} + {this.renderEventDropdownPart(TYPES.CONSOLE, 'Errors')} + {this.renderEventDropdownPart(TYPES.CUSTOM, 'Custom Events')} + {this.renderEventDropdownPart(KEYS.USER_COUNTRY, 'Country', _appliedFilterKeys)} + {this.renderEventDropdownPart(KEYS.USER_BROWSER, 'Browser', _appliedFilterKeys)} + {this.renderEventDropdownPart(KEYS.USER_DEVICE, 'Device', _appliedFilterKeys)} + {this.renderEventDropdownPart(TYPES.LOCATION, 'Page')} + {this.renderEventDropdownPart(TYPES.CLICK, 'Click')} + {this.renderEventDropdownPart(TYPES.FETCH, 'Fetch')} + {this.renderEventDropdownPart(TYPES.INPUT, 'Input')} + + {this.renderEventDropdownPart(KEYS.USER_OS, 'Operating System', _appliedFilterKeys)} + {this.renderEventDropdownPart(KEYS.REFERRER, 'Referrer', _appliedFilterKeys)} + {this.renderEventDropdownPart(TYPES.GRAPHQL, 'GraphQL')} + {this.renderEventDropdownPart(TYPES.STATEACTION, 'Store Action')} + {this.renderEventDropdownPart(TYPES.REVID, 'Rev ID')} + + } +
+ { searchQuery === '' && +
+ { + filteredList.map(category => ( +
+
{ category.category }
+
+ { this.renderList(category.type, category.keys) } +
+
+ )) + } +
+ } +
+
+ ); + } +} diff --git a/frontend/app/components/BugFinder/CustomFilters/filterItem.css b/frontend/app/components/BugFinder/CustomFilters/filterItem.css new file mode 100644 index 000000000..2840f2119 --- /dev/null +++ b/frontend/app/components/BugFinder/CustomFilters/filterItem.css @@ -0,0 +1,20 @@ +.filterItem { + display: flex; + align-items: center; + padding: 8px; + cursor: pointer; + border-radius: 3px; + transition: all 0.4s; + margin-bottom: 5px; + max-width: 100%; + & .label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/CustomFilters/filterModal.css b/frontend/app/components/BugFinder/CustomFilters/filterModal.css new file mode 100644 index 000000000..526016764 --- /dev/null +++ b/frontend/app/components/BugFinder/CustomFilters/filterModal.css @@ -0,0 +1,91 @@ +.modal { + position: absolute; + left: 0; + background-color: white; + width: -webkit-fill-available; + min-width: 705px; + max-width: calc(100vw - 500px); + border-radius: 3px; + border: solid thin $gray-light; + box-shadow: 0 2px 10px 0 $gray-light; + z-index: 99; + padding: 20px; +} + +.hint { + color: $gray-light; + font-size: 12px; + padding-bottom: 5px; +} + +h5.title { + margin: 10px 0 3px; +} + +.filterListDynamic { + max-height: 350px; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 2px; + } + + &::-webkit-scrollbar-thumb { + background: transparent; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &:hover { + &::-webkit-scrollbar-track { + background: #f3f3f3; + } + &::-webkit-scrollbar-thumb { + background: $gray-medium; + } + } + + + & .header { + margin-bottom: 10px; + font-size: 13px; + color: #596764; + white-space: nowrap; + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.1em; + text-align: left; + } + + & .list { + margin-left: -8px; + } +} + +.filterListStatic { + display: flex; + flex-wrap: wrap; + flex-direction: column; + max-height: 33rem; + min-height: 20px; + color: $gray-medium; + + & .header { + margin-bottom: 10px; + font-size: 13px; + color: #596764; + white-space: nowrap; + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.1em; + text-align: left; + } + + & .list { + margin-left: -8px; + } + + & .filterGroup { + width: 205px; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/CustomFilters/index.js b/frontend/app/components/BugFinder/CustomFilters/index.js new file mode 100644 index 000000000..29dfa472a --- /dev/null +++ b/frontend/app/components/BugFinder/CustomFilters/index.js @@ -0,0 +1 @@ +export { default } from './CustomFilters'; \ No newline at end of file diff --git a/frontend/app/components/BugFinder/DateRange.js b/frontend/app/components/BugFinder/DateRange.js new file mode 100644 index 000000000..4f2ce8e22 --- /dev/null +++ b/frontend/app/components/BugFinder/DateRange.js @@ -0,0 +1,32 @@ +import { connect } from 'react-redux'; +import { applyFilter, fetchList } from 'Duck/filters'; +import { fetchList as fetchFunnelsList } from 'Duck/funnels'; +import DateRangeDropdown from 'Shared/DateRangeDropdown'; + +@connect(state => ({ + rangeValue: state.getIn([ 'filters', 'appliedFilter', 'rangeValue' ]), + startDate: state.getIn([ 'filters', 'appliedFilter', 'startDate' ]), + endDate: state.getIn([ 'filters', 'appliedFilter', 'endDate' ]), +}), { + applyFilter, fetchList, fetchFunnelsList +}) +export default class DateRange extends React.PureComponent { + onDateChange = (e) => { + this.props.fetchList(e.rangeValue) + this.props.fetchFunnelsList(e.rangeValue) + this.props.applyFilter(e) + } + render() { + const { startDate, endDate, rangeValue, className } = this.props; + return ( + + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/DurationFilter/DurationFilter.js b/frontend/app/components/BugFinder/DurationFilter/DurationFilter.js new file mode 100644 index 000000000..c69e199a8 --- /dev/null +++ b/frontend/app/components/BugFinder/DurationFilter/DurationFilter.js @@ -0,0 +1,66 @@ +import { Input, Label } from 'semantic-ui-react'; +import styles from './durationFilter.css'; + +const fromMs = value => value ? `${ value / 1000 / 60 }` : '' +const toMs = value => value !== '' ? value * 1000 * 60 : null + +export default class DurationFilter extends React.PureComponent { + state = { focused: false } + onChange = (e, { name, value }) => { + const { onChange } = this.props; + if (typeof onChange === 'function') { + onChange({ + [ name ]: toMs(value), + }); + } + } + + onKeyPress = e => { + const { onEnterPress } = this.props; + if (e.key === 'Enter' && typeof onEnterPress === 'function') { + onEnterPress(e); + } + } + + render() { + const { + minDuration, + maxDuration, + } = this.props; + + return ( +
+ this.setState({ focused: true })} + onBlur={this.props.onBlur} + > + + + + this.setState({ focused: true })} + onBlur={this.props.onBlur} + > + + + +
+ ); + } +} diff --git a/frontend/app/components/BugFinder/DurationFilter/durationFilter.css b/frontend/app/components/BugFinder/DurationFilter/durationFilter.css new file mode 100644 index 000000000..c7a272458 --- /dev/null +++ b/frontend/app/components/BugFinder/DurationFilter/durationFilter.css @@ -0,0 +1,24 @@ +.wrapper { + display: flex; + justify-content: space-between; + + & input { + max-width: 85px !important; + font-size: 13px !important; + font-weight: 400 !important; + color: $gray-medium !important; + } + + & > div { + &:first-child { + margin-right: 10px; + } + } +} + +.label { + font-size: 13px !important; + font-weight: 400 !important; + color: $gray-medium !important; +} + diff --git a/frontend/app/components/BugFinder/EventFilter/EventDropdownItem.js b/frontend/app/components/BugFinder/EventFilter/EventDropdownItem.js new file mode 100644 index 000000000..8d6d58f0a --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/EventDropdownItem.js @@ -0,0 +1,32 @@ +import { TYPES } from 'Types/filter/event'; +import cn from 'classnames'; +import { Icon } from 'UI'; +import cls from './eventDropdownItem.css'; + + +const getText = (event) => { + if (event.type === TYPES.METADATA) { + return `${ event.key }: ${ event.value }`; + } + if (event.target) { + return event.target.label || event.value; + } + return event.value; // both should be? +}; + +export default function EventDropdownItem({ event }) { + return ( +
+ +
+ { getText(event) } +
+
+ ); +} diff --git a/frontend/app/components/BugFinder/EventFilter/EventEditor.js b/frontend/app/components/BugFinder/EventFilter/EventEditor.js new file mode 100644 index 000000000..d687adb86 --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/EventEditor.js @@ -0,0 +1,109 @@ +import { connect } from 'react-redux'; +import { DNDSource, DNDTarget } from 'Components/hocs/dnd'; +import Event, { TYPES } from 'Types/filter/event'; +import { operatorOptions } from 'Types/filter'; +import { editEvent, removeEvent, clearEvents, applyFilter } from 'Duck/filters'; +import { Icon } from 'UI'; +import stl from './eventEditor.css'; +import { debounce } from 'App/utils'; +import AttributeValueField from '../Attributes/AttributeValueField'; +import OperatorDropdown from '../Attributes/OperatorDropdown'; +import CustomFilters from '../CustomFilters'; +import FilterSelectionButton from '../FilterSelectionButton'; + +const getPlaceholder = ({ type }) => { + if (type === TYPES.INPUT) return "E.g. First Name"; + if (type === TYPES.LOCATION) return "Specify URL / Path"; + if (type === TYPES.VIEW) return "Specify View Name"; + if (type === TYPES.CONSOLE) return "Specify Error Message"; + if (type === TYPES.CUSTOM) return "Specify Custom Event Name"; + return ''; +}; + +const getLabel = ({ type }) => { + if (type === TYPES.INPUT) return "Specify Value"; + return getPlaceholder({ type }); +}; + +@DNDTarget('event') +@DNDSource('event') +@connect(state => ({ + isLastEvent: state.getIn([ 'filters', 'appliedFilter', 'events' ]).size === 1, +}), { editEvent, removeEvent, clearEvents, applyFilter }) +export default class EventEditor extends React.PureComponent { + applyFilter = debounce(this.props.applyFilter, 1500) + + onChange = (e, { name, value, searchType }) => { + const { index } = this.props; + const updFields = { [name]: value }; + if (searchType != null) { + updFields.searchType = searchType; + } + this.props.editEvent(index, updFields); + this.applyFilter(); + } + + onTargetChange = (e, {target}) => { + const { index, event } = this.props; + this.props.editEvent(index, {target}); + this.applyFilter(); + } + + onCheckboxChange = ({ target: { name, checked }}) => { + this.props.editEvent(this.props.index, name, checked); + } + + remove = () => { + this.props.removeEvent(this.props.index); + this.applyFilter() + }; + + render() { + const { + event, + index, + isDragging, + connectDragSource, + connectDropTarget, + } = this.props; + + const _operatorOptions = operatorOptions(event); + + const dndBtn = connectDragSource( + + ); + + return connectDropTarget( +
+
+
{ index + 1 }
+ + } + filterType="event" + /> + + + + +
+
+ { dndBtn } + +
+
+ ); + } +} diff --git a/frontend/app/components/BugFinder/EventFilter/EventFilter.js b/frontend/app/components/BugFinder/EventFilter/EventFilter.js new file mode 100644 index 000000000..3fba3e303 --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/EventFilter.js @@ -0,0 +1,202 @@ +import { connect } from 'react-redux'; +import { Input } from 'semantic-ui-react'; +import { DNDContext } from 'Components/hocs/dnd'; +import { + addEvent, applyFilter, moveEvent, clearEvents, + addCustomFilter, addAttribute, setSearchQuery, setActiveFlow, setFilterOption +} from 'Duck/filters'; +import { fetchList as fetchEventList } from 'Duck/events'; +import { debounce } from 'App/utils'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import EventEditor from './EventEditor'; +import ListHeader from '../ListHeader'; +import FilterModal from '../CustomFilters/FilterModal'; +import { IconButton } from 'UI'; +import stl from './eventFilter.css'; +import Attributes from '../Attributes/Attributes'; +import RandomPlaceholder from './RandomPlaceholder'; +import CustomFilters from '../CustomFilters'; +import ManageFilters from '../ManageFilters'; +import { blink as setBlink } from 'Duck/funnels'; +import cn from 'classnames'; + +@connect(state => ({ + events: state.getIn([ 'filters', 'appliedFilter', 'events' ]), + appliedFilter: state.getIn([ 'filters', 'appliedFilter' ]), + searchQuery: state.getIn([ 'filters', 'searchQuery' ]), + appliedFilterKeys: state.getIn([ 'filters', 'appliedFilter', 'filters' ]) + .map(({type}) => type).toJS(), + searchedEvents: state.getIn([ 'events', 'list' ]), + loading: state.getIn([ 'events', 'loading' ]), + strict: state.getIn([ 'filters', 'appliedFilter', 'strict' ]), + blink: state.getIn([ 'funnels', 'blink' ]), +}), { + applyFilter, + addEvent, + moveEvent, + fetchEventList, + clearEvents, + addCustomFilter, + addAttribute, + setSearchQuery, + setActiveFlow, + setFilterOption, + setBlink +}) +@DNDContext +export default class EventFilter extends React.PureComponent { + state = { search: '', showFilterModal: false, showPlacehoder: true } + fetchEventList = debounce(this.props.fetchEventList, 500) + inputRef = React.createRef() + + componentDidUpdate(){ + const { blink, setBlink } = this.props; + if (blink) { + setTimeout(function() { + setBlink(false) + }, 3000) + } + } + + onBlur = () => { + const { searchQuery } = this.props; + this.setState({ showPlacehoder: searchQuery === '' }); + } + + onFocus = () => { + this.setState({ showPlacehoder: false, showFilterModal: true }); + } + + onChangeStrict = () => { + this.props.applyFilter({ strict: !this.props.strict }); + } + + onSearchChange = (e, { value }) => { + this.props.setSearchQuery(value) + if (value !== '') this.fetchEventList({ q: value }); + } + + onPlaceholderClick = () => { + this.inputRef.current && this.inputRef.current.focus(); + } + + closeModal = () => { + this.setState({ showPlacehoder: true, showFilterModal: false }) + } + + onPlaceholderItemClick = (e, filter) => { + e.stopPropagation(); + e.preventDefault(); + + if (Array.isArray(filter)) { + for (var i = 0; i < filter.length; i++) { + this.onPlaceholderItemClick(e, filter[i]); + } + } else if (filter.isFilter) { + this.props.setFilterOption(filter.key, [{ value: filter.value[0], type: filter.key }]) + this.props.addAttribute(filter); + } + else + this.props.addEvent(filter); + + if (filter.value || filter.hasNoValue) { + this.props.applyFilter(); + } + } + + clearEvents = () => { + this.props.clearEvents(); + this.props.setActiveFlow(null) + } + + render() { + const { + events, + loading, + searchedEvents, + appliedFilterKeys, + appliedFilter, + searchQuery, + blink + } = this.props; + const { showFilterModal, showPlacehoder } = this.state; + const hasFilters = appliedFilter.events.size > 0 || appliedFilter.filters.size > 0; + + return ( + + { showPlacehoder && !hasFilters && +
+ { !searchQuery && + + } +
+ } + + + + + { hasFilters && +
+ { events.size > 0 && + <> +
+ { events.map((event, i) => ( + + )) } + + } + +
+ +
+
+ + +
+ } + showFilters={ true } + /> +
+
+
+ +
+ +
+
+ + } +
+ ); + } +} diff --git a/frontend/app/components/BugFinder/EventFilter/RandomPlaceholder.js b/frontend/app/components/BugFinder/EventFilter/RandomPlaceholder.js new file mode 100644 index 000000000..a8df1c5a4 --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/RandomPlaceholder.js @@ -0,0 +1,88 @@ +import React from 'react'; +import { RandomElement } from 'UI'; +import stl from './randomPlaceholder.css'; +import Event, { TYPES } from 'Types/filter/event'; +import CustomFilter, { KEYS } from 'Types/filter/customFilter'; + +const getLabel = (type) => { + if (type === KEYS.MISSING_RESOURCE) return 'Missing Resource'; + if (type === KEYS.SLOW_SESSION) return 'Slow Sessions'; + if (type === KEYS.USER_COUNTRY) return 'Country'; + if (type === KEYS.USER_BROWSER) return 'Browser'; + if (type === KEYS.USERID) return 'User Id'; +} + +const getObject = (type, key) => { + switch(type) { + case TYPES.CLICK: + case TYPES.INPUT: + case TYPES.ERROR: + case TYPES.LOCATION: + return Event({ type, key: type }); + case KEYS.JOURNEY: + return [ + Event({ type: TYPES.LOCATION, key: TYPES.LOCATION }), + Event({ type: TYPES.LOCATION, key: TYPES.LOCATION }), + Event({ type: TYPES.CLICK, key: TYPES.CLICK }) + ] + + case KEYS.USER_BROWSER: + return CustomFilter({type, key: type, isFilter: true, label: getLabel(type), value: ['Chrome'] }); + case TYPES.METADATA: + return CustomFilter({type, key, isFilter: true, label: key }); + case TYPES.USERID: + return CustomFilter({type, key, isFilter: true, label: key }); + case KEYS.USER_COUNTRY: + return CustomFilter({type, key: type, isFilter: true, value: ['FR'], label: getLabel(type) }); + case KEYS.SLOW_SESSION: + case KEYS.MISSING_RESOURCE: + return CustomFilter({type, key: type, hasNoValue: true, isFilter: true, label: getLabel(type) }); + } +} + +const getList = (onClick, appliedFilterKeys) => { + let list = [ + { + key: KEYS.CLICK, + element:
Find sessions with onClick(e, getObject(TYPES.CLICK))}>Click
+ }, + { + key: KEYS.INPUT, + element:
Find sessions with onClick(e, getObject(TYPES.INPUT))}>Input
+ }, + { + key: KEYS.ERROR, + element:
Find sessions with onClick(e, getObject(TYPES.ERROR))}>Errors
+ }, + { + key: KEYS.LOCATION, + element:
Find sessions with onClick(e, getObject(TYPES.LOCATION))}>URL
+ }, + { + key: TYPES.USERID, + element:
Find sessions with onClick(e, getObject(TYPES.USERID))}>User ID
+ }, + { + key: KEYS.JOURNEY, + element:
Find sessions in a onClick(e, getObject(KEYS.JOURNEY))}>Journey
+ }, + { + key: KEYS.USER_COUNTRY, + element:
Find sessions from onClick(e, getObject(KEYS.USER_COUNTRY))}>France
+ }, + { + key: KEYS.USER_BROWSER, + element:
Find sessions on onClick(e, getObject(KEYS.USER_BROWSER))}>Chrome
+ }, + ] + + return list.filter(({key}) => !appliedFilterKeys.includes(key)) +} + +const RandomPlaceholder = ({ onClick, appliedFilterKeys }) => { + return ( + + ); +}; + +export default RandomPlaceholder; diff --git a/frontend/app/components/BugFinder/EventFilter/TypeBadge.js b/frontend/app/components/BugFinder/EventFilter/TypeBadge.js new file mode 100644 index 000000000..5ad9a69a7 --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/TypeBadge.js @@ -0,0 +1,45 @@ +import cn from 'classnames'; +import { TYPES } from 'Types/filter/event'; +import { LEVEL } from 'Types/session/log'; +import { Icon } from 'UI'; + +import styles from './typeBadge.css'; + +function getText(type, source) { + if (type === TYPES.CLICK) return 'Click'; + if (type === TYPES.LOCATION) return 'URL'; + if (type === TYPES.VIEW) return 'View'; + if (type === TYPES.INPUT) return 'Input'; + if (type === TYPES.CONSOLE) return 'Console'; + if (type === TYPES.GRAPHQL) return 'GraphQL'; + if (type === TYPES.ERROR) return 'Error'; + if (type === TYPES.STATEACTION) return 'Store Action'; + if (type === TYPES.FETCH) return 'Fetch'; + if (type === TYPES.REVID) return 'Rev ID'; + if (type === TYPES.METADATA) return 'Metadata'; + if (type === TYPES.CUSTOM) { + if (!source) return 'Custom'; + return ( + + + { 'Custom' } + + ); + } + return '?'; +} + +const TypeBadge = ({ event: { type, level, source } }) => ( +
+ { getText(type, source) } +
+); + +TypeBadge.displayName = 'TypeBadge'; + +export default TypeBadge; diff --git a/frontend/app/components/BugFinder/EventFilter/eventDropdownItem.css b/frontend/app/components/BugFinder/EventFilter/eventDropdownItem.css new file mode 100644 index 000000000..a6f7dc4d1 --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/eventDropdownItem.css @@ -0,0 +1,26 @@ +.eventDropdownItem { + padding: 8px 0; + padding-left: 18px; + border-bottom: solid thin $gray-light; + + &:last-child { + border-bottom: solid thin transparent; + } + + & .values { + max-width: 400px; + overflow: hidden; + text-overflow: ellipsis; + + &.inputType, + &.clickType { + color: $gray-darkest !important; + font-size: 14px; + } + + &.consoleType { + font-family: 'menlo', 'monaco', 'consolas', monospace; + font-size: 12px; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/EventFilter/eventEditor.css b/frontend/app/components/BugFinder/EventFilter/eventEditor.css new file mode 100644 index 000000000..a997f0ff0 --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/eventEditor.css @@ -0,0 +1,71 @@ +@import 'mixins.css'; + +@import 'icons.css'; + +.wrapper { + width: 100%; + display: flex; + padding: 8px 15px; + background-color: white; + border-bottom: solid thin $gray-lightest; + transition: all 0.4s; + + &:last-child { + border-bottom: solid thin transparent; + } + + &:hover { + background-color: $active-blue; + transition: all 0.2s; + + & .actions { + opacity: 1; + transition: all 0.2s; + } + } + + & .leftSection, + & .actions { + display: flex; + align-items: center; + } + + & .leftSection { + flex: 1; + & > div { + margin-right: 10px; + flex-shrink: 0; + } + } +} + +.index { + background: $white; + width: 24px; + height: 24px; + border-radius: 12px; + margin-right: 10px; + color: $gray-medium; + font-weight: 300; + font-size: 12px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset; +} + +.button { + width: 25px; + height: 25px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + margin-left: 10px; +} + +.actions { + opacity: 0; + transition: all 0.4s; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/EventFilter/eventFilter.css b/frontend/app/components/BugFinder/EventFilter/eventFilter.css new file mode 100644 index 000000000..22b7485cd --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/eventFilter.css @@ -0,0 +1,59 @@ +.searchField { + box-shadow: none !important; + & input { + box-shadow: none !important; + border-radius: 3 !important; + border: solid thin $gray-light !important; + height: 46px !important; + font-size: 16px; + } +} + +.wrapper { + box-shadow: none !important; + position: relative; + + & .clearStepsButton { + position: absolute; + bottom: 10px; + right: 10x; + } +} + +.randomElement { + position: absolute; + left: 0; + top: 0; + right: 0; + z-index: 8; + padding: 15px; + padding-left: 40px; +} + +.dropdownMenu { + max-width: 100%; + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; + + &[data-hidden=true] { + display: none !important; + } +} + + +.header { + padding: 5px 10px; + letter-spacing: 1.5px; + background-color: $gray-lightest; + color: $gray-medium; + font-size: 12px; + text-transform: uppercase; +} + +.dateRange { + color: red; + z-index: 8; + position: absolute; + right: 9px; + top: 9px; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/EventFilter/index.js b/frontend/app/components/BugFinder/EventFilter/index.js new file mode 100644 index 000000000..8298d268d --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/index.js @@ -0,0 +1 @@ +export { default } from './EventFilter'; diff --git a/frontend/app/components/BugFinder/EventFilter/randomPlaceholder.css b/frontend/app/components/BugFinder/EventFilter/randomPlaceholder.css new file mode 100644 index 000000000..c0958d2aa --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/randomPlaceholder.css @@ -0,0 +1,17 @@ +.placeholder { + color: $gray-medium; + font-weight: 300; + font-size: 16px; + user-select: none; + + & span { + font-weight: 400; + color: $teal; + cursor: pointer; + border-bottom: dashed thin $teal; + + &:hover { + color: $teal-dark; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/EventFilter/typeBadge.css b/frontend/app/components/BugFinder/EventFilter/typeBadge.css new file mode 100644 index 000000000..2ff7005e4 --- /dev/null +++ b/frontend/app/components/BugFinder/EventFilter/typeBadge.css @@ -0,0 +1,23 @@ +.badge { + font-size: 11px; + border-radius: 3px; + background-color: white; + border: solid thin $gray-light; + padding: 2px 0; + text-align: center; + width: 66px; + margin-right: 10px; + user-select: none; + + &.red { + background-color: rgba(204, 0, 0, 0.05); + } + + &.yellow { + background-color: rgba(245, 166, 35, 0.05); + } +} + +.icon { + vertical-align: text-top; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/FilterSelectionButton.js b/frontend/app/components/BugFinder/FilterSelectionButton.js new file mode 100644 index 000000000..7779f0ebd --- /dev/null +++ b/frontend/app/components/BugFinder/FilterSelectionButton.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { Icon } from 'UI'; +import stl from './filterSelectionButton.css'; + +const FilterSelectionButton = ({ label }) => { + return ( +
+ { label } + +
+ ); +}; + +export default FilterSelectionButton; diff --git a/frontend/app/components/BugFinder/Filters/SortDropdown.js b/frontend/app/components/BugFinder/Filters/SortDropdown.js new file mode 100644 index 000000000..80f88a0d7 --- /dev/null +++ b/frontend/app/components/BugFinder/Filters/SortDropdown.js @@ -0,0 +1,36 @@ +import { connect } from 'react-redux'; +import { Dropdown } from 'semantic-ui-react'; +import { Icon } from 'UI'; +import { sort } from 'Duck/sessions'; +import { applyFilter } from 'Duck/filters'; +import stl from './sortDropdown.css'; + +@connect(null, { sort, applyFilter }) +export default class SortDropdown extends React.PureComponent { + state = { value: null } + sort = (e, { value }) => { + this.setState({ value: value }) + const [ sort, order ] = value.split('-'); + const sign = order === 'desc' ? -1 : 1; + this.props.applyFilter({ order, sort }); + + this.props.sort(sort, sign) + setTimeout(() => this.props.sort(sort, sign), 3000); //AAA + } + + render() { + const { options } = this.props; + return ( + } + /> + ); + } +} diff --git a/frontend/app/components/BugFinder/Filters/index.js b/frontend/app/components/BugFinder/Filters/index.js new file mode 100644 index 000000000..5b18d95f3 --- /dev/null +++ b/frontend/app/components/BugFinder/Filters/index.js @@ -0,0 +1 @@ +export { default } from './Filters'; diff --git a/frontend/app/components/BugFinder/Filters/sortDropdown.css b/frontend/app/components/BugFinder/Filters/sortDropdown.css new file mode 100644 index 000000000..87e26bc68 --- /dev/null +++ b/frontend/app/components/BugFinder/Filters/sortDropdown.css @@ -0,0 +1,23 @@ +.dropdown { + display: flex !important; + padding: 4px 6px; + border-radius: 3px; + color: $gray-darkest; + font-weight: 500; + &:hover { + background-color: $gray-light; + } +} + +.dropdownTrigger { + padding: 4px 8px; + border-radius: 3px; + &:hover { + background-color: $gray-light; + } +} + +.dropdownIcon { + margin-top: 2px; + margin-left: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/FindBlock.js b/frontend/app/components/BugFinder/FindBlock.js new file mode 100644 index 000000000..7b8f295c5 --- /dev/null +++ b/frontend/app/components/BugFinder/FindBlock.js @@ -0,0 +1,33 @@ +import { connect } from 'react-redux'; +import { Button } from 'UI'; +import { applyFilter } from 'Duck/filters'; +import styles from './findBlock.css'; + +@connect(state => ({ + eventsCount: state.getIn([ 'filters', 'appliedFilter', 'events' ]).size, + lodaing: state.getIn([ 'sessions', 'loading' ]), +}), { + applyFilter, +}) +export default class FindBlock extends React.PureComponent { + onClick = () => this.props.applyFilter() + render() { + const { lodaing, eventsCount } = this.props; + + return ( +
+
+ +
+
+ ); + } +} diff --git a/frontend/app/components/BugFinder/Insights.js b/frontend/app/components/BugFinder/Insights.js new file mode 100644 index 000000000..d96c62faa --- /dev/null +++ b/frontend/app/components/BugFinder/Insights.js @@ -0,0 +1,21 @@ +import { connect } from 'react-redux'; +import styles from './insights.css'; + +const Insights = ({ insights }) => ( +
+
+ + {'This journey is only 2% of all the journeys but represents 20% of problems.'} +
+
+ + {'Lorem Ipsum 1290 events of 1500 events.'} +
+
+); + +Insights.displayName = 'Insights'; + +export default connect(state => ({ + insights: state.getIn([ 'sessions', 'insights' ]), +}))(Insights); diff --git a/frontend/app/components/BugFinder/ListHeader.js b/frontend/app/components/BugFinder/ListHeader.js new file mode 100644 index 000000000..0c7801ce8 --- /dev/null +++ b/frontend/app/components/BugFinder/ListHeader.js @@ -0,0 +1,10 @@ +import React from 'react'; +import stl from './listHeader.css'; + +const ListHeader = ({ title }) => { + return ( +
{ title }
+ ); +}; + +export default ListHeader; diff --git a/frontend/app/components/BugFinder/ManageFilters/ActiveFilterDetails.js b/frontend/app/components/BugFinder/ManageFilters/ActiveFilterDetails.js new file mode 100644 index 000000000..42136831d --- /dev/null +++ b/frontend/app/components/BugFinder/ManageFilters/ActiveFilterDetails.js @@ -0,0 +1,64 @@ +import { Button } from 'UI'; +import styles from './activeFilterDetails.css'; +import cn from 'classnames'; +import { BrowserIcon, OsIcon } from 'UI'; +import TypeBadge from '../EventFilter/TypeBadge'; + +export default ({ + activeFilter, applyFiltersHandler, removeFilter, loading, +}) => ( +
+
+ { activeFilter.name } +
+
+
+
{ 'User Events' }
+
+
+ { activeFilter.events.map((item, i) => ( +
+
{ i+1 }
+ +
{ item.value }
+
+ ))} +
+
+
+ +
+
{ 'Location:' }
+
+ { activeFilter.userCountry } +
+
+ +
+
{ 'Browser:' }
+
+ + { activeFilter.userBrowser } +
+
+ +
+
{ 'OS:' }
+
+ + { activeFilter.userOs } +
+
+
+
+ + +
+
+); diff --git a/frontend/app/components/BugFinder/ManageFilters/ManageFilters.js b/frontend/app/components/BugFinder/ManageFilters/ManageFilters.js new file mode 100644 index 000000000..f43ed0e23 --- /dev/null +++ b/frontend/app/components/BugFinder/ManageFilters/ManageFilters.js @@ -0,0 +1,77 @@ +import { connect } from 'react-redux'; +import { IconButton } from 'UI'; +import Funnel from 'Types/funnel'; +import { + remove as removeFilter, + setActive as setActiveFilter, + applyFilter, + toggleFilterModal +} from 'Duck/filters'; +import { + fetchList as fetchFilterList, + save as saveFunnel +} from 'Duck/funnels'; +import withToggle from 'Components/hocs/withToggle'; +import SaveModal from './SaveModal'; + +@withToggle('slideModalDisplayed', 'toggleSlideModal') +@connect( + state => + ({ + savedFilters: state.getIn([ 'filters', 'list' ]), + activeFilter: state.getIn([ 'filters', 'activeFilter' ]), + fetching: state.getIn([ 'filters', 'fetchListRequest', 'loading' ]), + loading: state.getIn([ 'filters', 'loading' ]), + saveModalOpen: state.getIn([ 'filters', 'saveModalOpen' ]), + appliedFilter: state.getIn([ 'filters', 'appliedFilter' ]), + customFilters: state.getIn([ 'filters', 'customFilters']), + }) + , + { + fetchFilterList, + saveFunnel, + removeFilter, + setActiveFilter, + applyFilter, + toggleFilterModal, + }, +) +export default class ManageFilters extends React.PureComponent { + updateFilter = (name, isPublic = false) => { + const { appliedFilter } = this.props; + const savedFilter = Funnel({name, filter: appliedFilter, isPublic }); + this.props.saveFunnel(savedFilter).then(function() { + this.props.fetchFilterList(); + this.props.toggleFilterModal(false); + }.bind(this)); + } + + applyFiltersHandler = (filter) => { + this.props.applyFilter(filter); + this.props.toggleSlideModal(false); + } + + render() { + const { + saveModalOpen, + appliedFilter, + } = this.props; + + return ( +
+ this.props.toggleFilterModal(true) } + /> + +
+ ); + } +} diff --git a/frontend/app/components/BugFinder/ManageFilters/SaveModal.js b/frontend/app/components/BugFinder/ManageFilters/SaveModal.js new file mode 100644 index 000000000..e43cd69e9 --- /dev/null +++ b/frontend/app/components/BugFinder/ManageFilters/SaveModal.js @@ -0,0 +1,100 @@ +import { connect } from 'react-redux'; +import { Button, Modal, Form, Icon, Checkbox } from 'UI'; +import styles from './saveModal.css'; + +@connect(state => ({ + loading: state.getIn([ 'funnels', 'saveRequest', 'loading' ]) || state.getIn([ 'funnels', 'updateRequest', 'loading' ]), +})) +export default class SaveModal extends React.PureComponent { + state = { name: 'Untitled', isPublic: false }; + static getDerivedStateFromProps(props) { + if (!props.saveModalOpen) { + return { + name: props.appliedFilter.name || 'Untitled', + }; + } + return null; + } + + onNameChange = ({ target: { value } }) => { + this.setState({ name: value }); + }; + + onChangeOption = (e, { checked, name }) => this.setState({ [ name ]: !this.state.isPublic }) + + onSave = () => { + const { toggleFilterModal } = this.props; + const { name, isPublic } = this.state; + if (name.trim() === '') return; + this.props.updateFilter(name.trim(), isPublic); + } + + render() { + const { + saveModalOpen, + appliedFilter, + toggleFilterModal, + loading, + } = this.props; + const { name, isPublic } = this.state; + + return ( + + +
{ 'Save Funnel' }
+ toggleFilterModal(false) } + /> +
+ + +
+ + + + + + +
+ this.setState({ 'isPublic' : !isPublic }) } + className="mr-3" + /> +
this.setState({ 'isPublic' : !isPublic }) }> + + Team Funnel +
+
+
+
+
+ + + + +
+ ); + } +} diff --git a/frontend/app/components/BugFinder/ManageFilters/SavedFilterList.js b/frontend/app/components/BugFinder/ManageFilters/SavedFilterList.js new file mode 100644 index 000000000..b372c6d1f --- /dev/null +++ b/frontend/app/components/BugFinder/ManageFilters/SavedFilterList.js @@ -0,0 +1,17 @@ +import styles from './savedFilterList.css'; + +export default ({ savedFilters, activeFilter, onFilterClick }) => ( +
+ { savedFilters && savedFilters.size > 0 && + savedFilters.map((filter, index) => filter && +
onFilterClick(filter) } + key={ index } + > + { filter.name } +
) + } +
+); diff --git a/frontend/app/components/BugFinder/ManageFilters/activeFilterDetails.css b/frontend/app/components/BugFinder/ManageFilters/activeFilterDetails.css new file mode 100644 index 000000000..4b07bb60a --- /dev/null +++ b/frontend/app/components/BugFinder/ManageFilters/activeFilterDetails.css @@ -0,0 +1,85 @@ +.userEvents { + & .list { + margin-top: 10px; + margin-bottom: 10px; + border: solid thin $gray-light; + border-radius: 3px; + background-color: white; + & .filterType { + border-bottom: solid thin $gray-light; + padding: 8px 10px; + align-items: center; + + & .value { + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + &:last-child { + border-bottom: none; + } + + & .indexCount { + width: 20px; + height: 20px; + background-color: white; + border-radius: 50%; + margin-right: 10px; + box-shadow: 0 1px 5px 0 $gray-light; + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + } + } + } +} + +.filterDetails { + width: 400px; + padding: 20px; + + & .title { + font-size: 20px; + margin-bottom: 25px; + } +} + +.filterType { + display: flex; + align-items: start; + padding: 10px 0; + font-size: 12px; +} + +.filterLabel { + font-weight: bold; + width: 100px; + flex-grow: 0; + flex-shrink: 0; +} + +.eventsBadge { + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.footer { + margin-top: 30px; +} + +.badge { + padding: 5px 10px; + background-color: $gray-light; + margin-right: 10px; + border-radius: 3px; + font-size: 12px; + /* margin-bottom: 10px; */ +} + +[data-hidden=true] { + display: none; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/ManageFilters/index.js b/frontend/app/components/BugFinder/ManageFilters/index.js new file mode 100644 index 000000000..d890d9507 --- /dev/null +++ b/frontend/app/components/BugFinder/ManageFilters/index.js @@ -0,0 +1 @@ +export { default } from './ManageFilters'; diff --git a/frontend/app/components/BugFinder/ManageFilters/saveModal.css b/frontend/app/components/BugFinder/ManageFilters/saveModal.css new file mode 100644 index 000000000..ed2600745 --- /dev/null +++ b/frontend/app/components/BugFinder/ManageFilters/saveModal.css @@ -0,0 +1,15 @@ +@import 'mixins.css'; + +.modalHeader { + display: flex !important; + align-items: center; + justify-content: space-between; +} + +.cancelButton { + @mixin plainButton; +} + +.applyButton { + @mixin basicButton; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/ManageFilters/savedFilterList.css b/frontend/app/components/BugFinder/ManageFilters/savedFilterList.css new file mode 100644 index 000000000..9c5110038 --- /dev/null +++ b/frontend/app/components/BugFinder/ManageFilters/savedFilterList.css @@ -0,0 +1,17 @@ +.filter { + padding: 15px; + cursor: pointer; + border-top: solid thin $gray-light; + border-bottom: solid thin transparent; + transition: all 0.3s; + + &:last-child { + border-bottom: solid thin $gray-light; + } + + &[data-active=true], + &:hover { + background-color: $active-blue; + transition: all 0.2s; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionCaptureRate/SessionCaptureRate.js b/frontend/app/components/BugFinder/SessionCaptureRate/SessionCaptureRate.js new file mode 100644 index 000000000..12fff4610 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionCaptureRate/SessionCaptureRate.js @@ -0,0 +1,78 @@ +import React from 'react' +import { Input, Slider, Button, Popup, CircularLoader } from 'UI'; +import { saveCaptureRate, editCaptureRate } from 'Duck/watchdogs'; +import { connect } from 'react-redux'; +import stl from './sessionCaptureRate.css'; + +function isPercent(val) { + if (isNaN(+val)) return false; + if (+val > 100 || +val < 0) return false; + return true; +} + +const SessionCaptureRate = props => { + const { captureRate, saveCaptureRate, editCaptureRate, loading, onClose } = props; + const sampleRate = captureRate.get('rate'); + if (sampleRate == null) return null; + + const captureAll = captureRate.get('captureAll'); + + const onSampleRateChange = (e) => { + saveCaptureRate({ rate: sampleRate, captureAll: captureAll }).then(onClose); + } + const onCaptureAllChange = () => saveCaptureRate({ rate: sampleRate, captureAll: !captureAll }); + + return ( +
+ + } + content={ `Capture All` } + size="tiny" + inverted + position="top center" + /> + { !captureAll && ( +
+ isPercent(value) && editCaptureRate(+value) } + size="small" + className={stl.inputField} + /> +
+ + +
+
+ )} +
+ ) +} + +export default connect(state => ({ + currentProjectId: state.getIn([ 'user', 'siteId' ]), + captureRate: state.getIn(['watchdogs', 'captureRate']), + loading: state.getIn(['watchdogs', 'savingCaptureRate', 'loading']), +}), { + saveCaptureRate, editCaptureRate +})(SessionCaptureRate); \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionCaptureRate/index.js b/frontend/app/components/BugFinder/SessionCaptureRate/index.js new file mode 100644 index 000000000..aadc24425 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionCaptureRate/index.js @@ -0,0 +1 @@ +export { default } from './SessionCaptureRate'; \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionCaptureRate/sessionCaptureRate.css b/frontend/app/components/BugFinder/SessionCaptureRate/sessionCaptureRate.css new file mode 100644 index 000000000..6ad48ee08 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionCaptureRate/sessionCaptureRate.css @@ -0,0 +1,13 @@ +.inputField { + max-width: 140px !important; + & label { + font-weight: 300 !important; + } + & input { + max-width: 70px !important; + } +} + +.customSlider { + line-height: 20px !important; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionFlowList/SessionFlowList.js b/frontend/app/components/BugFinder/SessionFlowList/SessionFlowList.js new file mode 100644 index 000000000..c7dca4cf8 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionFlowList/SessionFlowList.js @@ -0,0 +1,33 @@ +import React from 'react' +import { connect } from 'react-redux' +import { Loader, NoContent } from 'UI'; +import SessionStack from 'Shared/SessionStack/SessionStack' +import FunnelListHeader from 'Components/Funnels/FunnelListHeader'; + +function SessionFlowList({ activeTab, savedFilters, loading }) { + return ( +
+ + + + {savedFilters.map(item => ( +
+ +
+ ))} +
+
+
+ ) +} + +export default connect(state => ({ + loading: state.getIn([ 'filters', 'fetchListRequest', 'loading' ]), + activeTab: state.getIn([ 'sessions', 'activeTab' ]), + savedFilters: state.getIn([ 'filters', 'list' ]), +}), {})(SessionFlowList) diff --git a/frontend/app/components/BugFinder/SessionFlowList/index.js b/frontend/app/components/BugFinder/SessionFlowList/index.js new file mode 100644 index 000000000..f43dd9c40 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionFlowList/index.js @@ -0,0 +1 @@ +export { default } from './SessionFlowList' \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionList/SessionList.js b/frontend/app/components/BugFinder/SessionList/SessionList.js new file mode 100644 index 000000000..13ddf9baa --- /dev/null +++ b/frontend/app/components/BugFinder/SessionList/SessionList.js @@ -0,0 +1,146 @@ +import { connect } from 'react-redux'; +import { Loader, NoContent, Message, Icon, Button, LoadMoreButton } from 'UI'; +import { applyFilter, addAttribute, addEvent } from 'Duck/filters'; +import SessionItem from 'Shared/SessionItem'; +import SessionListHeader from './SessionListHeader'; +import { KEYS } from 'Types/filter/customFilter'; +import styles from './sessionList.css'; + +const ALL = 'all'; +const PER_PAGE = 10; + +@connect(state => ({ + savedFilters: state.getIn([ 'filters', 'list' ]), + loading: state.getIn([ 'sessions', 'loading' ]), + activeTab: state.getIn([ 'sessions', 'activeTab' ]), + allList: state.getIn([ 'sessions', 'list' ]), + total: state.getIn([ 'sessions', 'total' ]), + filters: state.getIn([ 'filters', 'appliedFilter', 'filters' ]), +}), { + applyFilter, + addAttribute, + addEvent +}) +export default class SessionList extends React.PureComponent { + state = { + showPages: 1, + } + constructor(props) { + super(props); + } + + componentDidUpdate(prevProps) { + if (prevProps.loading && !this.props.loading) { + this.setState({ showPages: 1 }); + } + } + + addPage = () => this.setState({ showPages: this.state.showPages + 1 }) + + onUserClick = (userId, userAnonymousId) => { + if (userId) { + this.props.addAttribute({ label: 'User Id', key: KEYS.USERID, type: KEYS.USERID, operator: 'is', value: userId }) + } else { + this.props.addAttribute({ label: 'Anonymous ID', key: 'USERANONYMOUSID', type: "USERANONYMOUSID", operator: 'is', value: userAnonymousId }) + } + + this.props.applyFilter() + } + + getNoContentMessage = activeTab => { + let str = "No Sessions Found"; + if (activeTab.type !== 'all') { + str += ' with ' + activeTab.name; + return str; + } + + return str + '!'; + } + + renderActiveTabContent(list) { + const { + loading, + filters, + onMenuItemClick, + allList, + activeTab + } = this.props; + + const hasUserFilter = filters.map(i => i.key).includes(KEYS.USERID); + const { showPages } = this.state; + const displayedCount = Math.min(showPages * PER_PAGE, list.size); + + return ( + +
Please try changing your search parameters.
+ {allList.size > 0 && ( +
+ However, we found other sessions based on your search parameters. +
+ +
+
+ )} + + } + > + + { list.take(displayedCount).map(session => ( + + ))} + + + Haven't found the session in the above list?
Try being a bit more specific by setting a specific time frame or simply use different filters + + } + /> +
+ ); + } + + render() { + const { activeTab, allList, total } = this.props; + var filteredList; + + if (activeTab.type !== ALL && activeTab.type !== 'bookmark') { // Watchdog sessions + filteredList = allList.filter(session => activeTab.fits(session)) + } else { + filteredList = allList + } + + if (activeTab.type === 'bookmark') { + filteredList = filteredList.filter(item => item.favorite) + } + const _total = activeTab.type === 'all' ? total : filteredList.size + + return ( +
+
+
+ + { this.renderActiveTabContent(filteredList) } +
+ ); + } +} diff --git a/frontend/app/components/BugFinder/SessionList/SessionListFooter.js b/frontend/app/components/BugFinder/SessionList/SessionListFooter.js new file mode 100644 index 000000000..e9fc16cab --- /dev/null +++ b/frontend/app/components/BugFinder/SessionList/SessionListFooter.js @@ -0,0 +1,29 @@ +import { connect } from 'react-redux'; +import { Button } from 'UI'; +import styles from './sessionListFooter.css'; + +const SessionListFooter = ({ + displayedCount, totalCount, loading, onLoadMoreClick, +}) => ( +
+
+ { `Displaying ${ displayedCount } of ${ totalCount }` } +
+ { totalCount > displayedCount && + + } +
+); + +SessionListFooter.displayName = 'SessionListFooter'; + +export default connect(state => ({ + loading: state.getIn([ 'sessions', 'loading' ]) +}))(SessionListFooter); diff --git a/frontend/app/components/BugFinder/SessionList/SessionListHeader.js b/frontend/app/components/BugFinder/SessionList/SessionListHeader.js new file mode 100644 index 000000000..9417449af --- /dev/null +++ b/frontend/app/components/BugFinder/SessionList/SessionListHeader.js @@ -0,0 +1,56 @@ +import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; +import { applyFilter } from 'Duck/filters'; +import SortDropdown from '../Filters/SortDropdown'; +import DateRange from '../DateRange'; +import { TimezoneDropdown } from 'UI'; +import { numberWithCommas } from 'App/utils'; + +const DEFAULT_SORT = 'startTs'; +const DEFAULT_ORDER = 'desc'; +const sortOptionsMap = { + 'startTs-desc': 'Newest', + 'startTs-asc': 'Oldest', + 'eventsCount-asc': 'Events Ascending', + 'eventsCount-desc': 'Events Descending', +}; +const sortOptions = Object.entries(sortOptionsMap) + .map(([ value, text ]) => ({ value, text })); + + +function SessionListHeader({ + activeTab, + count, + applyFilter, + ...props +}) { + useEffect(() => { applyFilter({ sort: DEFAULT_SORT, order: DEFAULT_ORDER }) }, []) + return ( +
+
+

+ { activeTab.name } + { count ? numberWithCommas(count) : 0 } +

+
+ Sessions Captured in + +
+
+
+
+ Timezone + +
+
+ Sort By + +
+
+
+ ); +}; + +export default connect(state => ({ + activeTab: state.getIn([ 'sessions', 'activeTab' ]), +}), { applyFilter })(SessionListHeader); diff --git a/frontend/app/components/BugFinder/SessionList/Tooltip.js b/frontend/app/components/BugFinder/SessionList/Tooltip.js new file mode 100644 index 000000000..7d500d0c0 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionList/Tooltip.js @@ -0,0 +1,40 @@ +import { Popup } from 'UI'; + +export default class Tooltip extends React.PureComponent { + state = { + open: false, + } + mouseOver = false + onMouseEnter = () => { + this.mouseOver = true; + setTimeout(() => { + if (this.mouseOver) this.setState({ open: true }); + }, 1000) + } + onMouseLeave = () => { + this.mouseOver = false; + this.setState({ + open: false, + }); + } + + render() { + const { trigger, tooltip } = this.props; + const { open } = this.state; + return ( + + { trigger } + + } + /> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionList/index.js b/frontend/app/components/BugFinder/SessionList/index.js new file mode 100644 index 000000000..7ad26942d --- /dev/null +++ b/frontend/app/components/BugFinder/SessionList/index.js @@ -0,0 +1 @@ +export { default } from './SessionList'; diff --git a/frontend/app/components/BugFinder/SessionList/sessionList.css b/frontend/app/components/BugFinder/SessionList/sessionList.css new file mode 100644 index 000000000..1d8cbbc6b --- /dev/null +++ b/frontend/app/components/BugFinder/SessionList/sessionList.css @@ -0,0 +1,12 @@ +.customMessage { + padding: 5px 10px !important; + box-shadow: none !important; + font-size: 12px !important; + color: $gray-medium !important; + font-weight: 300; + display: flex; + justify-content: center; + & > div { + flex: none !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionList/sessionListFooter.css b/frontend/app/components/BugFinder/SessionList/sessionListFooter.css new file mode 100644 index 000000000..d7a90c1b7 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionList/sessionListFooter.css @@ -0,0 +1,18 @@ +@import 'mixins.css'; + +.pageLoading { + display: flex; + flex-flow: column; + align-items: center; + margin: 20px 0 30px; +} + +.loadMoreButton { + @mixin basicButton; +} + +.countInfo { + font-size: 10px; + color: #999; + margin-bottom: 10px; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionsMenu/SessionsMenu.js b/frontend/app/components/BugFinder/SessionsMenu/SessionsMenu.js new file mode 100644 index 000000000..c29cdd6a5 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionsMenu/SessionsMenu.js @@ -0,0 +1,99 @@ +import React, { useEffect } from 'react' +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { SideMenuitem, SavedSearchList, Progress, Popup } from 'UI' +import stl from './sessionMenu.css'; +import { fetchList, fetchWatchdogStatus } from 'Duck/watchdogs'; +import { setActiveFlow, clearEvents } from 'Duck/filters'; +import { setActiveTab } from 'Duck/sessions'; + +function SessionsMenu(props) { + const { + activeFlow, activeTab, watchdogs = [], keyMap, wdTypeCount, + fetchList, fetchWatchdogStatus, toggleRehydratePanel } = props; + + const onMenuItemClick = (filter) => { + props.onMenuItemClick(filter) + + if (activeFlow && activeFlow.type === 'flows') { + props.setActiveFlow(null) + } + } + + useEffect(() => { + fetchList() + fetchWatchdogStatus() + }, []) + + const capturingAll = props.captureRate && props.captureRate.get('captureAll'); + + return ( +
+
+
+ Sessions +
+ {capturingAll && Manage} + { !capturingAll && ( + + +
+ } + content={ `Capturing ${props.captureRate.get('rate')}% of all sessions. Click to manage capture rate. ` } + size="tiny" + inverted + position="top right" + /> + )} +
+ +
+ onMenuItemClick({ name: 'All', type: 'all' })} + /> +
+ + { watchdogs.filter(item => item.visible).map(item => ( + onMenuItemClick(item)} + /> + ))} + +
+
+ onMenuItemClick({ name: 'Bookmarks', type: 'bookmark' })} + /> +
+
+ +
+ ) +} + +export default connect(state => ({ + watchdogs: state.getIn(['watchdogs', 'list']).sortBy(i => i.order), + activeTab: state.getIn([ 'sessions', 'activeTab' ]), + keyMap: state.getIn([ 'sessions', 'keyMap' ]), + wdTypeCount: state.getIn([ 'sessions', 'wdTypeCount' ]), + activeFlow: state.getIn([ 'filters', 'activeFlow' ]), + captureRate: state.getIn(['watchdogs', 'captureRate']), +}), { + fetchList, fetchWatchdogStatus, setActiveFlow, clearEvents, setActiveTab +})(SessionsMenu); diff --git a/frontend/app/components/BugFinder/SessionsMenu/index.js b/frontend/app/components/BugFinder/SessionsMenu/index.js new file mode 100644 index 000000000..b045139e4 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionsMenu/index.js @@ -0,0 +1 @@ +export { default } from './SessionsMenu'; \ No newline at end of file diff --git a/frontend/app/components/BugFinder/SessionsMenu/sessionMenu.css b/frontend/app/components/BugFinder/SessionsMenu/sessionMenu.css new file mode 100644 index 000000000..fe6643871 --- /dev/null +++ b/frontend/app/components/BugFinder/SessionsMenu/sessionMenu.css @@ -0,0 +1,29 @@ +.header { + margin-bottom: 15px; + & .label { + text-transform: uppercase; + color: gray; + letter-spacing: 0.2em; + } + + & .manageButton { + margin-left: 5px; + font-size: 12px; + color: $teal; + cursor: pointer; + padding: 2px 5px; + border: solid thin transparent; + border-radius: 3px; + margin-bottom: -3px; + &:hover { + background-color: $gray-light; + color: $gray-darkest; + } + } +} + +.divider { + height: 1px; + width: 100%; + background-color: $gray-light; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/TabItem/TabItem.js b/frontend/app/components/BugFinder/TabItem/TabItem.js new file mode 100644 index 000000000..302f6e2e8 --- /dev/null +++ b/frontend/app/components/BugFinder/TabItem/TabItem.js @@ -0,0 +1,27 @@ +import React from 'react'; +import cn from 'classnames'; +import { Icon } from 'UI'; +import stl from './tabItem.css'; + +const TabItem = ({ icon, label, count, iconColor = 'teal', active = false, leading, ...rest }) => { + return ( +
+
+ { icon && } + { label } + { count && ({ count })} +
+ { !!leading && leading } +
+ ); +} + +export default TabItem; \ No newline at end of file diff --git a/frontend/app/components/BugFinder/TabItem/index.js b/frontend/app/components/BugFinder/TabItem/index.js new file mode 100644 index 000000000..a710e0eb5 --- /dev/null +++ b/frontend/app/components/BugFinder/TabItem/index.js @@ -0,0 +1 @@ +export { default } from './TabItem' \ No newline at end of file diff --git a/frontend/app/components/BugFinder/TabItem/tabItem.css b/frontend/app/components/BugFinder/TabItem/tabItem.css new file mode 100644 index 000000000..61dafc098 --- /dev/null +++ b/frontend/app/components/BugFinder/TabItem/tabItem.css @@ -0,0 +1,23 @@ +.wrapper { + color: $teal; + cursor: pointer; + padding: 5px; + border: solid thin transparent; + border-radius: 3px; + margin-left: -5px; + + &.active, + &:hover { + background-color: $active-blue; + border-color: $active-blue-border; + & .actionWrapper { + opacity: 1; + } + } +} + +.disabled { + opacity: 0.5; + pointer-events: none; + cursor: not-allowed; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/WatchDogs/components/JobCard/JobCard.js b/frontend/app/components/BugFinder/WatchDogs/components/JobCard/JobCard.js new file mode 100644 index 000000000..d0229e761 --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/JobCard/JobCard.js @@ -0,0 +1,34 @@ +import React from 'react'; +import { Icon, CircularLoader } from 'UI'; + +const JobCard = ({ className, job, ...rest }) => { + return ( +
+
+
{ job.name }
+
{ job.isInProgress() ? + : + }
+
+
+ Sessions: { job.sessionsCount } +
+
+ Period: { job.period() } +
+ +
+
+ + { job.createdAt.toFormat('LLL dd, yyyy') } +
+
+ + { job.user && job.user.name } +
+
+
+ ); +}; + +export default JobCard; diff --git a/frontend/app/components/BugFinder/WatchDogs/components/JobCard/JobCard.stories.js b/frontend/app/components/BugFinder/WatchDogs/components/JobCard/JobCard.stories.js new file mode 100644 index 000000000..6b4d263e4 --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/JobCard/JobCard.stories.js @@ -0,0 +1,13 @@ +import JobCard from './JobCard'; + +const job = { + name: "Job Name", + sessionsCount: 32000, + userName: 'Username' +} + +export default { + title: 'WatchDog|JobCard', +}; + +export const empty = () => ; diff --git a/frontend/app/components/BugFinder/WatchDogs/components/JobCard/index.js b/frontend/app/components/BugFinder/WatchDogs/components/JobCard/index.js new file mode 100644 index 000000000..e769eaf64 --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/JobCard/index.js @@ -0,0 +1 @@ +export { default } from './JobCard' \ No newline at end of file diff --git a/frontend/app/components/BugFinder/WatchDogs/components/JobForm/JobForm.js b/frontend/app/components/BugFinder/WatchDogs/components/JobForm/JobForm.js new file mode 100644 index 000000000..17bbf4143 --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/JobForm/JobForm.js @@ -0,0 +1,109 @@ +import React from 'react'; +import { Form, Input, Button } from 'UI'; +import { connect } from 'react-redux'; +import { save, edit } from 'Duck/rehydrate'; +import DatePicker from 'react-datepicker'; + +class JobForm extends React.PureComponent { + constructor(props) { + super(props); + this.state = { }; + } + + write = ({ target: { name, value } }) => this.props.edit({ [ name ]: value }); + writeOption = (e, { name, value }) => this.props.edit({ [ name ]: value }); + onSubmit = () => { + this.props.save(this.props.instance).then(() => this.props.onCancel()) + } + + handleStartDateChange = (startAt) => { + const { endAt: currentEndDate } = this.state; + const endAt = currentEndDate - startAt > 0 + ? currentEndDate + : new Date(); + this.setState({ startAt, endAt }); + this.props.edit({ startAt: startAt.getTime(), endAt: endAt.getTime() }) + } + + handleEndDateChange = (endAt) => { + this.setState({ endAt }); + this.props.edit({ endAt: endAt.getTime() }) + } + + render() { + const { instance = {}, creating, onCancel, saving } = this.props; + const { startAt, endAt } = this.state; + const now = new Date(); + return ( +
+ + + + + + +
+
+ + +
+
+ + +
+
+
+ + + + +
+ ); + } +} + +export default connect(state => ({ + instance: state.getIn(['rehydrate', 'instance']), + saving: state.getIn(['rehydrate', 'saveRequest', 'loading']) +}), { save, edit })(JobForm); diff --git a/frontend/app/components/BugFinder/WatchDogs/components/JobForm/JobForm.stories.js b/frontend/app/components/BugFinder/WatchDogs/components/JobForm/JobForm.stories.js new file mode 100644 index 000000000..ac1b2267f --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/JobForm/JobForm.stories.js @@ -0,0 +1,7 @@ +import JobForm from './JobForm'; + +export default { + title: 'WatchDog|JobForm', +}; + +export const empty = () =>
; diff --git a/frontend/app/components/BugFinder/WatchDogs/components/JobForm/index.js b/frontend/app/components/BugFinder/WatchDogs/components/JobForm/index.js new file mode 100644 index 000000000..6c2a904df --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/JobForm/index.js @@ -0,0 +1 @@ +export { default } from './JobForm' \ No newline at end of file diff --git a/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/RehydrateSlidePanel.js b/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/RehydrateSlidePanel.js new file mode 100644 index 000000000..754bdc0e9 --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/RehydrateSlidePanel.js @@ -0,0 +1,44 @@ +import React, { useState } from 'react'; +import { connect } from 'react-redux'; +import { SlideModal } from 'UI'; +import { fetchList, init } from 'Duck/rehydrate'; +import SessionCaptureRate from '../../../SessionCaptureRate'; + +const RehydrateSlidePanel = props => { + const { onClose, list, isModalDisplayed = true, users } = props; + const [showDetail, setShowDetail] = useState(false) + + list.map(job => job.user = users.filter(user => user.id === job.createdBy).first()) + + const showDetailsForm = (job) => { + props.init(job); + setShowDetail(true); + } + + return ( + + { 'Sessions Capture Rate' } +
+ } + isDisplayed={ isModalDisplayed } + onClose={ onClose } + size="small" + content={ +
+
+
+
{ 'What percentage of your user sessions do you want to record and monitor?' }
+ +
+
+ } + /> + ); +}; + +export default connect(state => ({ + list: state.getIn(['rehydrate', 'list']), + users: state.getIn([ 'members', 'list' ]).filter(u => u.id), +}), { fetchList, init })(RehydrateSlidePanel); diff --git a/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/RehydrateSlidePanel.stories.js b/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/RehydrateSlidePanel.stories.js new file mode 100644 index 000000000..3c288d5b5 --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/RehydrateSlidePanel.stories.js @@ -0,0 +1,8 @@ +import RehydrateSlidePanel from './RehydrateSlidePanel'; + +export default { + title: 'Watchdog|RehydrateSlidePanel', +}; + +export const empty = () =>
; + diff --git a/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/index.js b/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/index.js new file mode 100644 index 000000000..66bba354b --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/RehydrateSlidePanel/index.js @@ -0,0 +1 @@ +export { default } from './RehydrateSlidePanel'; \ No newline at end of file diff --git a/frontend/app/components/BugFinder/WatchDogs/components/index.js b/frontend/app/components/BugFinder/WatchDogs/components/index.js new file mode 100644 index 000000000..400dcf390 --- /dev/null +++ b/frontend/app/components/BugFinder/WatchDogs/components/index.js @@ -0,0 +1 @@ +export { default as RehydrateSlidePanel } from './RehydrateSlidePanel' \ No newline at end of file diff --git a/frontend/app/components/BugFinder/bugFinder.css b/frontend/app/components/BugFinder/bugFinder.css new file mode 100644 index 000000000..15198e709 --- /dev/null +++ b/frontend/app/components/BugFinder/bugFinder.css @@ -0,0 +1,44 @@ +@import 'mixins.css'; + +.searchWrapper { + flex: 1; + border-radius: 3px; + margin-bottom: 30px; +} + + +.bottom { + display: flex; + align-items: center; + border-top: solid thin #EDEDED; + & > div { + cursor: pointer; + padding: 0 10px; + border-right: solid thin $gray-light; + &:hover { + background-color: $active-blue; + } + &:last-child { + border-right: solid thin transparent; + } + &:first-child { + flex: 1; + text-align: center; + } + } + +} + +.savedSearchesWrapper { + width: 200px; + margin-left: 20px; +} + + +.header { + text-transform: uppercase; + font-size: 12px; + margin-bottom: 10px; + letter-spacing: 1px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/bugFinder.stories.js b/frontend/app/components/BugFinder/bugFinder.stories.js new file mode 100644 index 000000000..fb9acb8b6 --- /dev/null +++ b/frontend/app/components/BugFinder/bugFinder.stories.js @@ -0,0 +1,70 @@ +import { storiesOf } from '@storybook/react'; +import SessionsMenu from './SessionsMenu/SessionsMenu'; +import SessionItem from 'Shared/SessionItem'; +import SessionStack from 'Shared/SessionStack'; +import Session from 'Types/session'; +import SessionListHeader from './SessionList/SessionListHeader'; +import SavedFilter from 'Types/filter/savedFilter'; +import { List } from 'immutable'; + +var items = [ + { + "watchdogId": 140, + "projectId": 1, + "type": "errors", + "payload": { + "threshold": 0, + "captureAll": true + } + }, + { + "watchdogId": 139, + "projectId": 1, + "type": "bad_request", + "payload": { + "threshold": 0, + "captureAll": true + } + }, +] + +var session = Session({ + "projectId": 1, + "sessionId": "2236890417118217", + "userUuid": "1e4bec88-fe8d-4f51-9806-716e92384ffc", + "userId": null, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", + "userOs": "Mac OS X", + "userBrowser": "Chrome", + "userDevice": "Mac", + "userCountry": "FR", + "startTs": 1584132239030, + "duration": 618469, + "eventsCount": 24, + "pagesCount": 18, + "errorsCount": 0, + "watchdogs": [ + 137, + 143 + ], + "favorite": false, + "viewed": false +}) + +var savedFilters = [ + SavedFilter({filterId: 1, name: 'Something', count: 10, watchdogs: []}) +] + +storiesOf('Bug Finder', module) + .add('Sessions Menu', () => ( + + )) + .add('Sessions Item', () => ( + + )) + .add('Session List Header', () => ( + + )) + .add('Sessions Stack', () => ( + + )) diff --git a/frontend/app/components/BugFinder/filterSelectionButton.css b/frontend/app/components/BugFinder/filterSelectionButton.css new file mode 100644 index 000000000..1741e7d83 --- /dev/null +++ b/frontend/app/components/BugFinder/filterSelectionButton.css @@ -0,0 +1,24 @@ + +.wrapper { + display: flex; + align-items: center; + justify-content: space-between; + height: 28px; + border: solid thin rgba(34, 36, 38, 0.15) !important; + border-radius: 4px; + padding: 0 10px; + width: 150px; + color: $gray-darkest; + cursor: pointer; + background-color: rgba(255, 255, 255, 0.8) !important; + &:hover { + background-color: white; + } + & span { + margin-right: 5px; + max-width: 140px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/findBlock.css b/frontend/app/components/BugFinder/findBlock.css new file mode 100644 index 000000000..ef04b7814 --- /dev/null +++ b/frontend/app/components/BugFinder/findBlock.css @@ -0,0 +1,26 @@ + +@import 'mixins.css'; + +.clearStepsButton { + margin-right: 10px; +} + +.findBlock { + display: flex; + align-items: center; + justify-content: space-between; + margin-right: auto; + &[data-hide=true] { + display: none; + } + + & .findButton { + text-transform: uppercase; + } + + & button { + height: 23px !important; + padding: 0px 15px !important; + font-size: 12px !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/index.js b/frontend/app/components/BugFinder/index.js new file mode 100644 index 000000000..7594b6ce8 --- /dev/null +++ b/frontend/app/components/BugFinder/index.js @@ -0,0 +1 @@ +export { default } from './BugFinder'; diff --git a/frontend/app/components/BugFinder/insights.css b/frontend/app/components/BugFinder/insights.css new file mode 100644 index 000000000..8d935dbac --- /dev/null +++ b/frontend/app/components/BugFinder/insights.css @@ -0,0 +1,18 @@ + +@import 'icons.css'; + +.notes { + margin: 15px 0; + font-weight: 300; +} +.tipIcon { + @mixin icon lightbulb, $gray-medium, 13px; + margin-right: 5px; +} + +.tipText { + display: flex; + align-items: center; + color: $gray-medium; + font-size: 12px; +} diff --git a/frontend/app/components/BugFinder/listHeader.css b/frontend/app/components/BugFinder/listHeader.css new file mode 100644 index 000000000..76e5907e4 --- /dev/null +++ b/frontend/app/components/BugFinder/listHeader.css @@ -0,0 +1,7 @@ +.header { + padding: 3px 10px; + letter-spacing: 1.5px; + color: $gray-medium; + font-size: 12px; + text-transform: uppercase; +} \ No newline at end of file diff --git a/frontend/app/components/BugFinder/managerFitler.stories.js b/frontend/app/components/BugFinder/managerFitler.stories.js new file mode 100644 index 000000000..85d3a257e --- /dev/null +++ b/frontend/app/components/BugFinder/managerFitler.stories.js @@ -0,0 +1,40 @@ +import { storiesOf } from '@storybook/react'; +import { List } from 'immutable'; +import Filter from 'Types/filter'; +import ActiveFilterDetails from './ManageFilters/ActiveFilterDetails'; +import SavedFilterList from './ManageFilters/SavedFilterList'; + +const savedFilters = List([ + Filter({ + id: 1, + name: 'First Filter', + events: [ + {type: 'CLICK', value: 'test'}, + {type: 'CLICK', value: 'test'}, + {type: 'CLICK', value: 'this is some long test to test the text overflow, should show ellipsis'} + ], + userCountry: 'IN', userBrowser: 'Chrome', userOs: 'windows' + }), + Filter({ + id: 2, + name: 'Second Filter', + events: [ + {type: 'CLICK', value: 'test'}, + {type: 'CLICK', value: 'test'}, + {type: 'CLICK', value: 'this is some long test to test the text overflow, should show ellipsis'} + ], + userCountry: 'IN', userBrowser: 'Chrome', userOs: 'windows' + })] +) +storiesOf('ManageFilter', module) + .add('Filter Details', () => ( + + )) + .add('FilterList', () => ( + + )) + diff --git a/frontend/app/components/Client/Client.js b/frontend/app/components/Client/Client.js new file mode 100644 index 000000000..f8a3ee0c8 --- /dev/null +++ b/frontend/app/components/Client/Client.js @@ -0,0 +1,64 @@ +import { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom'; +import { Switch, Route, Redirect } from 'react-router'; +import { CLIENT_TABS, client as clientRoute } from 'App/routes'; +import { fetchList as fetchMemberList } from 'Duck/member'; +import { fetchList as fetchSiteList } from 'Duck/site'; + +import ProfileSettings from './ProfileSettings'; +import Integrations from './Integrations'; +import ManageUsers from './ManageUsers'; +import Sites from './Sites'; +import CustomFields from './CustomFields'; +import Webhooks from './Webhooks'; +import styles from './client.css'; +import cn from 'classnames'; +import PreferencesMenu from './PreferencesMenu'; +import Notifications from './Notifications'; + +@connect((state) => ({ + appearance: state.getIn([ 'user', 'account', 'appearance' ]), +}), { + fetchMemberList, + fetchSiteList, +}) +@withRouter +export default class Client extends React.PureComponent { + constructor(props){ + super(props); + props.fetchMemberList(); + } + + setTab = (tab) => { + this.props.history.push(clientRoute(tab)); + } + + renderActiveTab = (appearance) => ( + + + + + + + + + + + ) + + render() { + const { match: { params: { activeTab } }, appearance } = this.props; + return ( +
+
+
+ +
+
+ { activeTab && this.renderActiveTab(appearance) } +
+
+
+ ); + } +} diff --git a/frontend/app/components/Client/CustomFields/CustomFieldForm.js b/frontend/app/components/Client/CustomFields/CustomFieldForm.js new file mode 100644 index 000000000..e0b901392 --- /dev/null +++ b/frontend/app/components/Client/CustomFields/CustomFieldForm.js @@ -0,0 +1,62 @@ +import { connect } from 'react-redux'; +import { edit, save } from 'Duck/customField'; +import { Form, Button, Message } from 'UI'; +import styles from './customFieldForm.css'; + +@connect(state => ({ + field: state.getIn(['customFields', 'instance']), + saving: state.getIn(['customFields', 'saveRequest', 'loading']), + errors: state.getIn([ 'customFields', 'saveRequest', 'errors' ]), +}), { + edit, + save, +}) +class CustomFieldForm extends React.PureComponent { + setFocus = () => this.focusElement.focus(); + onChangeSelect = (event, { name, value }) => this.props.edit({ [ name ]: value }); + write = ({ target: { value, name } }) => this.props.edit({ [ name ]: value }); + + render() { + const { field, errors} = this.props; + const exists = field.exists(); + return ( +
+ + + { this.focusElement = ref; } } + name="key" + value={ field.key } + onChange={ this.write } + placeholder="Field Name" + /> + + + { errors && +
+ { errors.map(error => { error }) } +
+ } + + + +
+ ); + } +} + +export default CustomFieldForm; diff --git a/frontend/app/components/Client/CustomFields/CustomFields.js b/frontend/app/components/Client/CustomFields/CustomFields.js new file mode 100644 index 000000000..50b551242 --- /dev/null +++ b/frontend/app/components/Client/CustomFields/CustomFields.js @@ -0,0 +1,121 @@ +import cn from 'classnames'; +import { connect } from 'react-redux'; +import withPageTitle from 'HOCs/withPageTitle'; +import { IconButton, SlideModal, Loader, NoContent, Icon, TextLink } from 'UI'; +import { init, fetchList, save, remove } from 'Duck/customField'; +import SiteDropdown from 'Shared/SiteDropdown'; +import styles from './customFields.css'; +import CustomFieldForm from './CustomFieldForm'; +import ListItem from './ListItem'; +import { confirm } from 'UI/Confirmation'; + +@connect(state => ({ + fields: state.getIn(['customFields', 'list']).sortBy(i => i.index), + field: state.getIn(['customFields', 'instance']), + loading: state.getIn(['customFields', 'fetchRequest', 'loading']), + sites: state.getIn([ 'user', 'client', 'sites' ]), + errors: state.getIn([ 'customFields', 'saveRequest', 'errors' ]), +}), { + init, + fetchList, + save, + remove, +}) +@withPageTitle('Metadata - OpenReplay Preferences') +class CustomFields extends React.Component { + state = { showModal: false, currentSite: this.props.sites.get(0) }; + + componentWillMount() { + const activeSite = this.props.sites.get(0); + if (!activeSite) return; + + this.props.fetchList(activeSite.id); + } + + save = (field) => { + const { currentSite } = this.state; + this.props.save(currentSite.id, field).then(() => { + const { errors } = this.props; + if (!errors || errors.size === 0) { + return this.closeModal(); + } + }); + }; + + closeModal = () => this.setState({ showModal: false }); + init = (field) => { + this.props.init(field); + this.setState({ showModal: true }); + } + + onChangeSelect = (event, { value }) => { + const site = this.props.sites.find(s => s.id === value); + this.setState({ currentSite: site }) + this.props.fetchList(site.id); + } + + removeMetadata = async (field) => { + if (await confirm({ + header: 'Metadata', + confirmation: `Are you sure you want to remove?` + })) { + const { currentSite } = this.state; + this.props.remove(currentSite.id, field.index).then(() => { + + }); + } + } + + render() { + const { fields, field, loading } = this.props; + const { showModal, currentSite } = this.state; + return ( +
+ } + onClose={ this.closeModal } + /> +
+

{ 'Metadata' }

+
+ +
+ this.init() } /> + +
+ + + +
+ { fields.filter(i => i.index).map(field => ( + this.removeMetadata(field) } + /> + ))} +
+
+
+
+ ); + } +} + +export default CustomFields; diff --git a/frontend/app/components/Client/CustomFields/ListItem.js b/frontend/app/components/Client/CustomFields/ListItem.js new file mode 100644 index 000000000..95c776fc7 --- /dev/null +++ b/frontend/app/components/Client/CustomFields/ListItem.js @@ -0,0 +1,22 @@ +import React from 'react'; +import cn from 'classnames' +import { Icon } from 'UI'; +import styles from './listItem.css'; + +const ListItem = ({ field, onEdit, onDelete }) => { + return ( +
field.index != 0 && onEdit(field) } > + { field.key } +
+
{ e.stopPropagation(); onDelete(field) } }> + +
+
+ +
+
+
+ ); +}; + +export default ListItem; diff --git a/frontend/app/components/Client/CustomFields/customFieldForm.css b/frontend/app/components/Client/CustomFields/customFieldForm.css new file mode 100644 index 000000000..b1ae8536d --- /dev/null +++ b/frontend/app/components/Client/CustomFields/customFieldForm.css @@ -0,0 +1,3 @@ +.wrapper { + padding: 0 20px; +} diff --git a/frontend/app/components/Client/CustomFields/customFields.css b/frontend/app/components/Client/CustomFields/customFields.css new file mode 100644 index 000000000..8636473a7 --- /dev/null +++ b/frontend/app/components/Client/CustomFields/customFields.css @@ -0,0 +1,10 @@ +.tabHeader { + display: flex; + align-items: center; + margin-bottom: 25px; + + & .tabTitle { + margin: 0 15px 0 0; + font-weight: 400 !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/CustomFields/index.js b/frontend/app/components/Client/CustomFields/index.js new file mode 100644 index 000000000..2b1c8b48b --- /dev/null +++ b/frontend/app/components/Client/CustomFields/index.js @@ -0,0 +1 @@ +export { default } from './CustomFields'; \ No newline at end of file diff --git a/frontend/app/components/Client/CustomFields/listItem.css b/frontend/app/components/Client/CustomFields/listItem.css new file mode 100644 index 000000000..a46ac7a73 --- /dev/null +++ b/frontend/app/components/Client/CustomFields/listItem.css @@ -0,0 +1,50 @@ +@import 'mixins.css'; + +.wrapper { + display: flex; + padding: 15px 10px; + border-bottom: solid thin $gray-light; + transition: all 0.4s; + align-items: center; + cursor: pointer; + + &:hover { + background-color: $active-blue; + transition: all 0.2s; + & .actions { + opacity: 1; + transition: all 0.4s; + } + } +} + +.preDefined { + cursor: not-allowed; +} + +.actions { + margin-left: auto; + opacity: 0; + transition: all 0.4s; + display: flex; + align-items: center; + & .button { + padding: 5px; + cursor: pointer; + margin-left: 10px; + &:hover { + & svg { + fill: $teal-dark; + } + } + } +} + +.tag { + margin-left: 10px; + font-size: 12px; + padding: 2px 10px; + border-radius: 10px; + background-color: $gray-lightest; + box-shadow: 0 0 0 1px $gray-light inset; +} \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/BugsnagForm/BugsnagForm.js b/frontend/app/components/Client/Integrations/BugsnagForm/BugsnagForm.js new file mode 100644 index 000000000..fc3dc1c72 --- /dev/null +++ b/frontend/app/components/Client/Integrations/BugsnagForm/BugsnagForm.js @@ -0,0 +1,24 @@ +import { tokenRE } from 'Types/integrations/bugsnagConfig'; +import IntegrationForm from '../IntegrationForm'; +import ProjectListDropdown from './ProjectListDropdown'; + +const BugsnagForm = (props) => ( + tokenRE.test(config.authorizationToken), + component: ProjectListDropdown, + } + ]} + /> +); + +BugsnagForm.displayName = "BugsnagForm"; + +export default BugsnagForm; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/BugsnagForm/ProjectListDropdown.js b/frontend/app/components/Client/Integrations/BugsnagForm/ProjectListDropdown.js new file mode 100644 index 000000000..bb4758f4d --- /dev/null +++ b/frontend/app/components/Client/Integrations/BugsnagForm/ProjectListDropdown.js @@ -0,0 +1,78 @@ +import { connect } from 'react-redux'; +import { tokenRE } from 'Types/integrations/bugsnagConfig'; +import { edit } from 'Duck/integrations/actions'; +import { Dropdown } from 'UI'; +import { withRequest } from 'HOCs'; + +@connect(state => ({ + token: state.getIn([ 'bugsnag', 'instance', 'authorizationToken' ]) +}), { edit }) +@withRequest({ + dataName: "projects", + initialData: [], + dataWrapper: (data = [], prevData) => { + if (!Array.isArray(data)) throw new Error('Wrong responce format.'); + const withOrgName = data.length > 1; + return data.reduce((accum, { name: orgName, projects }) => { + if (!Array.isArray(projects)) throw new Error('Wrong responce format.'); + if (withOrgName) projects = projects.map(p => ({ ...p, name: `${ p.name } (${ orgName })` })) + return accum.concat(projects); + }, []); + }, + resetBeforeRequest: true, + requestName: "fetchProjectList", + endpoint: '/integrations/bugsnag/list_projects', + method: 'POST', +}) +export default class ProjectListDropdown extends React.PureComponent { + constructor(props) { + super(props); + this.fetchProjectList() + } + fetchProjectList() { + const { token } = this.props; + if (!tokenRE.test(token)) return; + this.props.fetchProjectList({ + authorizationToken: token, + }).then(() => { + const { value, projects } = this.props; + const values = projects.map(p => p.id); + if (!values.includes(value) && values.length > 0) { + this.props.edit("bugsnag", { + projectId: values[0], + }); + } + }); + } + componentDidUpdate(prevProps) { + if (prevProps.token !== this.props.token) { + this.fetchProjectList(); + } + } + onChange = (e, target) => { + if (typeof this.props.onChange === 'function') { + this.props.onChange({ target }); + } + } + render() { + const { + projects, + name, + value, + placeholder, + loading, + } = this.props; + const options = projects.map(({ name, id }) => ({ text: name, value: id })); + return ( + + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/BugsnagForm/index.js b/frontend/app/components/Client/Integrations/BugsnagForm/index.js new file mode 100644 index 000000000..b4cf301bf --- /dev/null +++ b/frontend/app/components/Client/Integrations/BugsnagForm/index.js @@ -0,0 +1 @@ +export { default } from './BugsnagForm'; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/CloudwatchForm/CloudwatchForm.js b/frontend/app/components/Client/Integrations/CloudwatchForm/CloudwatchForm.js new file mode 100644 index 000000000..df7fbd1ce --- /dev/null +++ b/frontend/app/components/Client/Integrations/CloudwatchForm/CloudwatchForm.js @@ -0,0 +1,41 @@ +import { ACCESS_KEY_ID_LENGTH, SECRET_ACCESS_KEY_LENGTH } from 'Types/integrations/cloudwatchConfig'; +import IntegrationForm from '../IntegrationForm'; +import LogGroupDropdown from './LogGroupDropdown'; +import RegionDropdown from './RegionDropdown'; + +const CloudwatchForm = (props) => ( + <> +
+
How to integrate CloudWatch with OpenReplay and see backend errors alongside session replays.
+
See Documentation for more details.
+
+ + config.awsSecretAccessKey.length === SECRET_ACCESS_KEY_LENGTH && + config.region !== '' && + config.awsAccessKeyId.length === ACCESS_KEY_ID_LENGTH + } + ]} + /> + +); + +CloudwatchForm.displayName = "CloudwatchForm"; + +export default CloudwatchForm; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/CloudwatchForm/LogGroupDropdown.js b/frontend/app/components/Client/Integrations/CloudwatchForm/LogGroupDropdown.js new file mode 100644 index 000000000..3617d58b7 --- /dev/null +++ b/frontend/app/components/Client/Integrations/CloudwatchForm/LogGroupDropdown.js @@ -0,0 +1,76 @@ +import { connect } from 'react-redux'; +import { ACCESS_KEY_ID_LENGTH, SECRET_ACCESS_KEY_LENGTH } from 'Types/integrations/cloudwatchConfig'; +import { edit } from 'Duck/integrations/actions'; +import { Dropdown } from 'UI'; +import { withRequest } from 'HOCs'; + +@connect(state => ({ + config: state.getIn([ 'cloudwatch', 'instance' ]) +}), { edit }) +@withRequest({ + dataName: "values", + initialData: [], + resetBeforeRequest: true, + requestName: "fetchLogGroups", + endpoint: '/integrations/cloudwatch/list_groups', + method: 'POST', +}) +export default class LogGroupDropdown extends React.PureComponent { + constructor(props) { + super(props); + this.fetchLogGroups() + } + fetchLogGroups() { + const { config } = this.props; + if (config.region === "" || + config.awsSecretAccessKey.length !== SECRET_ACCESS_KEY_LENGTH || + config.awsAccessKeyId.length !== ACCESS_KEY_ID_LENGTH + ) return; + this.props.fetchLogGroups({ + region: config.region, + awsSecretAccessKey: config.awsSecretAccessKey, + awsAccessKeyId: config.awsAccessKeyId, + }).then(() => { + const { value, values, name } = this.props; + if (!values.includes(value) && values.length > 0) { + this.props.edit("cloudwatch", { + [ name ]: values[0], + }); + } + }); + } + componentDidUpdate(prevProps) { + const { config } = this.props; + if (prevProps.config.region !== config.region || + prevProps.config.awsSecretAccessKey !== config.awsSecretAccessKey || + prevProps.config.awsAccessKeyId !== config.awsAccessKeyId) { + this.fetchLogGroups(); + } + } + onChange = (e, target) => { + if (typeof this.props.onChange === 'function') { + this.props.onChange({ target }); + } + } + render() { + const { + values, + name, + value, + placeholder, + loading, + } = this.props; + const options = values.map(g => ({ text: g, value: g })); + return ( + + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/CloudwatchForm/RegionDropdown.js b/frontend/app/components/Client/Integrations/CloudwatchForm/RegionDropdown.js new file mode 100644 index 000000000..21d8ed05a --- /dev/null +++ b/frontend/app/components/Client/Integrations/CloudwatchForm/RegionDropdown.js @@ -0,0 +1,18 @@ +import { regionLabels as labels } from 'Types/integrations/cloudwatchConfig'; +import { Dropdown } from 'UI'; + +const options = Object.keys(labels).map(key => ({ text: labels[ key ], value: key })); + +const RegionDropdown = props => ( + props.onChange({target})} + selection + options={ options } + /> +); + +RegionDropdown.displayName = "RegionDropdown"; + +export default RegionDropdown; + diff --git a/frontend/app/components/Client/Integrations/CloudwatchForm/index.js b/frontend/app/components/Client/Integrations/CloudwatchForm/index.js new file mode 100644 index 000000000..d6f9e199c --- /dev/null +++ b/frontend/app/components/Client/Integrations/CloudwatchForm/index.js @@ -0,0 +1 @@ +export { default } from './CloudwatchForm'; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/DatadogForm.js b/frontend/app/components/Client/Integrations/DatadogForm.js new file mode 100644 index 000000000..8805ee2a8 --- /dev/null +++ b/frontend/app/components/Client/Integrations/DatadogForm.js @@ -0,0 +1,27 @@ +import IntegrationForm from './IntegrationForm'; + +const DatadogForm = (props) => ( + <> +
+
How to integrate Datadog with OpenReplay and see backend errors alongside session recordings.
+
See Documentation for more details.
+
+ + +); + +DatadogForm.displayName = "DatadogForm"; + +export default DatadogForm; diff --git a/frontend/app/components/Client/Integrations/ElasticsearchForm.js b/frontend/app/components/Client/Integrations/ElasticsearchForm.js new file mode 100644 index 000000000..0cd60879f --- /dev/null +++ b/frontend/app/components/Client/Integrations/ElasticsearchForm.js @@ -0,0 +1,73 @@ +import { connect } from 'react-redux'; +import IntegrationForm from './IntegrationForm'; +import { withRequest } from 'HOCs'; +import { edit } from 'Duck/integrations/actions'; + +@connect(state => ({ + config: state.getIn([ 'elasticsearch', 'instance' ]) +}), { edit }) +@withRequest({ + dataName: "isValid", + initialData: false, + dataWrapper: data => data.state, + requestName: "validateConfig", + endpoint: '/integrations/elasticsearch/test', + method: 'POST', +}) +export default class ElasticsearchForm extends React.PureComponent { + componentWillReceiveProps(newProps) { + const { config: { host, port, apiKeyId, apiKey } } = this.props; + const { loading, config } = newProps; + const valuesChanged = host !== config.host || port !== config.port || apiKeyId !== config.apiKeyId || apiKey !== config.apiKey; + if (!loading && valuesChanged && newProps.config.validateKeys() && newProps) { + this.validateConfig(newProps); + } + } + + validateConfig = (newProps) => { + const { config } = newProps; + this.props.validateConfig({ + host: config.host, + port: config.port, + apiKeyId: config.apiKeyId, + apiKey: config.apiKey, + }).then((res) => { + const { isValid } = this.props; + this.props.edit('elasticsearch', { isValid: isValid }) + }); + } + + render() { + const props = this.props; + return ( + <> +
+
How to integrate Elasticsearch with OpenReplay and see backend errors alongside session recordings.
+
See Documentation for more details.
+
+ + + ) + } +}; diff --git a/frontend/app/components/Client/Integrations/FetchDoc/FetchDoc.js b/frontend/app/components/Client/Integrations/FetchDoc/FetchDoc.js new file mode 100644 index 000000000..c94d53a1e --- /dev/null +++ b/frontend/app/components/Client/Integrations/FetchDoc/FetchDoc.js @@ -0,0 +1,65 @@ +import Highlight from 'react-highlight' +import ToggleContent from '../../../shared/ToggleContent' + +const FetchDoc = (props) => { + return ( +
+
This plugin allows you to capture fetch payloads and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
+ +
Installation
+ + {`npm i @openreplay/tracker-fetch --save`} + + +
Usage
+

Use the provided fetch method from the plugin instead of the one built-in.

+
+ +
Usage
+ + {`import tracker from '@openreplay/tracker'; +import trackerFetch from '@openreplay/tracker-fetch'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +tracker.start(); +//... +export const fetch = tracker.use(trackerFetch()); // check list of available options below +//... +fetch('https://api.openreplay.com/').then(response => console.log(response.json()));`} + + } + second={ + + {`import OpenReplay from '@openreplay/tracker/cjs'; +import trackerFetch from '@openreplay/tracker-fetch/cjs'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +//... +function SomeFunctionalComponent() { + useEffect(() => { // or componentDidMount in case of Class approach + tracker.start(); + }, []) +//... +export const fetch = tracker.use(trackerFetch()); // check list of available options below +//... +fetch('https://api.openreplay.com/').then(response => console.log(response.json())); +}`} + + } + /> + +
See API for more options.
+
+ ) +}; + +FetchDoc.displayName = "FetchDoc"; + +export default FetchDoc; diff --git a/frontend/app/components/Client/Integrations/FetchDoc/index.js b/frontend/app/components/Client/Integrations/FetchDoc/index.js new file mode 100644 index 000000000..9bb21e9b9 --- /dev/null +++ b/frontend/app/components/Client/Integrations/FetchDoc/index.js @@ -0,0 +1 @@ +export { default } from './FetchDoc' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/GithubForm.js b/frontend/app/components/Client/Integrations/GithubForm.js new file mode 100644 index 000000000..f9daeebe4 --- /dev/null +++ b/frontend/app/components/Client/Integrations/GithubForm.js @@ -0,0 +1,28 @@ +import IntegrationForm from './IntegrationForm'; + +const GithubForm = (props) => ( + <> +
+
Integrate GitHub with OpenReplay and create issues directly from the recording page.
+ +
+ + +); + +GithubForm.displayName = "GithubForm"; + +export default GithubForm; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/GraphQLDoc/GraphQLDoc.js b/frontend/app/components/Client/Integrations/GraphQLDoc/GraphQLDoc.js new file mode 100644 index 000000000..dcafe41e5 --- /dev/null +++ b/frontend/app/components/Client/Integrations/GraphQLDoc/GraphQLDoc.js @@ -0,0 +1,62 @@ +import Highlight from 'react-highlight' +import ToggleContent from '../../../shared/ToggleContent'; + +const GraphQLDoc = (props) => { + return ( +
+

This plugin allows you to capture GraphQL requests and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.

+

GraphQL plugin is compatible with Apollo and Relay implementations.

+ +
Installation
+ + {`npm i @openreplay/tracker-graphql --save`} + + +
Usage
+

The plugin call will return the function, which receives four variables operationKind, operationName, variables and result. It returns result without changes.

+ +
+ + + {`import OpenReplay from '@openreplay/tracker'; +import trackerGraphQL from '@openreplay/tracker-graphql'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY, +}); +tracker.start(); +//... +export const recordGraphQL = tracker.use(trackerGraphQL());`} + + } + second={ + + {`import OpenReplay from '@openreplay/tracker/cjs'; +import trackerGraphQL from '@openreplay/tracker-graphql/cjs'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +//... +function SomeFunctionalComponent() { + useEffect(() => { // or componentDidMount in case of Class approach + tracker.start(); + }, []) +} +//... +export const recordGraphQL = tracker.use(trackerGraphQL());`} + + } + /> + +
See API for more options.
+
+ ) +}; + +GraphQLDoc.displayName = "GraphQLDoc"; + +export default GraphQLDoc; diff --git a/frontend/app/components/Client/Integrations/GraphQLDoc/index.js b/frontend/app/components/Client/Integrations/GraphQLDoc/index.js new file mode 100644 index 000000000..6fe38bba7 --- /dev/null +++ b/frontend/app/components/Client/Integrations/GraphQLDoc/index.js @@ -0,0 +1 @@ +export { default } from './GraphQLDoc' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/IntegrationForm.js b/frontend/app/components/Client/Integrations/IntegrationForm.js new file mode 100644 index 000000000..8057021c8 --- /dev/null +++ b/frontend/app/components/Client/Integrations/IntegrationForm.js @@ -0,0 +1,143 @@ +import { connect } from 'react-redux'; +import { Select, Form, Button, Checkbox } from 'UI'; +import SiteDropdown from 'Shared/SiteDropdown'; +import { save, init, edit, remove, fetchList } from 'Duck/integrations/actions'; + +@connect((state, { name, customPath }) => ({ + sites: state.getIn([ 'user', 'client', 'sites' ]), + initialSiteId: state.getIn([ 'user', 'siteId' ]), + list: state.getIn([ name, 'list' ]), + config: state.getIn([ name, 'instance']), + saving: state.getIn([ customPath || name, 'saveRequest', 'loading']), + removing: state.getIn([ name, 'removeRequest', 'loading']), +}), { + save, + init, + edit, + remove, + fetchList +}) +export default class IntegrationForm extends React.PureComponent { + constructor(props) { + super(props); + const currentSiteId = this.props.initialSiteId; + this.state = { currentSiteId }; + this.init(currentSiteId); + } + + write = ({ target: { value, name: key, type, checked } }) => { + if (type === 'checkbox') + this.props.edit(this.props.name, { [ key ]: checked }) + else + this.props.edit(this.props.name, { [ key ]: value }) + }; + + onChangeSelect = (event, { value }) => { + const { sites, list, name } = this.props; + const site = sites.find(s => s.id === value); + this.setState({ currentSiteId: site.id }) + this.init(value); + } + + init = (siteId) => { + const { list, name } = this.props; + const config = (parseInt(siteId) > 0) ? list.find(s => s.projectId === siteId) : undefined; + this.props.init(name, config ? config : list.first()); + } + + save = () => { + const { config, name, customPath } = this.props; + const isExists = config.exists(); + const { currentSiteId } = this.state; + const { ignoreProject } = this.props; + this.props.save(customPath || name, (!ignoreProject ? currentSiteId : null), config) + .then(() => { + this.props.fetchList(name) + this.props.onClose(); + if (isExists) return; + }); + } + + remove = () => { + const { name, config, ignoreProject } = this.props; + this.props.remove(name, !ignoreProject ? config.projectId : null).then(function() { + this.props.onClose(); + this.props.fetchList(name) + }.bind(this)); + } + + render() { + const { config, saving, removing, formFields, name, loading, ignoreProject } = this.props; + const { currentSiteId } = this.state; + + return ( +
+
+ {!ignoreProject && + + + + + } + + { formFields.map(({ + key, + label, + placeholder=label, + component: Component = 'input', + type = "text", + checkIfDisplayed, + autoFocus=false + }) => (typeof checkIfDisplayed !== 'function' || checkIfDisplayed(config)) && + ((type === 'checkbox') ? + + + + : + + + + + ) + )} + + + + +
+
+ ); + } +} diff --git a/frontend/app/components/Client/Integrations/IntegrationItem.js b/frontend/app/components/Client/Integrations/IntegrationItem.js new file mode 100644 index 000000000..e75eb6c37 --- /dev/null +++ b/frontend/app/components/Client/Integrations/IntegrationItem.js @@ -0,0 +1,27 @@ +import React from 'react'; +import cn from 'classnames'; +import { Icon } from 'UI'; +import stl from './integrationItem.css'; + +const onDocLinkClick = (e, link) => { + e.stopPropagation(); + window.open(link, '_blank'); +} + +const IntegrationItem = ({ + deleteHandler = null, icon, url = null, title = '', description = '', onClick = null, dockLink = '', integrated = false +}) => { + return ( +
onClick(e, url) }> + {integrated && ( +
+ +
+ )} + +

{ title }

+
+ ) +}; + +export default IntegrationItem; diff --git a/frontend/app/components/Client/Integrations/Integrations.js b/frontend/app/components/Client/Integrations/Integrations.js new file mode 100644 index 000000000..c148d7f31 --- /dev/null +++ b/frontend/app/components/Client/Integrations/Integrations.js @@ -0,0 +1,495 @@ +import { connect } from 'react-redux'; +import withPageTitle from 'HOCs/withPageTitle'; +import { Loader, IconButton, Button, Icon, SlideModal } from 'UI'; +import { fetchList as fetchListSlack } from 'Duck/integrations/slack'; +import { remove as removeIntegrationConfig } from 'Duck/integrations/actions'; +import { fetchList, init } from 'Duck/integrations/actions'; +import cn from 'classnames'; + +import IntegrationItem from './IntegrationItem'; +import SentryForm from './SentryForm'; +import GithubForm from './GithubForm'; +import SlackForm from './SlackForm'; +import DatadogForm from './DatadogForm'; +import StackdriverForm from './StackdriverForm'; +import RollbarForm from './RollbarForm'; +import NewrelicForm from './NewrelicForm'; +import BugsnagForm from './BugsnagForm'; +import CloudwatchForm from './CloudwatchForm'; +import ElasticsearchForm from './ElasticsearchForm'; +import SumoLogicForm from './SumoLogicForm'; +import JiraForm from './JiraForm'; +import styles from './integrations.css'; +import ReduxDoc from './ReduxDoc'; +import VueDoc from './VueDoc'; +import GraphQLDoc from './GraphQLDoc'; +import NgRxDoc from './NgRxDoc/NgRxDoc'; +import SlackAddForm from './SlackAddForm'; +import FetchDoc from './FetchDoc'; +import MobxDoc from './MobxDoc'; +import ProfilerDoc from './ProfilerDoc'; + +const NONE = -1; +const SENTRY = 0; +const DATADOG = 1; +const STACKDRIVER = 2; +const ROLLBAR = 3; +const NEWRELIC = 4; +const BUGSNAG = 5; +const CLOUDWATCH = 6; +const ELASTICSEARCH = 7; +const SUMOLOGIC = 8; +const JIRA = 9; +const GITHUB = 10; +const REDUX = 11; +const VUE = 12; +const GRAPHQL = 13; +const NGRX = 14; +const SLACK = 15; +const FETCH = 16; +const MOBX = 17; +const PROFILER = 18; + +const TITLE = { + [ SENTRY ]: 'Sentry', + [ SLACK ]: 'Slack', + [ DATADOG ]: 'Datadog', + [ STACKDRIVER ]: 'Stackdriver', + [ ROLLBAR ]: 'Rollbar', + [ NEWRELIC ]: 'New Relic', + [ BUGSNAG ]: 'Bugsnag', + [ CLOUDWATCH ]: 'CloudWatch', + [ ELASTICSEARCH ]: 'Elastic Search', + [ SUMOLOGIC ]: 'Sumo Logic', + [ JIRA ]: 'Jira', + [ GITHUB ]: 'Github', + [ REDUX ] : 'Redux', + [ VUE ] : 'VueX', + [ GRAPHQL ] : 'GraphQL', + [ NGRX ] : 'NgRx', + [ FETCH ] : 'Fetch', + [ MOBX ] : 'MobX', + [ PROFILER ] : 'Profiler', +} + +const DOCS = [REDUX, VUE, GRAPHQL, NGRX, FETCH, MOBX, PROFILER] + +const integrations = [ 'sentry', 'datadog', 'stackdriver', 'rollbar', 'newrelic', 'bugsnag', 'cloudwatch', 'elasticsearch', 'sumologic', 'issues' ]; + +@connect(state => { + const props = {}; + integrations.forEach(name => { + props[ `${ name }Integrated`] = name === 'issues' ? + !!(state.getIn([ name, 'list' ]).first() && state.getIn([ name, 'list' ]).first().token) : + state.getIn([ name, 'list' ]).size > 0; + props.loading = props.loading || state.getIn([ name, 'fetchRequest', 'loading']); + }) + return { + ...props, + issues: state.getIn([ 'issues', 'list']).first() || {}, + slackChannelListExists: state.getIn([ 'slack', 'list' ]).size > 0, + tenantId: state.getIn([ 'user', 'client', 'tenantId' ]), + jwt: state.get('jwt') + }; +}, { + fetchList, + init, + fetchListSlack, + removeIntegrationConfig +}) +@withPageTitle('Integrations - OpenReplay Preferences') +export default class Integrations extends React.PureComponent { + state = { + modalContent: NONE, + showDetailContent: false, + }; + + componentWillMount() { + integrations.forEach(name => + this.props.fetchList(name) + ); + this.props.fetchListSlack(); + } + + onClickIntegrationItem = (e, url) => { + e.preventDefault(); + window.open(url); + } + + closeModal = () => this.setState({ modalContent: NONE, showDetailContent: false }); + + onOauthClick = (source) => { + if (source === GITHUB) { + const githubUrl = `https://auth.openreplay.com/oauth/login?provider=github&back_url=${document.location.href}`; + const options = { + method: 'GET', + credentials: 'include', + headers: new Headers({ + 'Authorization': 'Bearer ' + this.props.jwt.toString() + }) + }; + fetch(githubUrl, options).then((resp) => resp.text().then((txt) => window.open(txt, '_self'))) + } + } + + renderDetailContent() { + switch (this.state.modalContent) { + case SLACK: + return this.setState({ showDetailContent: false }) } />; + } + } + + renderModalContent() { + switch (this.state.modalContent) { + case SENTRY: + return ; + case GITHUB: + return ; + case SLACK: + return this.setState({ showDetailContent: true })} + /> + case DATADOG: + return ; + case STACKDRIVER: + return ; + case ROLLBAR: + return ; + case NEWRELIC: + return ; + case BUGSNAG: + return ; + case CLOUDWATCH: + return ; + case ELASTICSEARCH: + return ; + case SUMOLOGIC: + return ; + case JIRA: + return ; + case REDUX: + return + case VUE: + return + case GRAPHQL: + return + case NGRX: + return + case FETCH: + return + case MOBX: + return + case PROFILER: + return + default: + return null; + } + } + + deleteHandler = name => { + this.props.removeIntegrationConfig(name, null).then(function() { + this.props.fetchList(name) + }.bind(this)); + } + + showIntegrationConfig = (type) => { + this.setState({ modalContent: type }); + } + + render() { + const { + loading, + sentryIntegrated, + stackdriverIntegrated, + datadogIntegrated, + rollbarIntegrated, + newrelicIntegrated, + bugsnagIntegrated, + cloudwatchIntegrated, + elasticsearchIntegrated, + sumologicIntegrated, + hideHeader=false, + plugins=false, + jiraIntegrated, + issuesIntegrated, + tenantId, + slackChannelListExists, + issues, + } = this.props; + const { modalContent, showDetailContent } = this.state; + return ( +
+ +
{TITLE[ modalContent ]}
+ { modalContent === SLACK && ( + this.setState({ showDetailContent: true })} + /> + )} +
+ } + isDisplayed={ modalContent !== NONE } + onClose={ this.closeModal } + size={ DOCS.includes(this.state.modalContent) ? 'middle' : 'small' } + content={ this.renderModalContent() } + detailContent={ showDetailContent && this.renderDetailContent() } + /> + + {!hideHeader && ( +
+

{ 'Integrations' }

+

Power your workflow with your favourite tools.

+
+
+ )} + + {plugins && ( +
+
Use plugins to better debug your application's store, monitor queries and track performance issues.
+
+ this.showIntegrationConfig(REDUX) } + // integrated={ sentryIntegrated } + /> + this.showIntegrationConfig(VUE) } + // integrated={ sentryIntegrated } + /> + this.showIntegrationConfig(GRAPHQL) } + // integrated={ sentryIntegrated } + /> + this.showIntegrationConfig(NGRX) } + // integrated={ sentryIntegrated } + /> + + this.showIntegrationConfig(FETCH) } + // integrated={ sentryIntegrated } + /> + + this.showIntegrationConfig(MOBX) } + // integrated={ sentryIntegrated } + /> + + this.showIntegrationConfig(PROFILER) } + // integrated={ sentryIntegrated } + /> +
+
+ )} + + {!plugins && ( + +
+
+
How are you monitoring errors and crash reporting?
+
+ { + (!issues.token || issues.provider !== 'github') && + this.showIntegrationConfig(JIRA) } + integrated={ issuesIntegrated } + /> + } + { (!issues.token || issues.provider !== 'jira') && + this.showIntegrationConfig(GITHUB) } + integrated={ issuesIntegrated } + deleteHandler={issuesIntegrated ? () => this.deleteHandler('issues') : null} + /> + } + {/* this.showIntegrationConfig(GITHUB) } + integrated={ sentryIntegrated } + /> + this.showIntegrationConfig(JIRA) } + integrated={ sentryIntegrated } + /> */} + this.showIntegrationConfig(SLACK) } + integrated={ sentryIntegrated } + /> + this.showIntegrationConfig(SENTRY) } + integrated={ sentryIntegrated } + /> + + this.showIntegrationConfig(BUGSNAG) } + integrated={ bugsnagIntegrated } + /> + + this.showIntegrationConfig(ROLLBAR) } + integrated={ rollbarIntegrated } + /> + + this.showIntegrationConfig(ELASTICSEARCH) } + integrated={ elasticsearchIntegrated } + /> + + this.showIntegrationConfig(DATADOG) } + integrated={ datadogIntegrated } + /> + this.showIntegrationConfig(SUMOLOGIC) } + integrated={ sumologicIntegrated } + /> + this.showIntegrationConfig(STACKDRIVER) } + integrated={ stackdriverIntegrated } + /> + + this.showIntegrationConfig(CLOUDWATCH) } + integrated={ cloudwatchIntegrated } + /> + + this.showIntegrationConfig(NEWRELIC) } + integrated={ newrelicIntegrated } + /> +
+
+ + {/*
+
How are you logging backend errors?
+
+ +
+
*/} + {/* + + */} +
+
+ )} +
+ ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/JiraForm/JiraForm.js b/frontend/app/components/Client/Integrations/JiraForm/JiraForm.js new file mode 100644 index 000000000..278f89890 --- /dev/null +++ b/frontend/app/components/Client/Integrations/JiraForm/JiraForm.js @@ -0,0 +1,27 @@ +import IntegrationForm from '../IntegrationForm'; + +const JiraForm = (props) => ( + +); + +JiraForm.displayName = "JiraForm"; + +export default JiraForm; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/JiraForm/ProjectDropdown.js b/frontend/app/components/Client/Integrations/JiraForm/ProjectDropdown.js new file mode 100644 index 000000000..b41eb543e --- /dev/null +++ b/frontend/app/components/Client/Integrations/JiraForm/ProjectDropdown.js @@ -0,0 +1,67 @@ +import { connect } from 'react-redux'; +import { edit } from 'Duck/integrations/actions'; +import { Dropdown } from 'UI'; +import { withRequest } from 'HOCs'; + +@connect(state => ({ + config: state.getIn([ 'issues', 'list' ]) +}), { edit }) +@withRequest({ + dataName: "values", + initialData: [], + resetBeforeRequest: true, + requestName: "fetchProjects", + endpoint: '/integrations/issues/list_projects', + method: 'GET', +}) +export default class ProductDropdown extends React.PureComponent { + constructor(props) { + super(props); + this.fetchProjects() + } + fetchProjects() { + const { config } = this.props; + if (!config.validateFetchProjects()) return; + + this.props.fetchProjects().then(() => { + const { value, values, name } = this.props; + if (values && !values.includes(value) && values.length > 0) { + this.props.edit("jira", { + [ name ]: values[0].id, + }); + } + }); + } + componentDidUpdate(prevProps) { + const { config } = this.props; + if ((prevProps.config.url !== config.url || prevProps.config.apiToken !== config.apiToken) && config.validateFetchProjects()) { + this.fetchProjects(); + } + } + onChange = (e, target) => { + if (typeof this.props.onChange === 'function') { + this.props.onChange({ target }); + } + } + render() { + const { + values, + name, + value, + placeholder, + loading, + } = this.props; + const options = values ? values.map(g => ({ text: g.name, value: g.id })) : [] + return ( + + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/JiraForm/index.js b/frontend/app/components/Client/Integrations/JiraForm/index.js new file mode 100644 index 000000000..d914b3234 --- /dev/null +++ b/frontend/app/components/Client/Integrations/JiraForm/index.js @@ -0,0 +1 @@ +export { default } from './JiraForm'; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/MobxDoc/MobxDoc.js b/frontend/app/components/Client/Integrations/MobxDoc/MobxDoc.js new file mode 100644 index 000000000..f8ab34fa0 --- /dev/null +++ b/frontend/app/components/Client/Integrations/MobxDoc/MobxDoc.js @@ -0,0 +1,59 @@ +import Highlight from 'react-highlight' +import ToggleContent from '../../../shared/ToggleContent' + +const MobxDoc = (props) => { + return ( +
+
This plugin allows you to capture MobX events and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
+ +
Installation
+ + {`npm i @openreplay/tracker-mobx --save`} + + +
Usage
+

Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put the generated middleware into your Redux chain.

+
+ +
Usage
+ + {`import OpenReplay from '@openreplay/tracker'; +import trackerMobX from '@openreplay/tracker-mobx'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +tracker.use(trackerMobX()); // check list of available options below +tracker.start();`} + + } + second={ + + {`import OpenReplay from '@openreplay/tracker/cjs'; +import trackerMobX from '@openreplay/tracker-mobx/cjs'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +tracker.use(trackerMobX()); // check list of available options below +//... +function SomeFunctionalComponent() { + useEffect(() => { // or componentDidMount in case of Class approach + tracker.start(); + }, []) +}`} + + } + /> + +
See API for more options.
+
+ ) +}; + +MobxDoc.displayName = "MobxDoc"; + +export default MobxDoc; diff --git a/frontend/app/components/Client/Integrations/MobxDoc/index.js b/frontend/app/components/Client/Integrations/MobxDoc/index.js new file mode 100644 index 000000000..51b6dedae --- /dev/null +++ b/frontend/app/components/Client/Integrations/MobxDoc/index.js @@ -0,0 +1 @@ +export { default } from './MobxDoc' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/NewrelicForm/NewrelicForm.js b/frontend/app/components/Client/Integrations/NewrelicForm/NewrelicForm.js new file mode 100644 index 000000000..769a17551 --- /dev/null +++ b/frontend/app/components/Client/Integrations/NewrelicForm/NewrelicForm.js @@ -0,0 +1,30 @@ +import IntegrationForm from '../IntegrationForm'; + +const NewrelicForm = (props) => ( + <> +
+
How to integrate NewRelic with OpenReplay and see backend errors alongside session recordings.
+
See Documentation for more details.
+
+ + +); + +NewrelicForm.displayName = "NewrelicForm"; + +export default NewrelicForm; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/NewrelicForm/index.js b/frontend/app/components/Client/Integrations/NewrelicForm/index.js new file mode 100644 index 000000000..0d4052873 --- /dev/null +++ b/frontend/app/components/Client/Integrations/NewrelicForm/index.js @@ -0,0 +1 @@ +export { default } from './NewrelicForm'; diff --git a/frontend/app/components/Client/Integrations/NgRxDoc/NgRxDoc.js b/frontend/app/components/Client/Integrations/NgRxDoc/NgRxDoc.js new file mode 100644 index 000000000..d45498fb3 --- /dev/null +++ b/frontend/app/components/Client/Integrations/NgRxDoc/NgRxDoc.js @@ -0,0 +1,75 @@ +import Highlight from 'react-highlight' +import ToggleContent from '../../../shared/ToggleContent' + +const NgRxDoc = (props) => { + return ( +
+
This plugin allows you to capture NgRx actions/state and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
+ +
Installation
+ + {`npm i @openreplay/tracker-ngrx --save`} + + +
Usage
+

Add the generated meta-reducer into your imports. See NgRx documentation for more details.

+
+ +
Usage
+ + {`import { StoreModule } from '@ngrx/store'; +import { reducers } from './reducers'; +import OpenReplay from '@openreplay/tracker'; +import trackerNgRx from '@openreplay/tracker-ngrx'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +tracker.start(); +//... +const metaReducers = [tracker.use(trackerNgRx())]; // check list of available options below +//... +@NgModule({ + imports: [StoreModule.forRoot(reducers, { metaReducers })] +}) +export class AppModule {}`} + + } + second={ + + {`import { StoreModule } from '@ngrx/store'; +import { reducers } from './reducers'; +import OpenReplay from '@openreplay/tracker/cjs'; +import trackerNgRx from '@openreplay/tracker-ngrx/cjs'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +//... +function SomeFunctionalComponent() { + useEffect(() => { // or componentDidMount in case of Class approach + tracker.start(); + }, []) +//... +const metaReducers = [tracker.use(trackerNgRx())]; // check list of available options below +//... + @NgModule({ + imports: [StoreModule.forRoot(reducers, { metaReducers })] + }) + export class AppModule {} +}`} + + } + /> + +
See API for more options.
+
+ ) +}; + +NgRxDoc.displayName = "NgRxDoc"; + +export default NgRxDoc; diff --git a/frontend/app/components/Client/Integrations/NgRxDoc/index.js b/frontend/app/components/Client/Integrations/NgRxDoc/index.js new file mode 100644 index 000000000..65f97eed5 --- /dev/null +++ b/frontend/app/components/Client/Integrations/NgRxDoc/index.js @@ -0,0 +1 @@ +export { default } from './NgRxDoc' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/ProfilerDoc/ProfilerDoc.js b/frontend/app/components/Client/Integrations/ProfilerDoc/ProfilerDoc.js new file mode 100644 index 000000000..4a3e4a3d9 --- /dev/null +++ b/frontend/app/components/Client/Integrations/ProfilerDoc/ProfilerDoc.js @@ -0,0 +1,69 @@ +import Highlight from 'react-highlight' +import ToggleContent from '../../../shared/ToggleContent' + +const ProfilerDoc = (props) => { + return ( +
+
The profiler plugin allows you to measure your JS functions' performance and capture both arguments and result for each function call.
+ +
Installation
+ + {`npm i @openreplay/tracker-profiler --save`} + + +
Usage
+

Initialize the tracker and load the plugin into it. Then decorate any function inside your code with the generated function.

+
+ +
Usage
+ + {`import OpenReplay from '@openreplay/tracker'; +import trackerProfiler from '@openreplay/tracker-profiler'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +tracker.start(); +//... +export const profiler = tracker.use(trackerProfiler()); +//... +const fn = profiler('call_name')(() => { +//... +}, thisArg); // thisArg is optional`} + + } + second={ + + {`import OpenReplay from '@openreplay/tracker/cjs'; +import trackerProfiler from '@openreplay/tracker-profiler/cjs'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +//... +function SomeFunctionalComponent() { + useEffect(() => { // or componentDidMount in case of Class approach + tracker.start(); + }, []) +//... +export const profiler = tracker.use(trackerProfiler()); +//... +const fn = profiler('call_name')(() => { + //... + }, thisArg); // thisArg is optional +}`} + + } + /> + +
See API for more options.
+
+ ) +}; + +ProfilerDoc.displayName = "ProfilerDoc"; + +export default ProfilerDoc; diff --git a/frontend/app/components/Client/Integrations/ProfilerDoc/index.js b/frontend/app/components/Client/Integrations/ProfilerDoc/index.js new file mode 100644 index 000000000..5a3da5d09 --- /dev/null +++ b/frontend/app/components/Client/Integrations/ProfilerDoc/index.js @@ -0,0 +1 @@ +export { default } from './ProfilerDoc' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/ReduxDoc/ReduxDoc.js b/frontend/app/components/Client/Integrations/ReduxDoc/ReduxDoc.js new file mode 100644 index 000000000..a88fb4103 --- /dev/null +++ b/frontend/app/components/Client/Integrations/ReduxDoc/ReduxDoc.js @@ -0,0 +1,68 @@ +import Highlight from 'react-highlight' +import ToggleContent from '../../../shared/ToggleContent'; + +const ReduxDoc = (props) => { + return ( +
+
This plugin allows you to capture Redux actions/state and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
+ +
Installation
+ + {`npm i @openreplay/tracker-redux --save`} + + + +
Usage
+

Initialize the tracker then put the generated middleware into your Redux chain.

+
+ + {`import { applyMiddleware, createStore } from 'redux'; +import OpenReplay from '@openreplay/tracker'; +import trackerRedux from '@openreplay/tracker-redux'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +tracker.start(); +//... +const store = createStore( + reducer, + applyMiddleware(tracker.use(trackerRedux())) // check list of available options below +);`} + + } + second={ + + {`import { applyMiddleware, createStore } from 'redux'; +import OpenReplay from '@openreplay/tracker/cjs'; +import trackerRedux from '@openreplay/tracker-redux/cjs'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +//... +function SomeFunctionalComponent() { + useEffect(() => { // or componentDidMount in case of Class approach + tracker.start(); + }, []) +//... +const store = createStore( + reducer, + applyMiddleware(tracker.use(trackerRedux())) // check list of available options below + ); +}`} + + } + /> + +
See API for more options.
+
+ ) +}; + +ReduxDoc.displayName = "ReduxDoc"; + +export default ReduxDoc; diff --git a/frontend/app/components/Client/Integrations/ReduxDoc/index.js b/frontend/app/components/Client/Integrations/ReduxDoc/index.js new file mode 100644 index 000000000..3c6245bd8 --- /dev/null +++ b/frontend/app/components/Client/Integrations/ReduxDoc/index.js @@ -0,0 +1 @@ +export { default } from './ReduxDoc' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/RollbarForm.js b/frontend/app/components/Client/Integrations/RollbarForm.js new file mode 100644 index 000000000..87a2033e4 --- /dev/null +++ b/frontend/app/components/Client/Integrations/RollbarForm.js @@ -0,0 +1,23 @@ +import IntegrationForm from './IntegrationForm'; + +const RollbarForm = (props) => ( + <> +
+
How to integrate Rollbar with OpenReplay and see backend errors alongside session replays.
+
See Documentation for more details.
+
+ + +); + +RollbarForm.displayName = "RollbarForm"; + +export default RollbarForm; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/SentryForm.js b/frontend/app/components/Client/Integrations/SentryForm.js new file mode 100644 index 000000000..265767edf --- /dev/null +++ b/frontend/app/components/Client/Integrations/SentryForm.js @@ -0,0 +1,29 @@ +import IntegrationForm from './IntegrationForm'; + +const SentryForm = (props) => ( + <> +
+
How to integrate Sentry with OpenReplay and see backend errors alongside session recordings.
+
See Documentation for more details.
+
+ + +); + +SentryForm.displayName = "SentryForm"; + +export default SentryForm; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/SlackAddForm/SlackAddForm.js b/frontend/app/components/Client/Integrations/SlackAddForm/SlackAddForm.js new file mode 100644 index 000000000..754146a36 --- /dev/null +++ b/frontend/app/components/Client/Integrations/SlackAddForm/SlackAddForm.js @@ -0,0 +1,105 @@ +import React from 'react' +import { connect } from 'react-redux' +import { edit, save, init } from 'Duck/integrations/slack' +import { Form, Input, Button, Message } from 'UI' +import { confirm } from 'UI/Confirmation'; +import { remove } from 'Duck/integrations/slack' + +class SlackAddForm extends React.PureComponent { + + componentWillUnmount() { + this.props.init({}); + } + + save = () => { + this.props.save(this.props.instance).then(function() { + + }) + } + + remove = async (id) => { + if (await confirm({ + header: 'Confirm', + confirmButton: 'Yes, Delete', + confirmation: `Are you sure you want to permanently delete this channel?` + })) { + this.props.remove(id); + } + } + + write = ({ target: { name, value } }) => this.props.edit({ [ name ]: value }); + + render() { + const { instance, saving, errors, onClose } = this.props; + return ( +
+
+ + + + + + + + +
+
+ + + +
+ + +
+
+ + { errors && +
+ { errors.map(error => { error }) } +
+ } +
+ ) + } +} + +export default connect(state => ({ + instance: state.getIn(['slack', 'instance']), + saving: state.getIn(['slack', 'saveRequest', 'loading']), + errors: state.getIn([ 'slack', 'saveRequest', 'errors' ]), +}), { edit, save, init, remove })(SlackAddForm) \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/SlackAddForm/index.js b/frontend/app/components/Client/Integrations/SlackAddForm/index.js new file mode 100644 index 000000000..beb10bb6d --- /dev/null +++ b/frontend/app/components/Client/Integrations/SlackAddForm/index.js @@ -0,0 +1 @@ +export { default } from './SlackAddForm' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/SlackChannelList/SlackChannelList.js b/frontend/app/components/Client/Integrations/SlackChannelList/SlackChannelList.js new file mode 100644 index 000000000..88529ce58 --- /dev/null +++ b/frontend/app/components/Client/Integrations/SlackChannelList/SlackChannelList.js @@ -0,0 +1,51 @@ +import React from 'react' +import { connect } from 'react-redux' +import { TextEllipsis, NoContent } from 'UI'; +import { remove, edit } from 'Duck/integrations/slack' + +function SlackChannelList(props) { + const { list } = props; + + const onEdit = (instance) => { + props.edit(instance) + props.onEdit() + } + + return ( +
+ + {list.map(c => ( +
onEdit(c)} + > +
+
{c.name}
+ + {c.endpoint} +
+ } + /> +
+ {/*
+ +
*/} +
+ ))} + +
+ ) +} + +export default connect(state => ({ + list: state.getIn(['slack', 'list']) +}), { remove, edit })(SlackChannelList) diff --git a/frontend/app/components/Client/Integrations/SlackChannelList/index.js b/frontend/app/components/Client/Integrations/SlackChannelList/index.js new file mode 100644 index 000000000..d9709c104 --- /dev/null +++ b/frontend/app/components/Client/Integrations/SlackChannelList/index.js @@ -0,0 +1 @@ +export { default } from './SlackChannelList' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/SlackForm.js b/frontend/app/components/Client/Integrations/SlackForm.js new file mode 100644 index 000000000..9ae37fbf1 --- /dev/null +++ b/frontend/app/components/Client/Integrations/SlackForm.js @@ -0,0 +1,16 @@ +import IntegrationForm from './IntegrationForm'; +import SlackAddForm from './SlackAddForm'; +import SlackChannelList from './SlackChannelList/SlackChannelList'; + +const SlackForm = (props) => { + const { onEdit } = props; + return ( + <> + + + ) +} + +SlackForm.displayName = "SlackForm"; + +export default SlackForm; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/StackdriverForm.js b/frontend/app/components/Client/Integrations/StackdriverForm.js new file mode 100644 index 000000000..2dec6b4c8 --- /dev/null +++ b/frontend/app/components/Client/Integrations/StackdriverForm.js @@ -0,0 +1,27 @@ +import IntegrationForm from './IntegrationForm'; + +const StackdriverForm = (props) => ( + <> +
+
How to integrate Stackdriver with OpenReplay and see backend errors alongside session recordings.
+
See Documentation for more details.
+
+ + +); + +StackdriverForm.displayName = "StackdriverForm"; + +export default StackdriverForm; diff --git a/frontend/app/components/Client/Integrations/SumoLogicForm/RegionDropdown.js b/frontend/app/components/Client/Integrations/SumoLogicForm/RegionDropdown.js new file mode 100644 index 000000000..f0625d521 --- /dev/null +++ b/frontend/app/components/Client/Integrations/SumoLogicForm/RegionDropdown.js @@ -0,0 +1,18 @@ +import { regionLabels as labels } from 'Types/integrations/sumoLogicConfig'; +import { Dropdown } from 'UI'; + +const options = Object.keys(labels).map(key => ({ text: labels[ key ], value: key })); + +const RegionDropdown = props => ( + props.onChange({target})} + selection + options={ options } + /> +); + +RegionDropdown.displayName = "RegionDropdown"; + +export default RegionDropdown; + diff --git a/frontend/app/components/Client/Integrations/SumoLogicForm/SumoLogicForm.js b/frontend/app/components/Client/Integrations/SumoLogicForm/SumoLogicForm.js new file mode 100644 index 000000000..4a562d02b --- /dev/null +++ b/frontend/app/components/Client/Integrations/SumoLogicForm/SumoLogicForm.js @@ -0,0 +1,31 @@ +import IntegrationForm from '../IntegrationForm'; +import RegionDropdown from './RegionDropdown'; + +const SumoLogicForm = (props) => ( + <> +
+
How to integrate SumoLogic with OpenReplay and see backend errors alongside session recordings.
+
See Documentation for more details.
+
+ + +); + +SumoLogicForm.displayName = "SumoLogicForm"; + +export default SumoLogicForm; diff --git a/frontend/app/components/Client/Integrations/SumoLogicForm/index.js b/frontend/app/components/Client/Integrations/SumoLogicForm/index.js new file mode 100644 index 000000000..1edc0164c --- /dev/null +++ b/frontend/app/components/Client/Integrations/SumoLogicForm/index.js @@ -0,0 +1 @@ +export { default } from './SumoLogicForm'; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/VueDoc/VueDoc.js b/frontend/app/components/Client/Integrations/VueDoc/VueDoc.js new file mode 100644 index 000000000..f370a5f80 --- /dev/null +++ b/frontend/app/components/Client/Integrations/VueDoc/VueDoc.js @@ -0,0 +1,69 @@ +import Highlight from 'react-highlight' +import ToggleContent from '../../../shared/ToggleContent'; + +const VueDoc = (props) => { + return ( +
+
This plugin allows you to capture VueX mutations/state and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
+ +
Installation
+ + {`npm i @openreplay/tracker-vuex --save`} + + +
Usage
+

Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put the generated plugin into your plugins field of your store.

+
+ + + + {`import Vuex from 'vuex' +import OpenReplay from '@openreplay/tracker'; +import trackerVuex from '@openreplay/tracker-vuex'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +tracker.start(); +//... +const store = new Vuex.Store({ + //... + plugins: [tracker.use(trackerVuex())] // check list of available options below +});`} + + } + second={ + + {`import Vuex from 'vuex' +import OpenReplay from '@openreplay/tracker/cjs'; +import trackerVuex from '@openreplay/tracker-vuex/cjs'; +//... +const tracker = new OpenReplay({ + projectKey: PROJECT_KEY +}); +//... +function SomeFunctionalComponent() { + useEffect(() => { // or componentDidMount in case of Class approach + tracker.start(); + }, []) +//... +const store = new Vuex.Store({ + //... + plugins: [tracker.use(trackerVuex())] // check list of available options below + }); +}`} + + } + /> + +
See API for more options.
+
+ ) +}; + +VueDoc.displayName = "VueDoc"; + +export default VueDoc; diff --git a/frontend/app/components/Client/Integrations/VueDoc/index.js b/frontend/app/components/Client/Integrations/VueDoc/index.js new file mode 100644 index 000000000..555e8acfb --- /dev/null +++ b/frontend/app/components/Client/Integrations/VueDoc/index.js @@ -0,0 +1 @@ +export { default } from './VueDoc' \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/_IntegrationItem .js_old b/frontend/app/components/Client/Integrations/_IntegrationItem .js_old new file mode 100644 index 000000000..6aebe13a3 --- /dev/null +++ b/frontend/app/components/Client/Integrations/_IntegrationItem .js_old @@ -0,0 +1,42 @@ +import React from 'react'; +import cn from 'classnames'; +import { Icon } from 'UI'; +import styles from './integrationItem.css'; + +const onDocLinkClick = (e, link) => { + e.stopPropagation(); + window.open(link, '_blank'); +} + +const IntegrationItem = ({ + deleteHandler = null, icon, url = null, title = '', description = '', onClick = null, dockLink = '', integrated = false +}) => { + return ( +
onClick(e, url) }> + +

{ title }

+

{ description }

+
+
+ {deleteHandler && ( +
+ + { 'Remove' } +
+ )} + { dockLink && ( +
onDocLinkClick(e, dockLink) }> + + { 'Documentation' } +
+ )} +
+ + { 'Integrated' } +
+
+
+ ) +}; + +export default IntegrationItem; diff --git a/frontend/app/components/Client/Integrations/index.js b/frontend/app/components/Client/Integrations/index.js new file mode 100644 index 000000000..1a6b7f6cb --- /dev/null +++ b/frontend/app/components/Client/Integrations/index.js @@ -0,0 +1 @@ +export { default } from './Integrations'; \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/integrationItem.css b/frontend/app/components/Client/Integrations/integrationItem.css new file mode 100644 index 000000000..94ab26726 --- /dev/null +++ b/frontend/app/components/Client/Integrations/integrationItem.css @@ -0,0 +1,64 @@ +.wrapper { + border-radius: 3px; + /* border: solid thin $gray-light-shade; */ + margin-right: 10px; + padding: 20px; + cursor: pointer; + width: 130px; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + /* min-height: 250px; */ + /* min-width: 260px; */ + /* max-width: 300px; */ + + &:hover { + background-color: $active-blue; + } + + & .description { + font-weight: 300; + font-size: 12px; + } +} + +.externalIcon { + position: absolute; + right: 20px; + top: 20px; +} + +.footer { + display: flex; + align-items: center; + position: absolute; + bottom: 14px; + left: 20px; + justify-content: space-between; + right: 20px; +} + +.docsLink { + display: flex; + align-items: center; + color: $gray-medium; + &:hover { + text-decoration: underline; + } + &.hidden { + opacity: 0; + pointer-events: none; + } +} + +.integratedCheck { + display: flex; + align-items: center; + color: $teal; +} + +.integrated { + background-color: $active-blue; +} \ No newline at end of file diff --git a/frontend/app/components/Client/Integrations/integrations.css b/frontend/app/components/Client/Integrations/integrations.css new file mode 100644 index 000000000..fb7dcafa4 --- /dev/null +++ b/frontend/app/components/Client/Integrations/integrations.css @@ -0,0 +1,58 @@ +.tabHeader { + margin-bottom: 25px; + + & .tabTitle { + margin: 0 15px 0 0; + font-weight: 400 !important; + } + & .subText { + font-weight: 300; + color: $gray-medium; + padding: 5px 0; + } + & .divider { + height: 1px; + background-color: #DDDDDD; + } +} + +.sectionTitle { + margin: 10px 15px 15px 0; + font-weight: 400 !important; + display: flex; + align-items: center; + &>span:first-child { + padding-right: 10px; + }; +} + +.message { + color: $gray-light; + display: inline; + padding-left: 20px; +} + +.applicable { + padding-left: 15px; + font-size: 11px; + color: $gray-light; +} + +.requestNew { + min-width: 135px; + color: $gray-medium; + font-size: 12px; + display: flex; + align-items: center; + cursor: pointer; + text-decoration: underline; +} + +.content { + display: flex; + flex-wrap: wrap; + & > div { + margin-bottom: 20px; + margin-right: 20px; + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/ManageUsers/ManageUsers.js b/frontend/app/components/Client/ManageUsers/ManageUsers.js new file mode 100644 index 000000000..c8d1c633d --- /dev/null +++ b/frontend/app/components/Client/ManageUsers/ManageUsers.js @@ -0,0 +1,219 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import withPageTitle from 'HOCs/withPageTitle'; +import { IconButton, SlideModal, Input, Button, Loader, NoContent, Popup } from 'UI'; +import { init, save, edit, remove as deleteMember, fetchList } from 'Duck/member'; +import styles from './manageUsers.css'; +import UserItem from './UserItem'; +import { confirm } from 'UI/Confirmation'; +import { toast } from 'react-toastify'; + +const PERMISSION_WARNING = 'You don’t have the permissions to perform this action.'; +const LIMIT_WARNING = 'You have reached users limit.'; + +@connect(state => ({ + account: state.getIn([ 'user', 'account' ]), + members: state.getIn([ 'members', 'list' ]).filter(u => u.id), + member: state.getIn([ 'members', 'instance' ]), + errors: state.getIn([ 'members', 'saveRequest', 'errors' ]), + loading: state.getIn([ 'members', 'loading' ]), + saving: state.getIn([ 'members', 'saveRequest', 'loading' ]), +}), { + init, + save, + edit, + deleteMember, + fetchList +}) +@withPageTitle('Manage Users - OpenReplay Preferences') +class ManageUsers extends React.PureComponent { + state = { showModal: false, remaining: this.props.account.limits.teamMember.remaining } + + onChange = (e, { name, value }) => this.props.edit({ [ name ]: value }); + onChangeCheckbox = ({ target: { checked, name } }) => this.props.edit({ [ name ]: checked }); + setFocus = () => this.focusElement.focus(); + closeModal = () => this.setState({ showModal: false }); + componentWillMount = () => { + this.props.fetchList(); + } + + adminLabel = (user) => { + if (user.superAdmin) return 'Super Admin'; + return user.admin ? 'Admin' : ''; + }; + + editHandler = user => { + this.init(user) + } + + deleteHandler = async (user) => { + if (await confirm({ + header: 'Manage Users', + confirmation: `Are you sure you want to remove this user?` + })) { + this.props.deleteMember(user.id).then(() => { + const { remaining } = this.state; + if (remaining <= 0) return; + this.setState({ remaining: remaining - 1 }) + }); + } + } + + save = (e) => { + e.preventDefault(); + this.props.save(this.props.member) + .then(() => { + const { errors } = this.props; + if (errors && errors.size > 0) { + errors.forEach(e => { + toast.error(e); + }) + } + this.closeModal() + }); + } + + formContent = member => ( +
+
+
+ + { this.focusElement = ref; } } + name="name" + value={ member.name } + onChange={ this.onChange } + className={ styles.input } + id="name-field" + /> +
+ +
+ + +
+ +
+ +
{ 'Can manage Projects and Users.' }
+
+
+ + + +
+ ) + + init = (v) => { + this.props.init(v); + this.setState({ showModal: true }); + this.setFocus(); + } + + render() { + const { + members, member, loading, account, hideHeader = false, + } = this.props; + const { showModal, remaining } = this.state; + const isAdmin = account.admin || account.superAdmin; + const canAddUsers = isAdmin && remaining !== 0; + + return ( + + + +
+
+ { !hideHeader &&

{ (isAdmin ? 'Manage ' : '') + 'Users' }

} + { hideHeader &&

{ `Team Size ${members.size}` }

} + + this.init() } + /> +
+ } + // disabled={ canAddUsers } + content={ `${ !canAddUsers ? (!isAdmin ? PERMISSION_WARNING : LIMIT_WARNING) : 'Add team member' }` } + size="tiny" + inverted + position="top left" + /> +
+ + +
+ { + members.map(user => ( + + )) + } + + { !members.size > 0 && +
{ 'No Data.' }
+ } +
+
+
+ + + ); + } +} + +export default ManageUsers; diff --git a/frontend/app/components/Client/ManageUsers/UserItem.js b/frontend/app/components/Client/ManageUsers/UserItem.js new file mode 100644 index 000000000..078128c22 --- /dev/null +++ b/frontend/app/components/Client/ManageUsers/UserItem.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { Icon } from 'UI'; +import styles from './userItem.css'; + +const UserItem = ({ user, adminLabel, deleteHandler, editHandler }) => ( +
+ +
{ user.name || user.email }
+ { adminLabel &&
{ adminLabel }
} +
+ { !!deleteHandler && +
deleteHandler(user) } id="trash"> + +
+ } + { !!editHandler && +
editHandler(user) }> + +
+ } +
+
+); + +export default UserItem; diff --git a/frontend/app/components/Client/ManageUsers/index.js b/frontend/app/components/Client/ManageUsers/index.js new file mode 100644 index 000000000..64f58febe --- /dev/null +++ b/frontend/app/components/Client/ManageUsers/index.js @@ -0,0 +1 @@ +export { default } from './ManageUsers'; diff --git a/frontend/app/components/Client/ManageUsers/manageUsers.css b/frontend/app/components/Client/ManageUsers/manageUsers.css new file mode 100644 index 000000000..64e529d92 --- /dev/null +++ b/frontend/app/components/Client/ManageUsers/manageUsers.css @@ -0,0 +1,37 @@ +.tabHeader { + display: flex; + align-items: center; + margin-bottom: 25px; + + & .tabTitle { + margin: 0 15px 0 0; + font-weight: 400 !important; + } +} + +.form { + padding: 0 20px; + + & .formGroup { + margin-bottom: 15px; + } + & label { + display: block; + margin-bottom: 5px; + font-weight: 500; + } + + & .input { + width: 100%; + } + + & input[type=checkbox] { + margin-right: 10px; + height: 13px; + } +} + +.adminInfo { + font-size: 12px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/Client/ManageUsers/userItem.css b/frontend/app/components/Client/ManageUsers/userItem.css new file mode 100644 index 000000000..599aa34f1 --- /dev/null +++ b/frontend/app/components/Client/ManageUsers/userItem.css @@ -0,0 +1,44 @@ +@import 'mixins.css'; + +.wrapper { + padding: 15px 10px; + display: flex; + align-items: center; + border-bottom: solid thin $gray-light-shade; + + &:hover { + background-color: $active-blue; + transition: all 0.2s; + & .actions { + opacity: 1; + transition: all 0.4s; + } + } + + & .adminLabel { + margin-left: 10px; + padding: 0 10px; + border-radius: 3px; + background-color: $gray-lightest; + font-size: 12px; + border: solid thin $gray-light; + } +} + +.actions { + margin-left: auto; + /* opacity: 0; */ + transition: all 0.4s; + display: flex; + align-items: center; + & .button { + padding: 5px; + cursor: pointer; + margin-left: 10px; + &:hover { + & svg { + fill: $teal-dark; + } + } + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/Notifications/Notifications.js b/frontend/app/components/Client/Notifications/Notifications.js new file mode 100644 index 000000000..08db0a3b9 --- /dev/null +++ b/frontend/app/components/Client/Notifications/Notifications.js @@ -0,0 +1,45 @@ +import React, { useEffect } from 'react' +import cn from 'classnames' +import stl from './notifications.css' +import { Checkbox } from 'UI' +import { connect } from 'react-redux' +import { withRequest } from 'HOCs' +import { fetch as fetchConfig, edit as editConfig, save as saveConfig } from 'Duck/config' + +function Notifications(props) { + const { config } = props; + + useEffect(() => { + props.fetchConfig(); + }, []) + + const onChange = () => { + const _config = { 'weeklyReport' : !config.weeklyReport }; + props.editConfig(_config); + props.saveConfig(_config) + } + + return ( +
+
+ {

{ 'Notifications' }

} +
+
+ + +
+
+ ) +} + +export default connect(state => ({ + config: state.getIn(['config', 'options']) +}), { fetchConfig, editConfig, saveConfig })(Notifications) diff --git a/frontend/app/components/Client/Notifications/index.js b/frontend/app/components/Client/Notifications/index.js new file mode 100644 index 000000000..1dc1a1351 --- /dev/null +++ b/frontend/app/components/Client/Notifications/index.js @@ -0,0 +1 @@ +export { default } from './Notifications' \ No newline at end of file diff --git a/frontend/app/components/Client/Notifications/notifications.css b/frontend/app/components/Client/Notifications/notifications.css new file mode 100644 index 000000000..64e529d92 --- /dev/null +++ b/frontend/app/components/Client/Notifications/notifications.css @@ -0,0 +1,37 @@ +.tabHeader { + display: flex; + align-items: center; + margin-bottom: 25px; + + & .tabTitle { + margin: 0 15px 0 0; + font-weight: 400 !important; + } +} + +.form { + padding: 0 20px; + + & .formGroup { + margin-bottom: 15px; + } + & label { + display: block; + margin-bottom: 5px; + font-weight: 500; + } + + & .input { + width: 100%; + } + + & input[type=checkbox] { + margin-right: 10px; + height: 13px; + } +} + +.adminInfo { + font-size: 12px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/Client/PreferencesMenu/PreferencesMenu.js b/frontend/app/components/Client/PreferencesMenu/PreferencesMenu.js new file mode 100644 index 000000000..7e95d1daa --- /dev/null +++ b/frontend/app/components/Client/PreferencesMenu/PreferencesMenu.js @@ -0,0 +1,93 @@ +import React from 'react' +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { SideMenuitem } from 'UI' +import stl from './preferencesMenu.css'; +import { CLIENT_TABS, client as clientRoute } from 'App/routes'; +import { withRouter } from 'react-router-dom'; + +function PreferencesMenu({ activeTab, appearance, history }) { + + const setTab = (tab) => { + history.push(clientRoute(tab)); + } + + return ( +
+
+
+ Preferences +
+
+ +
+ setTab(CLIENT_TABS.PROFILE) } + /> +
+ +
+ setTab(CLIENT_TABS.INTEGRATIONS) } + /> +
+ +
+ setTab(CLIENT_TABS.CUSTOM_FIELDS) } + title="Metadata" + /> +
+ + { appearance.tests && appearance.runs && +
+ setTab(CLIENT_TABS.WEBHOOKS) } + /> +
+ } + +
+ setTab(CLIENT_TABS.SITES) } + /> +
+ +
+ setTab(CLIENT_TABS.MANAGE_USERS) } + /> +
+ +
+ setTab(CLIENT_TABS.NOTIFICATIONS) } + /> +
+
+ ) +} + +export default connect(state => ({ + appearance: state.getIn([ 'user', 'account', 'appearance' ]), +}))(withRouter(PreferencesMenu)); diff --git a/frontend/app/components/Client/PreferencesMenu/index.js b/frontend/app/components/Client/PreferencesMenu/index.js new file mode 100644 index 000000000..ecd18ce72 --- /dev/null +++ b/frontend/app/components/Client/PreferencesMenu/index.js @@ -0,0 +1 @@ +export { default } from './PreferencesMenu'; \ No newline at end of file diff --git a/frontend/app/components/Client/PreferencesMenu/preferencesMenu.css b/frontend/app/components/Client/PreferencesMenu/preferencesMenu.css new file mode 100644 index 000000000..818008fb8 --- /dev/null +++ b/frontend/app/components/Client/PreferencesMenu/preferencesMenu.css @@ -0,0 +1,35 @@ +.wrapper { + position: fixed; + top: 81px; + width: 200px; +} + +.header { + margin-bottom: 15px; + & .label { + text-transform: uppercase; + color: gray; + letter-spacing: 0.2em; + } + + & .manageButton { + margin-left: 5px; + font-size: 12px; + color: $teal; + cursor: pointer; + padding: 2px 5px; + border: solid thin transparent; + border-radius: 3px; + margin-bottom: -3px; + &:hover { + background-color: $gray-light; + color: $gray-darkest; + } + } +} + +.divider { + height: 1px; + width: 100%; + background-color: $gray-light; +} \ No newline at end of file diff --git a/frontend/app/components/Client/ProfileSettings/Api.js b/frontend/app/components/Client/ProfileSettings/Api.js new file mode 100644 index 000000000..fe648c2ae --- /dev/null +++ b/frontend/app/components/Client/ProfileSettings/Api.js @@ -0,0 +1,51 @@ +// TODO this can be deleted +import copy from 'copy-to-clipboard'; +import { connect } from 'react-redux'; +import styles from './profileSettings.css'; + +@connect(state => ({ + apiKey: state.getIn([ 'user', 'client', 'apiKey' ]), + loading: state.getIn([ 'user', 'updateAccountRequest', 'loading' ]) || + state.getIn([ 'user', 'putClientRequest', 'loading' ]), +})) +export default class Api extends React.PureComponent { + state = { copied: false } + + copyHandler = () => { + const { apiKey } = this.props; + this.setState({ copied: true }); + copy(apiKey); + setTimeout(() => { + this.setState({ copied: false }); + }, 1000); + }; + + render() { + const { apiKey } = this.props; + const { copied } = this.state; + + return ( +
+
+ +
+ +
+ { copied ? 'copied' : 'copy' } +
+
+
+
+ ); + } +} diff --git a/frontend/app/components/Client/ProfileSettings/ChangePassword.js b/frontend/app/components/Client/ProfileSettings/ChangePassword.js new file mode 100644 index 000000000..c213024d2 --- /dev/null +++ b/frontend/app/components/Client/ProfileSettings/ChangePassword.js @@ -0,0 +1,133 @@ +import { connect } from 'react-redux'; +import { Button, Message } from 'UI'; +import styles from './profileSettings.css'; +import { updatePassword } from 'Duck/user'; + +const ERROR_DOESNT_MATCH = "Passwords doesn't match"; +const MIN_LENGTH = 8; +const PASSWORD_POLICY = `Password should contain at least ${ MIN_LENGTH } symbols`; +const checkDoesntMatch = (newPassword, newPasswordRepeat) => newPasswordRepeat.length > 0 && newPasswordRepeat !== newPassword; + +const defaultState = { + oldPassword: '', + newPassword: '', + newPasswordRepeat: '', + success: false, +}; +@connect(state => ({ + passwordErrors: state.getIn(['user', 'passwordErrors']), + loading: state.getIn(['user', 'updatePasswordRequest', 'loading']) +}), { + updatePassword +}) +export default class ChangePassword extends React.PureComponent { + state = defaultState + + write = ({ target: { name, value } }) => { + this.setState({ + [ name ]: value, + }); + } + + handleSubmit = (e) => { + e.preventDefault(); + if (this.isSubmitDisabled()) return; + + const { oldPassword, newPassword } = this.state; + this.setState({ + success: false, + }); + + this.props.updatePassword({ + oldPassword, + newPassword, + }).then(() => { + if (this.props.passwordErrors.size === 0) { + this.setState({ + ...defaultState, + success: true, + }); + } + }); + } + + isSubmitDisabled() { + const { oldPassword, newPassword, newPasswordRepeat } = this.state; + if (newPassword !== newPasswordRepeat || + newPassword.length < MIN_LENGTH || + oldPassword.length < MIN_LENGTH) return true; + return false; + } + + render() { + const { + oldPassword, newPassword, newPasswordRepeat, success + } = this.state; + const { loading, passwordErrors } = this.props; + + const doesntMatch = checkDoesntMatch(newPassword, newPasswordRepeat); + return ( +
+
+ + +
+
+ + +
+ { PASSWORD_POLICY } +
+
+
+ + +
+ { passwordErrors.map(err => ( + + { err } + + ))} + +
+ + ); + } +} diff --git a/frontend/app/components/Client/ProfileSettings/index.js b/frontend/app/components/Client/ProfileSettings/index.js new file mode 100644 index 000000000..93688ca34 --- /dev/null +++ b/frontend/app/components/Client/ProfileSettings/index.js @@ -0,0 +1 @@ +export { default } from './ProfileSettings'; diff --git a/frontend/app/components/Client/ProfileSettings/profileSettings.css b/frontend/app/components/Client/ProfileSettings/profileSettings.css new file mode 100644 index 000000000..a5491ed24 --- /dev/null +++ b/frontend/app/components/Client/ProfileSettings/profileSettings.css @@ -0,0 +1,39 @@ + +.left { + padding: 40px; + width: 320px; + & .info { + color: $gray-medium; + font-weight: 300; + } +} + +.form { + margin-top: 30px; + width: 350px; + & .formGroup { + display: flex; + flex-direction: column; + margin-bottom: 25px; + & label { + font-weight: 500 !important; + margin-bottom: 3px; + } + + & input { + background-color: white; + padding: 8px 10px; + border: 1px solid #ddd; + border-radius: 4px; + &:read-only { + background-color: $gray-lightest; + } + } + } +} + +.passwordPolicy { + color: $gray-medium; + padding: 5px 0 10px; + font-size: 13px; +} diff --git a/frontend/app/components/Client/Sites/BlockedIps.js b/frontend/app/components/Client/Sites/BlockedIps.js new file mode 100644 index 000000000..c5ba4be44 --- /dev/null +++ b/frontend/app/components/Client/Sites/BlockedIps.js @@ -0,0 +1,31 @@ +import React from 'react'; +import { Input, Button, Icon } from 'UI'; +import styles from './blockedIps.css'; + +class BlockedIps extends React.PureComponent { + render() { + return ( +
+

{ 'Block IP' }

+
+ +
+ + +
+ +
+
+
{ '192.128.2.1' }
+
+ +
+
+
+
+
+ ); + } +} + +export default BlockedIps; diff --git a/frontend/app/components/Client/Sites/GDPRForm.js b/frontend/app/components/Client/Sites/GDPRForm.js new file mode 100644 index 000000000..6e52c9962 --- /dev/null +++ b/frontend/app/components/Client/Sites/GDPRForm.js @@ -0,0 +1,135 @@ +import { connect } from 'react-redux'; +import { Button, Select, Input, Icon } from 'UI'; +import { editGDPR, saveGDPR } from 'Duck/site'; +import { validateNumber } from 'App/validate'; +import styles from './siteForm.css'; + +const inputModeOptions = [ + { text: 'Record all inputs', value: 'plain' }, + { text: 'Ignore all inputs', value: 'obscured' }, + { text: 'Obscure all inputs', value: 'hidden' }, +]; + +@connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), + gdpr: state.getIn([ 'site', 'instance', 'gdpr' ]), + saving: state.getIn([ 'site', 'saveGDPR', 'loading' ]), +}), { + editGDPR, + saveGDPR, +}) +export default class GDPRForm extends React.PureComponent { + onChange = ({ target: { name, value } }) => { + if (name === "sampleRate") { + if (!validateNumber(value, { min: 0, max: 100 })) return; + if (value.length > 1 && value[0] === "0") { + value = value.slice(1); + } + } + this.props.editGDPR({ [ name ]: value }); + } + + onSampleRateBlur = ({ target: { name, value } }) => { //TODO: editState hoc + if (value === ''){ + this.props.editGDPR({ sampleRate: 100 }); + } + } + + onChangeSelect = (event, { name, value }) => { + this.props.editGDPR({ [ name ]: value }); + }; + + onChangeOption = ({ target: { checked, name } }) => { + this.props.editGDPR({ [ name ]: checked }); + } + + onSubmit = (e) => { + e.preventDefault(); + const { site, gdpr } = this.props; + this.props.saveGDPR(site.id, gdpr); + } + + render() { + const { + site, onClose, saving, gdpr, + } = this.props; + + return ( +
+
+
+ +
{ site.host }
+
+
+ + +
+ +
+ + + { 'Do not record any numeric text' } +
{ 'If enabled, OpenReplay will not record or store any numeric text for all sessions.' }
+ +
+ +
+ +
+ +
+
+ { 'Block IP' } +
+
+
+ +
+
+
+ ); + } +} diff --git a/frontend/app/components/Client/Sites/NewSiteForm.js b/frontend/app/components/Client/Sites/NewSiteForm.js new file mode 100644 index 000000000..dfb8087fe --- /dev/null +++ b/frontend/app/components/Client/Sites/NewSiteForm.js @@ -0,0 +1,82 @@ +import { connect } from 'react-redux'; +import { Input, Button, Label } from 'UI'; +import { save, edit, update , fetchList } from 'Duck/site'; +import { pushNewSite } from 'Duck/user'; +import styles from './siteForm.css'; + +@connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), + sites: state.getIn([ 'site', 'list' ]), + siteList: state.getIn([ 'site', 'list' ]), + loading: state.getIn([ 'site', 'save', 'loading' ]), +}), { + save, + edit, + update, + pushNewSite, + fetchList +}) +export default class NewSiteForm extends React.PureComponent { + state = { + existsError: false, + } + + onSubmit = e => { + e.preventDefault(); + const { site, siteList } = this.props; + if (!site.exists() && siteList.some(({ name }) => name === site.name)) { + return this.setState({ existsError: true }); + } + if (site.exists()) { + this.props.update(this.props.site, this.props.site.id).then(() => { + this.props.onClose(null) + this.props.fetchList(); + }) + } else { + this.props.save(this.props.site).then(() => { + const { sites } = this.props; + this.props.onClose(null, sites.last()) + }); + } + } + + edit = ({ target: { name, value } }) => { + if (value.includes(' ')) return; // TODO: site validation + this.setState({ existsError: false }); + this.props.edit({ [ name ]: value }); + } + + render() { + const { site, loading, onClose } = this.props; + return ( +
+
+
+ + +
+
+
+ { this.state.existsError && +
+ { "Site exists already. Please choose another one." } +
+ } +
+
+ ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/Sites/Sites.js b/frontend/app/components/Client/Sites/Sites.js new file mode 100644 index 000000000..ac02268ab --- /dev/null +++ b/frontend/app/components/Client/Sites/Sites.js @@ -0,0 +1,219 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import withPageTitle from 'HOCs/withPageTitle'; +import { Loader, SlideModal, IconButton, Icon, Button, Popup, TextLink } from 'UI'; +import { init, remove, fetchGDPR } from 'Duck/site'; +import { RED, YELLOW, GREEN, STATUS_COLOR_MAP } from 'Types/site'; +import stl from './sites.css'; +import NewSiteForm from './NewSiteForm'; +import GDPRForm from './GDPRForm'; +import TrackingCodeModal from 'Shared/TrackingCodeModal'; +import BlockedIps from './BlockedIps'; +import { confirm } from 'UI/Confirmation'; + +const STATUS_MESSAGE_MAP = { + [ RED ]: ' There seems to be an issue (please verify your installation)', + [ YELLOW ]: 'We\'re collecting data from time to time (perhaps low traffic)', + [ GREEN ]: 'All good!', +}; + +const PERMISSION_WARNING = 'You don’t have the permissions to perform this action.'; +const LIMIT_WARNING = 'You have reached site limit.'; + +const BLOCKED_IPS = 'BLOCKED_IPS'; +const NONE = 'NONE'; + +const NEW_SITE_FORM = 'NEW_SITE_FORM'; +const GDPR_FORM = 'GDPR_FORM'; + +@connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), + sites: state.getIn([ 'site', 'list' ]), + loading: state.getIn([ 'site', 'loading' ]), + user: state.getIn([ 'user', 'account' ]), + account: state.getIn([ 'user', 'account' ]), +}), { + init, + remove, + fetchGDPR +}) +@withPageTitle('Sites - OpenReplay Preferences') +class Sites extends React.PureComponent { + state = { + showTrackingCode: false, + modalContent: NONE, + detailContent: NONE, + }; + + toggleBlockedIp = () => { + this.setState({ + detailContent: this.state.detailContent === BLOCKED_IPS ? NONE : BLOCKED_IPS, + }); + }; + + closeModal = () => this.setState({ modalContent: NONE, detailContent: NONE }); + + edit = site => { + this.props.init(site) + this.setState({ modalContent: NEW_SITE_FORM }); + } + + remove = async (site) => { + if (await confirm({ + header: 'Projects', + confirmation: `Are you sure you want to delete this Project? We won't be able to record anymore sessions.` + })) { + this.props.remove(site.id); + } + }; + + showGDPRForm = (site) => { + this.props.init(site); + this.setState({ modalContent: GDPR_FORM }); + }; + + showNewSiteForm = () => { + this.props.init(); + this.setState({ modalContent: NEW_SITE_FORM }); + }; + + showTrackingCode = (site) => { + this.props.init(site); + this.setState({ showTrackingCode: true }); + }; + + getModalTitle() { + switch (this.state.modalContent) { + case NEW_SITE_FORM: + return 'New Project'; + case GDPR_FORM: + return 'Project Settings'; + default: + return ''; + } + } + + renderModalContent() { + switch (this.state.modalContent) { + case NEW_SITE_FORM: + return ; + case GDPR_FORM: + return + default: + return null; + } + } + + renderModalDetailContent() { + switch (this.state.detailContent) { + case BLOCKED_IPS: + return ; + default: + return null; + } + } + + render() { + const { loading, sites, site, user, account } = this.props; + const { modalContent, showTrackingCode } = this.state; + const isAdmin = user.admin || user.superAdmin; + const canAddSites = isAdmin && account.limits.projects && account.limits.projects.remaining !== 0; + const canDeleteSites = sites.size > 1; + + return ( + + this.setState({ showTrackingCode: false }) } + site={ site } + /> + +
+
+

{ 'Projects' }

+ + +
+ } + disabled={ canAddSites } + content={ `${ !isAdmin ? PERMISSION_WARNING : LIMIT_WARNING }` } + size="tiny" + inverted + position="top left" + /> + + +
+ +
+ { + sites.map(_site => ( +
+
+ + +
+ } + content={ STATUS_MESSAGE_MAP[ _site.status ] } + inverted + position="top center" + /> +
+
{ _site.host }
+
{_site.projectKey}
+
+
+
+ + +
+ {/* */} +
+
+ )) + } +
+
+ + ); + } +} + +export default Sites; diff --git a/frontend/app/components/Client/Sites/blockedIps.css b/frontend/app/components/Client/Sites/blockedIps.css new file mode 100644 index 000000000..1099d8835 --- /dev/null +++ b/frontend/app/components/Client/Sites/blockedIps.css @@ -0,0 +1,37 @@ +.wrapper { + width: 300px; + padding: 20px; + & label { + color: $gray-medium; + font-size: 12px; + } +} + +.inputWrapper { + display: flex; + align-items: center; + justify-content: space-between; +} + +.list { + margin-top: 20px; + display: none; /* TODO enable this once the API is Ready */ + & .item { + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: solid thin $gray-light; + padding: 8px 5px; + + &:hover { + background-color: $active-blue; + & .actions { + opacity: 1; + } + } + + & .actions { + opacity: 0; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/Sites/index.js b/frontend/app/components/Client/Sites/index.js new file mode 100644 index 000000000..8ca673fb0 --- /dev/null +++ b/frontend/app/components/Client/Sites/index.js @@ -0,0 +1 @@ +export { default } from './Sites'; diff --git a/frontend/app/components/Client/Sites/siteForm.css b/frontend/app/components/Client/Sites/siteForm.css new file mode 100644 index 000000000..08e50ce0d --- /dev/null +++ b/frontend/app/components/Client/Sites/siteForm.css @@ -0,0 +1,68 @@ +.formWrapper { + position: relative; + height: calc(100vh - 59px); + + & .content { + padding: 0 20px; + } + + & .formGroup { + display: flex; + flex-direction: column; + margin-bottom: 15px; + + & label { + font-weight: 500; + margin-bottom: 8px; + } + + & input { + background-color: white; + padding: 8px 10px; + border: 1px solid #ddd; + border-radius: 4px; + } + + & input[type=checkbox] { + margin-right: 10px; + } + + & .controlSubtext { + padding-left: 23px; + font-size:12px; + color: $gray-medium; + line-height: 14px; + font-weight: 400; + } + } + + & .footer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 10px; + box-shadow: 0px -3px 8px 0px rgba(0, 0, 0, 0.08); + } +} + +.sampleRate { + width: 90px; +} + +.blockIpWarapper { + & .button { + padding: 8px 10px; + border: solid thin $teal; + border-radius: 3px; + display: flex; + justify-content: space-between; + cursor: pointer; + } +} + +.errorMessage { + color: $red; + font-size: 12px; + font-weight: 500; +} \ No newline at end of file diff --git a/frontend/app/components/Client/Sites/sites.css b/frontend/app/components/Client/Sites/sites.css new file mode 100644 index 000000000..fecd7238c --- /dev/null +++ b/frontend/app/components/Client/Sites/sites.css @@ -0,0 +1,53 @@ +@import 'mixins.css'; + +.tabHeader { + display: flex; + align-items: center; + margin-bottom: 25px; + + & .tabTitle { + margin: 0 15px 0 0; + font-weight: 400 !important; + } +} + +.site { + padding: 15px 10px; + border-bottom: solid thin $gray-light-shade; + + display: flex; + align-items: center; + + &:hover { + & .actions button { + display: unset; + } + } + + & .actions { + margin-left: auto; + display: flex; + align-items: center; + justify-content: flex-end; + + & > * { + margin-left: 15px; + } + + & button { + &:disabled { + opacity: 0.3; + } + } + } +} + + +.label { + margin-left: 10px; + padding: 2px 10px; + border-radius: 3px; + background-color: $gray-lightest; + font-size: 12px; + border: solid thin $gray-light; +} \ No newline at end of file diff --git a/frontend/app/components/Client/TabItem.js b/frontend/app/components/Client/TabItem.js new file mode 100644 index 000000000..ec40037b3 --- /dev/null +++ b/frontend/app/components/Client/TabItem.js @@ -0,0 +1,15 @@ +import { Icon } from 'UI'; +import styles from './client.css'; + +const TabItem = ({ active = false, onClick, icon, label }) => { + return ( +
  • + + + { label } + +
  • + ); +}; + +export default TabItem; diff --git a/frontend/app/components/Client/Webhooks/ListItem.js b/frontend/app/components/Client/Webhooks/ListItem.js new file mode 100644 index 000000000..c14265dc9 --- /dev/null +++ b/frontend/app/components/Client/Webhooks/ListItem.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from 'UI'; +import styles from './listItem.css'; + +const ListItem = ({ webhook, onEdit, onDelete }) => { + return ( +
    +
    + { webhook.name } +
    { webhook.endpoint }
    +
    +
    +
    { e.stopPropagation(); onDelete(webhook) } }> + +
    +
    + +
    +
    +
    + ); +}; + +export default ListItem; \ No newline at end of file diff --git a/frontend/app/components/Client/Webhooks/WebhookForm.js b/frontend/app/components/Client/Webhooks/WebhookForm.js new file mode 100644 index 000000000..5aa991a14 --- /dev/null +++ b/frontend/app/components/Client/Webhooks/WebhookForm.js @@ -0,0 +1,83 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { edit, save } from 'Duck/webhook'; +import { Form, Button } from 'UI'; +import styles from './webhookForm.css'; + +@connect(state => ({ + webhook: state.getIn(['webhooks', 'instance']), + loading: state.getIn(['webhooks', 'saveRequest', 'loading']), +}), { + edit, + save, +}) +class WebhookForm extends React.PureComponent { + setFocus = () => this.focusElement.focus(); + onChangeSelect = (event, { name, value }) => this.props.edit({ [ name ]: value }); + write = ({ target: { value, name } }) => this.props.edit({ [ name ]: value }); + + save = () => { + this.props.save(this.props.webhook).then(() => { + this.props.onClose(); + }); + }; + + render() { + const { webhook, loading } = this.props; + return ( +
    + + + { this.focusElement = ref; } } + name="name" + value={ webhook.name } + onChange={ this.write } + placeholder="Name" + /> + + + + + { this.focusElement = ref; } } + name="endpoint" + value={ webhook.endpoint } + onChange={ this.write } + placeholder="Endpoint" + /> + + + + + { this.focusElement = ref; } } + name="authHeader" + value={ webhook.authHeader } + onChange={ this.write } + placeholder="Auth Header" + /> + + + + +
    + ); + } +} + +export default WebhookForm; diff --git a/frontend/app/components/Client/Webhooks/Webhooks.js b/frontend/app/components/Client/Webhooks/Webhooks.js new file mode 100644 index 000000000..61d30345e --- /dev/null +++ b/frontend/app/components/Client/Webhooks/Webhooks.js @@ -0,0 +1,81 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import withPageTitle from 'HOCs/withPageTitle'; +import { IconButton, SlideModal, Loader, NoContent } from 'UI'; +import { init, fetchList, remove } from 'Duck/webhook'; +import WebhookForm from './WebhookForm'; +import ListItem from './ListItem'; +import styles from './webhooks.css'; + +@connect(state => ({ + webhooks: state.getIn(['webhooks', 'list']), + loading: state.getIn(['webhooks', 'loading']), +}), { + init, + fetchList, + remove, +}) +@withPageTitle('Webhooks - OpenReplay Preferences') +class Webhooks extends React.PureComponent { + state = { showModal: false }; + + componentWillMount() { + this.props.fetchList(); + } + + closeModal = () => this.setState({ showModal: false }); + init = (v) => { + this.props.init(v); + this.setState({ showModal: true }); + } + + removeWebhook = id => { + const sure = window.confirm("Are you sure you want to remove this webhook?"); + if (!sure) return; + this.props.remove(id); + } + + render() { + const { webhooks, loading } = this.props; + const { showModal } = this.state; + + const noSlackWebhooks = webhooks.filter(hook => hook.type !== 'slack'); + return ( +
    + } + onClose={ this.closeModal } + /> +
    +

    { 'Webhooks' }

    + this.init() } /> +
    + + + +
    + { noSlackWebhooks.map(webhook => ( + this.init(webhook) } + onDelete={ () => this.removeWebhook(webhook.webhookId) } + /> + ))} +
    +
    +
    +
    + ); + } +} + +export default Webhooks; \ No newline at end of file diff --git a/frontend/app/components/Client/Webhooks/index.js b/frontend/app/components/Client/Webhooks/index.js new file mode 100644 index 000000000..beb5f4106 --- /dev/null +++ b/frontend/app/components/Client/Webhooks/index.js @@ -0,0 +1 @@ +export { default } from './Webhooks'; \ No newline at end of file diff --git a/frontend/app/components/Client/Webhooks/listItem.css b/frontend/app/components/Client/Webhooks/listItem.css new file mode 100644 index 000000000..33a5c1d2d --- /dev/null +++ b/frontend/app/components/Client/Webhooks/listItem.css @@ -0,0 +1,53 @@ + +@import 'mixins.css'; + +.wrapper { + display: flex; + padding: 15px 10px; + border-bottom: solid thin $gray-light; + transition: all 0.4s; + align-items: center; + + &:hover { + background-color: $active-blue; + transition: all 0.2s; + & .actions { + opacity: 1; + transition: all 0.4s; + } + } +} + +.actions { + margin-left: auto; + opacity: 0; + transition: all 0.4s; + display: flex; + align-items: center; + & .button { + padding: 5px; + cursor: pointer; + margin-left: 10px; + &:hover { + & svg { + fill: $teal-dark; + } + } + } +} + +.tag { + margin-left: 10px; + font-size: 12px; + padding: 2px 10px; + border-radius: 10px; + background-color: $gray-lightest; + box-shadow: 0 0 0 1px $gray-light inset; +} + +.endpoint { + font-weight: 300; + font-size: 12px; + color: $gray-medium; + margin-top: 5px; +} \ No newline at end of file diff --git a/frontend/app/components/Client/Webhooks/webhookForm.css b/frontend/app/components/Client/Webhooks/webhookForm.css new file mode 100644 index 000000000..05beaeb73 --- /dev/null +++ b/frontend/app/components/Client/Webhooks/webhookForm.css @@ -0,0 +1,3 @@ +.wrapper { + padding: 0 20px; +} \ No newline at end of file diff --git a/frontend/app/components/Client/Webhooks/webhooks.css b/frontend/app/components/Client/Webhooks/webhooks.css new file mode 100644 index 000000000..718a256f3 --- /dev/null +++ b/frontend/app/components/Client/Webhooks/webhooks.css @@ -0,0 +1,12 @@ +@import 'mixins.css'; + +.tabHeader { + display: flex; + align-items: center; + margin-bottom: 25px; + + & .tabTitle { + margin: 0 15px 0 0; + font-weight: 400 !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Client/client.css b/frontend/app/components/Client/client.css new file mode 100644 index 000000000..871d0e269 --- /dev/null +++ b/frontend/app/components/Client/client.css @@ -0,0 +1,66 @@ +@import 'mixins.css'; + +.wrapper { + margin-top: -30px; +} + +.main { + max-height: 100%; + display: flex; + min-height: calc(100vh - 51px); + + & .tabMenu { + width: 240px; + margin: 0; + background-color: $gray-lightest; + } + + & .tabContent { + background-color: white; + padding: 25px; + margin-top: -30px; + margin-right: -20px; + width: 100%; + } +} + +.form { + width: 350px; + + & .formGroup { + margin-bottom: 25px; + + & .label { + margin-bottom: 3px; + font-weight: 500; + } + } + + & p { + margin: 0; + margin-top: 10px; + } + + & input { + display: inline-block; + width: 100%; + border: $gray-light solid 1px; + border-radius: 4px; + background: $white; + padding: 10px 8px !important; + &:focus { + border-color: $teal !important; + } + } + + & .submit { + margin-top: 20px; + } + + &:after { + content: ''; + display: block; + clear: both; + } +} + diff --git a/frontend/app/components/Dashboard/AddWidgets.js b/frontend/app/components/Dashboard/AddWidgets.js new file mode 100644 index 000000000..72c3731e4 --- /dev/null +++ b/frontend/app/components/Dashboard/AddWidgets.js @@ -0,0 +1,90 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import withToggle from 'HOCs/withToggle'; +import { IconButton, SlideModal, NoContent } from 'UI'; +import { updateAppearance } from 'Duck/user'; +import { WIDGET_LIST } from 'Types/dashboard'; +import stl from './addWidgets.css'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; + +@connect(state => ({ + appearance: state.getIn([ 'user', 'account', 'appearance' ]), +}), { + updateAppearance, +}) +@withToggle() +export default class AddWidgets extends React.PureComponent { + makeAddHandler = widgetKey => () => { + const { appearance } = this.props; + const newAppearance = appearance.setIn([ 'dashboard', widgetKey ], true); + this.props.switchOpen(false); + this.props.updateAppearance(newAppearance) + } + + render() { + const { appearance, disabled } = this.props; + const avaliableWidgets = WIDGET_LIST.filter(({ key, type }) => !appearance.dashboard[ key ] && type === this.props.type ); + + return ( +
    + this.props.switchOpen(false)}> + {this.props.open && +
    + {avaliableWidgets.map(w => ( +
    + {w.name} +
    + ))} +
    + } +
    + + + { avaliableWidgets.map(({ key, name, description, thumb }) => ( +
    +
    +
    +

    { name }

    +
    + +
    +
    + ))} + + } + onClose={ this.props.switchOpen } + /> + +
    + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Dashboard.js b/frontend/app/components/Dashboard/Dashboard.js new file mode 100644 index 000000000..ffbc87b41 --- /dev/null +++ b/frontend/app/components/Dashboard/Dashboard.js @@ -0,0 +1,252 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import withPageTitle from 'HOCs/withPageTitle'; +import { setPeriod, setPlatform, fetchMetadataOptions } from 'Duck/dashboard'; +import { NoContent } from 'UI'; +import { WIDGET_KEYS } from 'Types/dashboard'; + +import { + MissingResources, + SlowestResources, + DomBuildingTime, + ResourceLoadingTime, + ResponseTime, + ResponseTimeDistribution, + TimeToRender, + SessionsImpactedBySlowRequests, + MemoryConsumption, + CpuLoad, + FPS, + Crashes, + SlowestDomains, + ErrorsPerDomain, + CallWithErrors, + ErrorsByType, + ErrorsByOrigin, + ResourceLoadedVsResponseEnd, + ResourceLoadedVsVisuallyComplete, + SessionsAffectedByJSErrors, + BreakdownOfLoadedResources, + SpeedIndexLocation, + SessionsPerBrowser, + CallsErrors5xx, + CallsErrors4xx +} from './Widgets'; + +import SideMenuSection from './SideMenu/SideMenuSection'; +import styles from './dashboard.css'; +import WidgetSection from 'Shared/WidgetSection/WidgetSection'; +import OverviewWidgets from './Widgets/OverviewWidgets/OverviewWidgets'; +import WidgetHolder from './WidgetHolder/WidgetHolder'; +import MetricsFilters from 'Shared/MetricsFilters/MetricsFilters'; +import { withRouter } from 'react-router'; + +const OVERVIEW = 'overview'; +const PERFORMANCE = 'performance'; +const ERRORS_N_CRASHES = 'errors_n_crashes'; +const RESOURCES = 'resources'; + +const menuList = [ + { + key: OVERVIEW, + section: 'metrics', + icon: "info-square", + label: getStatusLabel(OVERVIEW), + active: status === OVERVIEW, + }, + { + key: ERRORS_N_CRASHES, + section: 'metrics', + icon: "exclamation-circle", + label: getStatusLabel(ERRORS_N_CRASHES), + active: status === ERRORS_N_CRASHES, + }, + { + key: PERFORMANCE, + section: 'metrics', + icon: "tachometer-slow", + label: getStatusLabel(PERFORMANCE), + active: status === PERFORMANCE, + }, + { + key: RESOURCES, + section: 'metrics', + icon: "collection", + label: getStatusLabel(RESOURCES), + active: status === RESOURCES, + }, + +]; + +function getStatusLabel(status) { + switch(status) { + case OVERVIEW: + return "Overview"; + case PERFORMANCE: + return "Performance"; + case ERRORS_N_CRASHES: + return "Errors"; + case RESOURCES: + return "Resources"; + default: + return ""; + } +} + +function isInViewport(el) { + const rect = el.getBoundingClientRect(); + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); +} + +@connect(state => ({ + period: state.getIn([ 'dashboard', 'period' ]), + comparing: state.getIn([ 'dashboard', 'comparing' ]), + platform: state.getIn([ 'dashboard', 'platform' ]), + dashboardAppearance: state.getIn([ 'user', 'account', 'appearance', 'dashboard' ]), +}), { setPeriod, setPlatform, fetchMetadataOptions }) +@withPageTitle('Metrics - OpenReplay') +@withRouter +export default class Dashboard extends React.PureComponent { + constructor(props) { + super(props) + this.list = {}; + menuList.forEach(item => { + this.list[item.key] = React.createRef(); + }); + props.fetchMetadataOptions(); + } + + state = { + rangeName: this.props.period.rangeName, + startDate: null, + endDate: null, + pageSection: 'metrics', + }; + + componentDidMount() { + const { history, location } = this.props; + // TODO check the hash navigato it + } + + onMenuItemClick = ({section, key}) => { + const { history, location } = this.props; + const path = location.pathname + '#' + key; + history.push(path); + this.setState({ pageSection: section }); + setTimeout(function() { + this.navigateHash(section, key); + }.bind(this), 10); + } + + navigateHash = (section, key) => { + const { history, location } = this.props; + + const element = this.list[key].current; + const offset = 110; + const bodyRect = document.body.getBoundingClientRect().top; + const elementRect = element.getBoundingClientRect().top; + const elementPosition = elementRect - bodyRect; + const offsetPosition = elementPosition - offset; + + const path = location.pathname + '#' + key; + history.push(path); + window.scrollTo({ + top: offsetPosition, + behavior: 'smooth' + }); + } + + render() { + const { dashboardAppearance, comparing } = this.props; + const { pageSection } = this.state; + + const noWidgets = WIDGET_KEYS + .filter(key => dashboardAppearance[ key ]) + .length === 0; + + return ( +
    +
    + +
    +
    +
    +
    + +
    +
    + + +
    + +
    +
    + + +
    + { dashboardAppearance.impactedSessionsByJsErrors && } + { dashboardAppearance.errorsPerDomains && } + { dashboardAppearance.errorsPerType && } + { dashboardAppearance.resourcesByParty && } + { dashboardAppearance.domainsErrors_4xx && } + { dashboardAppearance.domainsErrors_5xx && } + { dashboardAppearance.callsErrors && +
    + } +
    +
    + + +
    + { dashboardAppearance.speedLocation && } + { dashboardAppearance.crashes && } + { dashboardAppearance.pagesResponseTime && } + { dashboardAppearance.impactedSessionsBySlowPages && } + { dashboardAppearance.pagesResponseTimeDistribution && +
    + } + { dashboardAppearance.pagesDomBuildtime && } + { dashboardAppearance.timeToRender && } + { dashboardAppearance.memoryConsumption && } + { dashboardAppearance.cpu && } + { dashboardAppearance.slowestDomains && } + { dashboardAppearance.resourcesVsVisuallyComplete && } + { dashboardAppearance.fps && } + { dashboardAppearance.sessionsPerBrowser && } +
    +
    + + +
    + { dashboardAppearance.resourcesCountByType && } + { dashboardAppearance.resourcesLoadingTime && } + { dashboardAppearance.resourceTypeVsResponseEnd && } + { dashboardAppearance.missingResources && } + { dashboardAppearance.slowestResources && +
    + } +
    +
    +
    +
    +
    +
    +
    + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/DashboardHeader/DashboardHeader.css b/frontend/app/components/Dashboard/DashboardHeader/DashboardHeader.css new file mode 100644 index 000000000..bef1bd7f1 --- /dev/null +++ b/frontend/app/components/Dashboard/DashboardHeader/DashboardHeader.css @@ -0,0 +1,27 @@ +.dropdown { + display: 'flex' !important; + align-items: 'center'; + padding: 5px 8px; + border-radius: 3px; + transition: all 0.3s; + font-weight: 500; + + &:hover { + background-color: #DDDDDD; + transition: all 0.2s; + } +} + +.dateInput { + display: flex; + align-items: center; + padding: 4px; + font-weight: 500; + font-size: 14px; + color: $gray-darkest; + + &:hover { + background-color: lightgray; + border-radius: 3px; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/DashboardHeader/DashboardHeader.js b/frontend/app/components/Dashboard/DashboardHeader/DashboardHeader.js new file mode 100644 index 000000000..dd2c35c76 --- /dev/null +++ b/frontend/app/components/Dashboard/DashboardHeader/DashboardHeader.js @@ -0,0 +1,40 @@ +import React from 'react' +import { LAST_24_HOURS, LAST_30_MINUTES, LAST_7_DAYS, LAST_30_DAYS, CUSTOM_RANGE } from 'Types/app/period'; +import { ALL, DESKTOP, MOBILE } from 'Types/app/platform'; +import { connect } from 'react-redux'; +import { setPeriod, setPlatform } from 'Duck/dashboard'; +import cn from 'classnames'; +import styles from './DashboardHeader.css'; +import Filters from '../Filters/Filters'; + +export const PERIOD_OPTIONS = [ + { text: 'Past 30 Min', value: LAST_30_MINUTES }, + { text: 'Past 24 Hours', value: LAST_24_HOURS }, + { text: 'Past 7 Days', value: LAST_7_DAYS }, + { text: 'Past 30 Days', value: LAST_30_DAYS }, + { text: 'Choose Date', value: CUSTOM_RANGE }, +]; + +const PLATFORM_OPTIONS = [ + { text: 'All Platforms', value: ALL }, + { text: 'Desktop', value: DESKTOP }, + { text: 'Mobile', value: MOBILE } +]; + +const DashboardHeader = props => { + return ( +
    + + +
    +
    +
    + ) +} + +export default connect(state => ({ + period: state.getIn([ 'dashboard', 'period' ]), + platform: state.getIn([ 'dashboard', 'platform' ]), + currentProjectId: state.getIn([ 'user', 'siteId' ]), + sites: state.getIn([ 'site', 'list' ]), +}), { setPeriod, setPlatform })(DashboardHeader) diff --git a/frontend/app/components/Dashboard/DashboardHeader/index.js b/frontend/app/components/Dashboard/DashboardHeader/index.js new file mode 100644 index 000000000..924f0ec2c --- /dev/null +++ b/frontend/app/components/Dashboard/DashboardHeader/index.js @@ -0,0 +1 @@ +export { default as DashboardHeader } from './DashboardHeader'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Filters/FilterItem/FilterItem.js b/frontend/app/components/Dashboard/Filters/FilterItem/FilterItem.js new file mode 100644 index 000000000..4fc4410cf --- /dev/null +++ b/frontend/app/components/Dashboard/Filters/FilterItem/FilterItem.js @@ -0,0 +1,86 @@ +import React, { useState } from 'react'; +import { Icon, Button } from 'UI'; +import { LAST_24_HOURS, LAST_30_MINUTES, LAST_7_DAYS, LAST_30_DAYS, CUSTOM_RANGE } from 'Types/app/period'; +import stl from './filterItem.css'; +import cn from 'classnames'; +import { setPeriod } from 'Duck/dashboard'; +import { connect } from 'react-redux'; +import { debounce } from 'App/utils'; +import DateRangeDropdown from 'Shared/DateRangeDropdown/DateRangeDropdown'; +import FilterDropdown from 'Shared/FilterDropdown'; + +export const PERIOD_OPTIONS = [ + { text: 'Past 30 Min', value: LAST_30_MINUTES }, + { text: 'Past 24 Hours', value: LAST_24_HOURS }, + { text: 'Past 7 Days', value: LAST_7_DAYS }, + { text: 'Past 30 Days', value: LAST_30_DAYS }, + { text: 'Choose Date', value: CUSTOM_RANGE }, +]; + +const FilterItem = props => { + const { period, filters, compare = false, metaOptions } = props; + const filterKeyMaps = filters.map(f => f.key).toJS(); + const [rangeName, setRangeName] = useState(period.rangeName) + const [startDate, setStartDate] = useState(null) + const [endDate, setEndDate] = useState(null) + const setPeriod = debounce(props.setPeriod, 500) + + const onDateChange = (e) => { + setPeriod(compare, { rangeName: e.rangeValue, start: e.startDate, end: e.endDate }); + setRangeName(e.rangeValue) + setStartDate(e.startDate) + setEndDate(e.endDate) + } + + return ( +
    +
    + +
    + +
    + {filters.map(f => ( +
    +
    + {f.value} + props.removeFilter(f)} /> +
    +
    + ))} + +
    +
    +
    + {filters.size > 0 && ( + + )} + { compare && + + } +
    +
    +
    + ) +} + +export default connect((state, props) => { + const comparing = props && props.compare; + return { + period: state.getIn([ 'dashboard', comparing ? 'periodCompare' : 'period' ]), + metaOptions: state.getIn([ 'dashboard', 'metaOptions' ]) + } +}, { setPeriod })(FilterItem) \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Filters/FilterItem/filterItem.css b/frontend/app/components/Dashboard/Filters/FilterItem/filterItem.css new file mode 100644 index 000000000..3a6bb1008 --- /dev/null +++ b/frontend/app/components/Dashboard/Filters/FilterItem/filterItem.css @@ -0,0 +1,29 @@ +.wrapper { + min-height: 38px; +} + +.dropdown { + display: 'flex' !important; + align-items: 'center'; + padding: 5px 8px; + border-radius: 3px; + transition: all 0.3s; + font-weight: 500; + + &:hover { + background-color: #DDDDDD; + transition: all 0.2s; + } +} + +.circle { + width: 15px; + height: 15px; + background-color: $tealx; + border-radius: 50%; + margin-right: 10px; + + &.compare { + background-color: $teal; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Filters/FilterItem/index.js b/frontend/app/components/Dashboard/Filters/FilterItem/index.js new file mode 100644 index 000000000..7442505f6 --- /dev/null +++ b/frontend/app/components/Dashboard/Filters/FilterItem/index.js @@ -0,0 +1 @@ +export { default } from './FilterItem'; diff --git a/frontend/app/components/Dashboard/Filters/Filters.js b/frontend/app/components/Dashboard/Filters/Filters.js new file mode 100644 index 000000000..0c4ce0d62 --- /dev/null +++ b/frontend/app/components/Dashboard/Filters/Filters.js @@ -0,0 +1,58 @@ +import React from 'react' +import { Button } from 'UI'; +import stl from './filters.css'; +import { LAST_24_HOURS, LAST_30_MINUTES, LAST_7_DAYS, LAST_30_DAYS, CUSTOM_RANGE } from 'Types/app/period'; +import FilterItem from './FilterItem'; +import { setComparing, setFilters, clearFilters, removeFilter } from 'Duck/dashboard'; +import { connect } from 'react-redux'; + +export const PERIOD_OPTIONS = [ + { text: 'Past 30 Min', value: LAST_30_MINUTES }, + { text: 'Past 24 Hours', value: LAST_24_HOURS }, + { text: 'Past 7 Days', value: LAST_7_DAYS }, + { text: 'Past 30 Days', value: LAST_30_DAYS }, + { text: 'Choose Date', value: CUSTOM_RANGE }, +]; + +const Filters = props => { + const { rangeName, comparing, filters, filtersCompare } = props; + + return ( +
    + props.setFilters('default', filter)} + removeFilter={filter => props.removeFilter('default', filter.key)} + resetFilters={() => props.clearFilters('default')} + /> +
    + {!comparing && ( +
    + +
    + )} + {comparing && ( + + props.setFilters('compare', filter)} + removeFilter={filter => props.removeFilter('compare', filter.key)} + removeCompare={() => props.setComparing(false)} + resetFilters={() => props.clearFilters('compare')} + /> + + )} +
    + ) +} + +export default connect(state => ({ + comparing: state.getIn([ 'dashboard', 'comparing' ]), + filters: state.getIn([ 'dashboard', 'filters' ]), + filtersCompare: state.getIn([ 'dashboard', 'filtersCompare' ]), +}), { setComparing, setFilters, clearFilters, removeFilter })(Filters) diff --git a/frontend/app/components/Dashboard/Filters/filters.css b/frontend/app/components/Dashboard/Filters/filters.css new file mode 100644 index 000000000..9c0bda3a4 --- /dev/null +++ b/frontend/app/components/Dashboard/Filters/filters.css @@ -0,0 +1,32 @@ +.dropdown { + display: 'flex' !important; + align-items: 'center'; + padding: 5px 8px; + border-radius: 3px; + transition: all 0.3s; + font-weight: 500; + + &:hover { + background-color: #DDDDDD; + transition: all 0.2s; + } +} + +.dateInput { + display: flex; + align-items: center; + padding: 4px; + font-weight: 500; + font-size: 14px; + color: $gray-darkest; + + &:hover { + background-color: lightgray; + border-radius: 3px; + } +} + +.divider { + margin: 10px 0; + border-top: solid thin $gray-light; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Filters/index.js b/frontend/app/components/Dashboard/Filters/index.js new file mode 100644 index 000000000..a7eb8c1cf --- /dev/null +++ b/frontend/app/components/Dashboard/Filters/index.js @@ -0,0 +1 @@ +export { default as Filters } from './Filters'; diff --git a/frontend/app/components/Dashboard/SideMenu/SideMenuDividedItem.js b/frontend/app/components/Dashboard/SideMenu/SideMenuDividedItem.js new file mode 100644 index 000000000..bd8af6281 --- /dev/null +++ b/frontend/app/components/Dashboard/SideMenu/SideMenuDividedItem.js @@ -0,0 +1,20 @@ +import { SideMenuitem } from "UI"; +import Divider from 'Components/Errors/ui/Divider'; + +function SideMenuDividedItem({ className, noTopDivider = false, noBottomDivider = false, ...props }) { + return ( +
    + { !noTopDivider && } + + { !noBottomDivider && } +
    + ); +} + +SideMenuDividedItem.displayName = "SideMenuDividedItem"; + +export default SideMenuDividedItem; + diff --git a/frontend/app/components/Dashboard/SideMenu/SideMenuHeader.js b/frontend/app/components/Dashboard/SideMenu/SideMenuHeader.js new file mode 100644 index 000000000..7f237263a --- /dev/null +++ b/frontend/app/components/Dashboard/SideMenu/SideMenuHeader.js @@ -0,0 +1,13 @@ +import cn from 'classnames'; +import stl from './sideMenuHeader.css'; + +function SideMenuHeader({ text, className }) { + return ( +
    + { text } +
    + ) +} + +SideMenuHeader.displayName = "SideMenuHeader"; +export default SideMenuHeader; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/SideMenu/SideMenuSection.js b/frontend/app/components/Dashboard/SideMenu/SideMenuSection.js new file mode 100644 index 000000000..977989559 --- /dev/null +++ b/frontend/app/components/Dashboard/SideMenu/SideMenuSection.js @@ -0,0 +1,40 @@ +import { SideMenuitem } from 'UI'; +import SideMenuHeader from './SideMenuHeader'; +import { setShowAlerts } from 'Duck/dashboard'; +import stl from './sideMenuSection.css'; +import { connect } from 'react-redux'; +import { NavLink } from 'react-router-dom'; +import { withSiteId } from 'App/routes'; + +function SideMenuSection({ title, items, onItemClick, setShowAlerts, siteId }) { + return ( + <> + + { items.filter(i => i.section === 'metrics').map(item => + onItemClick(item)} + /> + )} + +
    +
    + setShowAlerts(true)} + /> +
    + + ); +} + +SideMenuSection.displayName = "SideMenuSection"; + +export default connect(state => ({ + siteId: state.getIn([ 'user', 'siteId' ]) +}), { setShowAlerts })(SideMenuSection); \ No newline at end of file diff --git a/frontend/app/components/Dashboard/SideMenu/sideMenuHeader.css b/frontend/app/components/Dashboard/SideMenu/sideMenuHeader.css new file mode 100644 index 000000000..5dce4e250 --- /dev/null +++ b/frontend/app/components/Dashboard/SideMenu/sideMenuHeader.css @@ -0,0 +1,4 @@ +.label { + letter-spacing: 0.2em; + color: gray; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/SideMenu/sideMenuSection.css b/frontend/app/components/Dashboard/SideMenu/sideMenuSection.css new file mode 100644 index 000000000..fccde627d --- /dev/null +++ b/frontend/app/components/Dashboard/SideMenu/sideMenuSection.css @@ -0,0 +1,5 @@ +.divider { + height: 1px; + width: 100%; + background-color: $gray-light; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/WidgetHolder/WidgetHolder.js b/frontend/app/components/Dashboard/WidgetHolder/WidgetHolder.js new file mode 100644 index 000000000..e5c90967d --- /dev/null +++ b/frontend/app/components/Dashboard/WidgetHolder/WidgetHolder.js @@ -0,0 +1,33 @@ +import React from 'react' +import { connect } from 'react-redux' +import cn from 'classnames' +import stl from './widgetHolder.css' +import LazyLoad from 'react-lazyload'; + +const WidgetHolder = props => { + const { comparing, Component, period, periodCompare, fullWidth = false } = props; + const showSync = comparing && period.rangeName === periodCompare.rangeName; + + return ( +
    + + {} + + {comparing && ( + + +
    + +
    +
    +
    + )} +
    + ) +} + +export default connect(state => ({ + comparing: state.getIn([ 'dashboard', 'comparing' ]), + period: state.getIn([ 'dashboard', 'period' ]), + periodCompare: state.getIn([ 'dashboard', 'periodCompare' ]) +}))(WidgetHolder) diff --git a/frontend/app/components/Dashboard/WidgetHolder/index.js b/frontend/app/components/Dashboard/WidgetHolder/index.js new file mode 100644 index 000000000..afb19393a --- /dev/null +++ b/frontend/app/components/Dashboard/WidgetHolder/index.js @@ -0,0 +1 @@ +export { default } from './WidgetHolder'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/WidgetHolder/widgetHolder.css b/frontend/app/components/Dashboard/WidgetHolder/widgetHolder.css new file mode 100644 index 000000000..c4f9d132c --- /dev/null +++ b/frontend/app/components/Dashboard/WidgetHolder/widgetHolder.css @@ -0,0 +1,12 @@ +.wrapper { + border: dotted 2px transparent; + border-radius: 3px; + margin: -5px; + padding: 5px; + transition: all 0.3s; + + &:hover { + transition: all 0.2s; + border: dotted 2px $gray-medium; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/WidgetSection/WidgetSection.js b/frontend/app/components/Dashboard/WidgetSection/WidgetSection.js new file mode 100644 index 000000000..a7129c7fb --- /dev/null +++ b/frontend/app/components/Dashboard/WidgetSection/WidgetSection.js @@ -0,0 +1,20 @@ +import React from 'react' +import cn from 'classnames' +import AddWidgets from '../AddWidgets'; + +function WidgetSection({ className, title, children, description, type }) { + return ( +
    +
    +
    +
    {title}
    + +
    + {description &&
    {description}
    } +
    + { children } +
    + ) +} + +export default WidgetSection diff --git a/frontend/app/components/Dashboard/WidgetSection/index.js b/frontend/app/components/Dashboard/WidgetSection/index.js new file mode 100644 index 000000000..13f279e4e --- /dev/null +++ b/frontend/app/components/Dashboard/WidgetSection/index.js @@ -0,0 +1 @@ +export { default as WidgetSection } from './WidgetSection'; diff --git a/frontend/app/components/Dashboard/Widgets/ApplicationActivity.js b/frontend/app/components/Dashboard/Widgets/ApplicationActivity.js new file mode 100644 index 000000000..d19b83faa --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ApplicationActivity.js @@ -0,0 +1,42 @@ +import { Loader } from 'UI'; +import { msToSec } from 'App/date'; +import { CountBadge, Divider, widgetHOC } from './common'; + +@widgetHOC('applicationActivity') +export default class ApplicationActivity extends React.PureComponent { + render() { + const { data, loading } = this.props; + return ( +
    + + + + + + + +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/BreakdownOfLoadedResources/BreakdownOfLoadedResources.js b/frontend/app/components/Dashboard/Widgets/BreakdownOfLoadedResources/BreakdownOfLoadedResources.js new file mode 100644 index 000000000..240b9b9bc --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/BreakdownOfLoadedResources/BreakdownOfLoadedResources.js @@ -0,0 +1,58 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { + BarChart, Bar, CartesianGrid, Legend, ResponsiveContainer, + XAxis, YAxis, Tooltip +} from 'recharts'; + +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 28 } + + if (rangeName === LAST_24_HOURS) params.density = 21 + if (rangeName === LAST_30_MINUTES) params.density = 28 + if (rangeName === YESTERDAY) params.density = 28 + if (rangeName === LAST_7_DAYS) params.density = 28 + + return params +} + +@widgetHOC('resourcesCountByType', { customParams }) +export default class BreakdownOfLoadedResources extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + + return ( + + + + + + + + + + + + + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/BreakdownOfLoadedResources/index.js b/frontend/app/components/Dashboard/Widgets/BreakdownOfLoadedResources/index.js new file mode 100644 index 000000000..6e2e706fb --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/BreakdownOfLoadedResources/index.js @@ -0,0 +1 @@ +export { default } from './BreakdownOfLoadedResources'; diff --git a/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/BusiestTimeOfTheDay.js b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/BusiestTimeOfTheDay.js new file mode 100644 index 000000000..a0e601afa --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/BusiestTimeOfTheDay.js @@ -0,0 +1,42 @@ +import { Loader, NoContent } from 'UI'; +import { Table, widgetHOC, domain } from '../common'; +import { + Radar, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, + PieChart, Pie, Cell, Tooltip, ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area } from 'recharts'; + +const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042']; +const RADIAN = Math.PI / 180; + +@widgetHOC('busiestTimeOfDay', { fitContent: true }) +export default class BusiestTimeOfTheDay extends React.PureComponent { + renderCustomizedLabel = ({ + cx, cy, midAngle, innerRadius, outerRadius, percent, index, + }) => { + const radius = innerRadius + (outerRadius - innerRadius) * 0.5; + const x = cx + radius * Math.cos(-midAngle * RADIAN); + const y = cy + radius * Math.sin(-midAngle * RADIAN); + + return ( + cx ? 'start' : 'end'} dominantBaseline="central"> + {`${(percent * 100).toFixed(0)}%`} + + ); + }; + + render() { + const { data, loading } = this.props; + return ( + + + + + + + + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/Chart.js b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/Chart.js new file mode 100644 index 000000000..2a23c4f47 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/Chart.js @@ -0,0 +1,13 @@ +import { AreaChart, Area } from 'recharts'; + +const Chart = ({ data }) => { + return ( + + + + ); +} + +Chart.displayName = 'Chart'; + +export default Chart; diff --git a/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/ImageInfo.js b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/ImageInfo.js new file mode 100644 index 000000000..dc085df5c --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/ImageInfo.js @@ -0,0 +1,27 @@ +import { Popup, Icon } from 'UI'; +import styles from './imageInfo.css'; + +const ImageInfo = ({ data }) => ( +
    + + +
    { 'Preview' }
    +
    + } + content={ One of the slowest images } + /> + { data.name } + } + content={ data.url } + /> +
    +); + +ImageInfo.displayName = 'ImageInfo'; + +export default ImageInfo; diff --git a/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/imageInfo.css b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/imageInfo.css new file mode 100644 index 000000000..69030a582 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/imageInfo.css @@ -0,0 +1,39 @@ +.name { + display: flex; + align-items: center; + + & > span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 60%; + } +} + +.imagePreview { + max-width: 200px; + max-height: 200px; +} + +.imageWrapper { + display: flex; + flex-flow: column; + align-items: center; + width: 40px; + text-align: center; + margin-right: 10px; + & > span { + height: 16px; + } + & .label { + font-size: 9px; + color: $gray-light; + } +} + +.popup { + background-color: #f5f5f5 !important; + &:before { + background-color: #f5f5f5 !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/index.js b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/index.js new file mode 100644 index 000000000..ce82e31a0 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/BusiestTimeOfTheDay/index.js @@ -0,0 +1 @@ +export { default } from './BusiestTimeOfTheDay'; diff --git a/frontend/app/components/Dashboard/Widgets/CallWithErrors/CallWithErrors.js b/frontend/app/components/Dashboard/Widgets/CallWithErrors/CallWithErrors.js new file mode 100644 index 000000000..3f24ba40e --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallWithErrors/CallWithErrors.js @@ -0,0 +1,76 @@ +import { Loader, NoContent } from 'UI'; +import { Table, widgetHOC } from '../common'; +import { getRE } from 'App/utils'; +import ImageInfo from './ImageInfo'; +import MethodType from './MethodType'; +import cn from 'classnames'; +import stl from './callWithErrors.css'; + +const cols = [ + { + key: 'method', + title: 'Method', + className: 'text-left', + Component: MethodType, + cellClass: 'ml-2', + width: '8%', + }, + { + key: 'urlHostpath', + title: 'Path', + Component: ImageInfo, + width: '40%', + }, + { + key: 'allRequests', + title: 'Requests', + className: 'text-left', + width: '15%', + }, + { + key: '4xx', + title: '4xx', + className: 'text-left', + width: '15%', + }, + { + key: '5xx', + title: '5xx', + className: 'text-left', + width: '15%', + } +]; + +@widgetHOC('callsErrors', { fitContent: true }) +export default class CallWithErrors extends React.PureComponent { + state = { search: ''} + + test = (value = '', serach) => getRE(serach, 'i').test(value); + + write = ({ target: { name, value } }) => { + this.setState({ [ name ]: value }) + }; + + render() { + const { data: images, loading } = this.props; + const { search } = this.state; + const _data = search ? images.filter(i => this.test(i.urlHostpath, search)) : images; + + return ( + +
    + +
    + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/CallWithErrors/Chart.js b/frontend/app/components/Dashboard/Widgets/CallWithErrors/Chart.js new file mode 100644 index 000000000..2a23c4f47 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallWithErrors/Chart.js @@ -0,0 +1,13 @@ +import { AreaChart, Area } from 'recharts'; + +const Chart = ({ data }) => { + return ( + + + + ); +} + +Chart.displayName = 'Chart'; + +export default Chart; diff --git a/frontend/app/components/Dashboard/Widgets/CallWithErrors/ImageInfo.js b/frontend/app/components/Dashboard/Widgets/CallWithErrors/ImageInfo.js new file mode 100644 index 000000000..8251bec60 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallWithErrors/ImageInfo.js @@ -0,0 +1,12 @@ +import { Popup, Icon, TextEllipsis } from 'UI'; +import styles from './imageInfo.css'; + +const ImageInfo = ({ data }) => ( +
    + +
    +); + +ImageInfo.displayName = 'ImageInfo'; + +export default ImageInfo; diff --git a/frontend/app/components/Dashboard/Widgets/CallWithErrors/MethodType.js b/frontend/app/components/Dashboard/Widgets/CallWithErrors/MethodType.js new file mode 100644 index 000000000..ba370b481 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallWithErrors/MethodType.js @@ -0,0 +1,10 @@ +import React from 'react' +import { Label } from 'UI'; + +const MethodType = ({ data }) => { + return ( + + ) +} + +export default MethodType diff --git a/frontend/app/components/Dashboard/Widgets/CallWithErrors/callWithErrors.css b/frontend/app/components/Dashboard/Widgets/CallWithErrors/callWithErrors.css new file mode 100644 index 000000000..bc37a3991 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallWithErrors/callWithErrors.css @@ -0,0 +1,22 @@ +.topActions { + position: absolute; + top: -4px; + right: 50px; + display: flex; + justify-content: flex-end; +} + +.searchField { + padding: 4px 5px; + border-bottom: dotted thin $gray-light; + border-radius: 3px; + &:focus, + &:active { + border: solid thin transparent !important; + box-shadow: none; + background-color: $gray-light; + } + &:hover { + border: solid thin $gray-light !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CallWithErrors/imageInfo.css b/frontend/app/components/Dashboard/Widgets/CallWithErrors/imageInfo.css new file mode 100644 index 000000000..69030a582 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallWithErrors/imageInfo.css @@ -0,0 +1,39 @@ +.name { + display: flex; + align-items: center; + + & > span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 60%; + } +} + +.imagePreview { + max-width: 200px; + max-height: 200px; +} + +.imageWrapper { + display: flex; + flex-flow: column; + align-items: center; + width: 40px; + text-align: center; + margin-right: 10px; + & > span { + height: 16px; + } + & .label { + font-size: 9px; + color: $gray-light; + } +} + +.popup { + background-color: #f5f5f5 !important; + &:before { + background-color: #f5f5f5 !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CallWithErrors/index.js b/frontend/app/components/Dashboard/Widgets/CallWithErrors/index.js new file mode 100644 index 000000000..6b0db1bd0 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallWithErrors/index.js @@ -0,0 +1 @@ +export { default } from './CallWithErrors'; diff --git a/frontend/app/components/Dashboard/Widgets/CallsErrors4xx/CallsErrors4xx.js b/frontend/app/components/Dashboard/Widgets/CallsErrors4xx/CallsErrors4xx.js new file mode 100644 index 000000000..00693315d --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallsErrors4xx/CallsErrors4xx.js @@ -0,0 +1,78 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, + LineChart, Line, Legend, Tooltip +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@widgetHOC('domainsErrors_4xx', { customParams }) +export default class CallsErrors4xx extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + + const namesMap = data.chart + .map(i => Object.keys(i)) + .flat() + .filter(i => i !== 'time' && i !== 'timestamp') + .reduce( + (unique, item) => (unique.includes(item) ? unique : [...unique, item]), + [] + ); + + return ( + + + + + + + + + + + + + + + + { namesMap.map((key, index) => ( + + ))} + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/CallsErrors4xx/index.js b/frontend/app/components/Dashboard/Widgets/CallsErrors4xx/index.js new file mode 100644 index 000000000..78fa75b53 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallsErrors4xx/index.js @@ -0,0 +1 @@ +export { default } from './CallsErrors4xx'; diff --git a/frontend/app/components/Dashboard/Widgets/CallsErrors5xx/CallsErrors5xx.js b/frontend/app/components/Dashboard/Widgets/CallsErrors5xx/CallsErrors5xx.js new file mode 100644 index 000000000..3790d64bd --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallsErrors5xx/CallsErrors5xx.js @@ -0,0 +1,83 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, + LineChart, Line, Legend, Tooltip +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@widgetHOC('domainsErrors_5xx', { customParams }) +export default class CallsErrors5xx extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + + const namesMap = data.chart + .map(i => Object.keys(i)) + .flat() + .filter(i => i !== 'time' && i !== 'timestamp') + .reduce( + (unique, item) => (unique.includes(item) ? unique : [...unique, item]), + [] + ); + + return ( + + + + + + + + + + { namesMap.map((key, index) => ( + + ))} + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/CallsErrors5xx/index.js b/frontend/app/components/Dashboard/Widgets/CallsErrors5xx/index.js new file mode 100644 index 000000000..61b9900d7 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CallsErrors5xx/index.js @@ -0,0 +1 @@ +export { default } from './CallsErrors5xx'; diff --git a/frontend/app/components/Dashboard/Widgets/CpuLoad/CpuLoad.js b/frontend/app/components/Dashboard/Widgets/CpuLoad/CpuLoad.js new file mode 100644 index 000000000..479db15e8 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CpuLoad/CpuLoad.js @@ -0,0 +1,67 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles, AvgLabel } from '../common'; +import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, AreaChart, Area, Tooltip } from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@widgetHOC('cpu', { customParams }) +export default class CpuLoad extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + const gradientDef = Styles.gradientDef(); + + return ( + + +
    + +
    + + + {gradientDef} + + + Styles.tickFormatter(val)} + label={{ ...Styles.axisLabelLeft, value: "CPU Load (%)" }} + /> + + + + +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/CpuLoad/index.js b/frontend/app/components/Dashboard/Widgets/CpuLoad/index.js new file mode 100644 index 000000000..84bd7bc61 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CpuLoad/index.js @@ -0,0 +1 @@ +export { default } from './CpuLoad'; diff --git a/frontend/app/components/Dashboard/Widgets/Crashes/Crashes.js b/frontend/app/components/Dashboard/Widgets/Crashes/Crashes.js new file mode 100644 index 000000000..c657bae19 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/Crashes/Crashes.js @@ -0,0 +1,66 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { + AreaChart, Area, ResponsiveContainer, + XAxis, YAxis, CartesianGrid, Tooltip +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@widgetHOC('crashes', { customParams }) +export default class Crashes extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + const gradientDef = Styles.gradientDef(); + + return ( + + + + + {gradientDef} + + + Styles.tickFormatter(val)} + label={{ ...Styles.axisLabelLeft, value: "Number of Crashes" }} + /> + + + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/Crashes/index.js b/frontend/app/components/Dashboard/Widgets/Crashes/index.js new file mode 100644 index 000000000..cb869ef09 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/Crashes/index.js @@ -0,0 +1 @@ +export { default } from './Crashes'; diff --git a/frontend/app/components/Dashboard/Widgets/DomBuildingTime/DomBuildingTime.js b/frontend/app/components/Dashboard/Widgets/DomBuildingTime/DomBuildingTime.js new file mode 100644 index 000000000..c46bea4f7 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/DomBuildingTime/DomBuildingTime.js @@ -0,0 +1,100 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles, AvgLabel } from '../common'; +import { withRequest } from 'HOCs'; +import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; +import WidgetAutoComplete from 'Shared/WidgetAutoComplete'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const WIDGET_KEY = 'pagesDomBuildtime'; +const toUnderscore = s => s.split(/(?=[A-Z])/).join('_').toLowerCase(); + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} +@withRequest({ + dataName: "options", + initialData: [], + dataWrapper: data => data, + loadingName: 'optionsLoading', + requestName: "fetchOptions", + endpoint: '/dashboard/' + toUnderscore(WIDGET_KEY) + '/search', + method: 'GET' +}) +@widgetHOC(WIDGET_KEY, { customParams }) +export default class DomBuildingTime extends React.PureComponent { + onSelect = (params) => { + const _params = customParams(this.props.period.rangeName) + this.props.fetchWidget(WIDGET_KEY, this.props.period, this.props.platform, { ..._params, url: params.value }) + } + + render() { + const { data, loading, period, optionsLoading, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + const gradientDef = Styles.gradientDef(); + + return ( + + +
    + + +
    + + + + + {gradientDef} + + + Styles.tickFormatter(val)} + /> + + + + + + +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/DomBuildingTime/index.js b/frontend/app/components/Dashboard/Widgets/DomBuildingTime/index.js new file mode 100644 index 000000000..b5d6c5682 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/DomBuildingTime/index.js @@ -0,0 +1 @@ +export { default } from './DomBuildingTime'; diff --git a/frontend/app/components/Dashboard/Widgets/Errors/Errors.js b/frontend/app/components/Dashboard/Widgets/Errors/Errors.js new file mode 100644 index 000000000..0faf167cf --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/Errors/Errors.js @@ -0,0 +1,53 @@ +import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area } from 'recharts'; +import { Loader, NoContent } from 'UI'; +import { CountBadge, domain, widgetHOC } from '../common'; +import styles from './errors.css'; + +@widgetHOC('errors') +export default class Errors extends React.PureComponent { + render() { + const { data, loading } = this.props; + + const isMoreThanKSessions = data.impactedSessions > 1000; + const impactedSessionsView = isMoreThanKSessions ? Math.trunc(data.impactedSessions / 1000) : data.impactedSessions; + return ( +
    + + + { 'Events' }
    } + count={ data.count } + change={ data.progress } + oppositeColors + /> + { 'Sessions' } } + count={ impactedSessionsView } + change={ data.impactedSessionsProgress } + unit={ isMoreThanKSessions ? 'k' : '' } + oppositeColors + /> + + + + + + + + + + + + + + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/Errors/errors.css b/frontend/app/components/Dashboard/Widgets/Errors/errors.css new file mode 100644 index 000000000..1de075dc2 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/Errors/errors.css @@ -0,0 +1,4 @@ +.label { + max-width: 65px; + line-height: 14px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/Errors/index.js b/frontend/app/components/Dashboard/Widgets/Errors/index.js new file mode 100644 index 000000000..87b132550 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/Errors/index.js @@ -0,0 +1 @@ +export { default } from './Errors'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/ErrorsByOrigin/ErrorsByOrigin.js b/frontend/app/components/Dashboard/Widgets/ErrorsByOrigin/ErrorsByOrigin.js new file mode 100644 index 000000000..eaa4802b9 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ErrorsByOrigin/ErrorsByOrigin.js @@ -0,0 +1,56 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { + BarChart, Bar, CartesianGrid, Tooltip, Legend, ResponsiveContainer, + XAxis, YAxis +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 28 } + + if (rangeName === LAST_24_HOURS) params.density = 28 + if (rangeName === LAST_30_MINUTES) params.density = 28 + if (rangeName === YESTERDAY) params.density = 28 + if (rangeName === LAST_7_DAYS) params.density = 28 + + return params +} + +@widgetHOC('resourcesByParty', { fullwidth: true, customParams }) +export default class ErrorsByOrigin extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + + return ( + + + + + + + + + + 1st Party} dataKey="firstParty" stackId="a" fill={colors[0]} /> + 3rd Party} dataKey="thirdParty" stackId="a" fill={colors[2]} /> + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ErrorsByOrigin/index.js b/frontend/app/components/Dashboard/Widgets/ErrorsByOrigin/index.js new file mode 100644 index 000000000..9ef5b0117 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ErrorsByOrigin/index.js @@ -0,0 +1 @@ +export { default } from './ErrorsByOrigin'; diff --git a/frontend/app/components/Dashboard/Widgets/ErrorsByType/ErrorsByType.js b/frontend/app/components/Dashboard/Widgets/ErrorsByType/ErrorsByType.js new file mode 100644 index 000000000..fc07c8ec9 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ErrorsByType/ErrorsByType.js @@ -0,0 +1,61 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, domain, Styles } from '../common'; +import { numberWithCommas} from 'App/utils'; +import { + BarChart, Bar, CartesianGrid, Tooltip, + LineChart, Line, Legend, ResponsiveContainer, + XAxis, YAxis +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 28 } + + if (rangeName === LAST_24_HOURS) params.density = 21 + if (rangeName === LAST_30_MINUTES) params.density = 28 + if (rangeName === YESTERDAY) params.density = 28 + if (rangeName === LAST_7_DAYS) params.density = 28 + + return params +} + +@widgetHOC('errorsPerType', { fullwidth: true, customParams }) +export default class ErrorsByType extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + + return ( + + + + + + + + + + + + + + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ErrorsByType/index.js b/frontend/app/components/Dashboard/Widgets/ErrorsByType/index.js new file mode 100644 index 000000000..53f976df3 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ErrorsByType/index.js @@ -0,0 +1 @@ +export { default } from './ErrorsByType'; diff --git a/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/Bar.css b/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/Bar.css new file mode 100644 index 000000000..d3d399918 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/Bar.css @@ -0,0 +1,6 @@ +.bar { + height: 10px; + background-color: red; + width: 100%; + border-radius: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/Bar.js b/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/Bar.js new file mode 100644 index 000000000..99b37a032 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/Bar.js @@ -0,0 +1,18 @@ +import React from 'react' +import stl from './Bar.css' + +const Bar = ({ className = '', width = 0, avg, domain, color }) => { + return ( +
    +
    +
    0 ? width : 5 }%`, backgroundColor: color }}>
    +
    + {`${avg}`} +
    +
    +
    {domain}
    +
    + ) +} + +export default Bar diff --git a/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/ErrorsPerDomain.js b/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/ErrorsPerDomain.js new file mode 100644 index 000000000..3a152161d --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/ErrorsPerDomain.js @@ -0,0 +1,35 @@ +import { Loader, NoContent } from 'UI'; +import { Table, widgetHOC, domain, AvgLabel, Styles } from '../common'; +import Bar from './Bar'; +import { numberWithCommas } from 'App/utils'; + +@widgetHOC('errorsPerDomains') +export default class ErrorsPerDomain extends React.PureComponent { + render() { + const { data, loading, compare = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const firstAvg = data.first() && data.first().errorsCount; + + return ( + + +
    + {data.map((item, i) => + + )} +
    +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/index.js b/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/index.js new file mode 100644 index 000000000..3a60d15c0 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ErrorsPerDomain/index.js @@ -0,0 +1 @@ +export { default } from './ErrorsPerDomain'; diff --git a/frontend/app/components/Dashboard/Widgets/FPS/FPS.js b/frontend/app/components/Dashboard/Widgets/FPS/FPS.js new file mode 100644 index 000000000..2da364985 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/FPS/FPS.js @@ -0,0 +1,66 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles, AvgLabel } from '../common'; +import { ResponsiveContainer, Tooltip, XAxis, YAxis, CartesianGrid, AreaChart, Area } from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@widgetHOC('fps', { customParams }) +export default class FPS extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + const gradientDef = Styles.gradientDef(); + + return ( + + +
    + +
    + + + {gradientDef} + + + Styles.tickFormatter(val)} + label={{ ...Styles.axisLabelLeft, value: "Frames Per Second" }} + /> + + + + +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/FPS/index.js b/frontend/app/components/Dashboard/Widgets/FPS/index.js new file mode 100644 index 000000000..55394ee20 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/FPS/index.js @@ -0,0 +1 @@ +export { default } from './FPS'; diff --git a/frontend/app/components/Dashboard/Widgets/LastFrustrations/LastFrustrations.js b/frontend/app/components/Dashboard/Widgets/LastFrustrations/LastFrustrations.js new file mode 100644 index 000000000..ee68539b8 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/LastFrustrations/LastFrustrations.js @@ -0,0 +1,42 @@ +import { Loader, NoContent, BrowserIcon, OsIcon } from 'UI'; +import { countries } from 'App/constants'; +import { diffFromNowString } from 'App/date'; +import { widgetHOC, SessionLine } from '../common'; + +@widgetHOC('sessionsFrustration', { fitContent: true }) +export default class LastFeedbacks extends React.PureComponent { + render() { + const { data: sessions, loading } = this.props; + return ( + + + { sessions.map(({ + startedAt, + sessionId, + clickRage, + returningLocation, + userBrowser, + userOs, + userCountry, + }) => ( + + { clickRage ? "Click Rage" : "Returning Location" } + + + + } + subInfo={ `${ diffFromNowString(startedAt) } ago - ${ countries[ userCountry ] || '' }` } + /> + ))} + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/LastFrustrations/index.js b/frontend/app/components/Dashboard/Widgets/LastFrustrations/index.js new file mode 100644 index 000000000..caaafd7e5 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/LastFrustrations/index.js @@ -0,0 +1 @@ +export { default } from './LastFrustrations'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/LastPerformance/LastPerformance.js b/frontend/app/components/Dashboard/Widgets/LastPerformance/LastPerformance.js new file mode 100644 index 000000000..e23e10be1 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/LastPerformance/LastPerformance.js @@ -0,0 +1,28 @@ +import { connect } from 'react-redux'; +import { Loader, NoContent } from 'UI'; +import { widgetHOC, SessionLine } from '../common'; + +@widgetHOC('sessionsPerformance', { fitContent: true }) +export default class LastFeedbacks extends React.PureComponent { + render() { + const { data: sessions, loading } = this.props; + return ( + + + { sessions.map(({ sessionId, missedResources }) => ( + + ))} + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/LastPerformance/index.js b/frontend/app/components/Dashboard/Widgets/LastPerformance/index.js new file mode 100644 index 000000000..6563813c2 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/LastPerformance/index.js @@ -0,0 +1 @@ +export { default } from './LastPerformance'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/MemoryConsumption/MemoryConsumption.js b/frontend/app/components/Dashboard/Widgets/MemoryConsumption/MemoryConsumption.js new file mode 100644 index 000000000..cc778a02d --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MemoryConsumption/MemoryConsumption.js @@ -0,0 +1,69 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles, AvgLabel } from '../common'; +import { ResponsiveContainer, Tooltip, XAxis, YAxis, CartesianGrid, AreaChart, Area } from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} +@widgetHOC('memoryConsumption', { customParams }) +export default class MemoryConsumption extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + const gradientDef = Styles.gradientDef(); + + return ( + + +
    + +
    + + + {gradientDef} + + + Styles.tickFormatterBytes(val)} + label={{ ...Styles.axisLabelLeft, value: "JS Heap Size (mb)" }} + /> + + + + +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/MemoryConsumption/index.js b/frontend/app/components/Dashboard/Widgets/MemoryConsumption/index.js new file mode 100644 index 000000000..9e6644855 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MemoryConsumption/index.js @@ -0,0 +1 @@ +export { default } from './MemoryConsumption'; diff --git a/frontend/app/components/Dashboard/Widgets/MissingResources/Chart.js b/frontend/app/components/Dashboard/Widgets/MissingResources/Chart.js new file mode 100644 index 000000000..0cbf173c1 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MissingResources/Chart.js @@ -0,0 +1,16 @@ +import { AreaChart, Area } from 'recharts'; +import { Styles } from '../common'; + +const Chart = ({ data, compare }) => { + const colors = compare ? Styles.compareColors : Styles.colors; + + return ( + + + + ); +} + +Chart.displayName = 'Chart'; + +export default Chart; diff --git a/frontend/app/components/Dashboard/Widgets/MissingResources/CopyPath.js b/frontend/app/components/Dashboard/Widgets/MissingResources/CopyPath.js new file mode 100644 index 000000000..6b7e709e7 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MissingResources/CopyPath.js @@ -0,0 +1,23 @@ +import React from 'react' +import copy from 'copy-to-clipboard' +import { useState } from 'react' + +const CopyPath = ({ data }) => { + const [copied, setCopied] = useState(false) + + const copyHandler = () => { + copy(data.url); + setCopied(true); + setTimeout(function() { + setCopied(false) + }, 500); + } + + return ( +
    + { copied ? 'Copied' : 'Copy Path'} +
    + ) +} + +export default CopyPath diff --git a/frontend/app/components/Dashboard/Widgets/MissingResources/MissingResources.js b/frontend/app/components/Dashboard/Widgets/MissingResources/MissingResources.js new file mode 100644 index 000000000..765104efb --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MissingResources/MissingResources.js @@ -0,0 +1,57 @@ +import { Loader, NoContent } from 'UI'; +import { Table, widgetHOC } from '../common'; +import Chart from './Chart'; +import ResourceInfo from './ResourceInfo'; +import CopyPath from './CopyPath'; + +const cols = [ + { + key: 'resource', + title: 'Resource', + Component: ResourceInfo, + width: '40%', + }, + { + key: 'sessions', + title: 'Sessions', + toText: count => `${ count > 1000 ? Math.trunc(count / 1000) : count }${ count > 1000 ? 'k' : '' }`, + width: '20%', + }, + { + key: 'trend', + title: 'Trend', + Component: Chart, + width: '20%', + }, + { + key: 'copy-path', + title: '', + Component: CopyPath, + cellClass: 'invisible group-hover:visible text-right', + width: '20%', + } +]; + +@widgetHOC('missingResources', { }) +export default class MissingResources extends React.PureComponent { + render() { + const { data: resources, loading, compare } = this.props; + return ( + + +
    + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/MissingResources/ResourceInfo.js b/frontend/app/components/Dashboard/Widgets/MissingResources/ResourceInfo.js new file mode 100644 index 000000000..004612705 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MissingResources/ResourceInfo.js @@ -0,0 +1,18 @@ +import { diffFromNowString } from 'App/date'; +import { TextEllipsis } from 'UI'; + +import styles from './resourceInfo.css'; + +export default class ResourceInfo extends React.PureComponent { + render() { + const { data } = this.props; + return ( +
    + +
    + { `${ diffFromNowString(data.endedAt) } ago - ${ diffFromNowString(data.startedAt) } old` } +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/MissingResources/index.js b/frontend/app/components/Dashboard/Widgets/MissingResources/index.js new file mode 100644 index 000000000..27229bb1c --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MissingResources/index.js @@ -0,0 +1 @@ +export { default } from './MissingResources'; diff --git a/frontend/app/components/Dashboard/Widgets/MissingResources/resourceInfo.css b/frontend/app/components/Dashboard/Widgets/MissingResources/resourceInfo.css new file mode 100644 index 000000000..d73d23530 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MissingResources/resourceInfo.css @@ -0,0 +1,10 @@ +.name { + letter-spacing: -.04em; + font-size: .9rem; + cursor: pointer; +} + +.timings { + color: $gray-medium; + font-size: 12px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/Chart.js b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/Chart.js new file mode 100644 index 000000000..1f97c6605 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/Chart.js @@ -0,0 +1,11 @@ +import { BarChart, Bar } from 'recharts'; + +const Chart = ({ data }) => ( + + + +); + +Chart.displaName = 'Chart'; + +export default Chart; diff --git a/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/ErrorInfo.js b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/ErrorInfo.js new file mode 100644 index 000000000..4dbbd2583 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/ErrorInfo.js @@ -0,0 +1,30 @@ +import { diffFromNowString } from 'App/date'; +import { TextEllipsis } from 'UI'; +import styles from './errorInfo.css'; + +export default class ErrorInfo extends React.PureComponent { + findJourneys = () => this.props.findJourneys(this.props.data.error) + + render() { + const { data } = this.props; + return ( +
    + +
    + { `${ diffFromNowString(data.lastOccurrenceAt) } ago - ${ diffFromNowString(data.firstOccurrenceAt) } old` } +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/MostImpactfulErrors.js b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/MostImpactfulErrors.js new file mode 100644 index 000000000..f5d252e08 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/MostImpactfulErrors.js @@ -0,0 +1,61 @@ +import { connect } from 'react-redux'; +import withSiteIdRouter from 'HOCs/withSiteIdRouter'; +import { Loader, NoContent } from 'UI'; +import { addEvent } from 'Duck/filters'; +import { TYPES } from 'Types/filter/event'; +import { sessions } from 'App/routes'; +import { Table, widgetHOC } from '../common'; +import Chart from './Chart'; +import ErrorInfo from './ErrorInfo'; + +const cols = [ + { + key: 'error', + title: 'Error Info', + Component: ErrorInfo, + width: '80%', + }, + { + key: 'trend', + title: 'Trend', + Component: Chart, + width: '10%', + }, + { + key: 'sessions', + title: 'Sessions', + toText: count => `${ count > 1000 ? Math.trunc(count / 1000) : count }${ count > 1000 ? 'k' : '' }`, + width: '10%', + }, +]; + +@withSiteIdRouter +@widgetHOC('errorsTrend', { fullwidth: true }) +@connect(null, { addEvent }) +export default class MostImpactfulErrors extends React.PureComponent { + findJourneys = (error) => { + this.props.addEvent({ + type: TYPES.CONSOLE, + value: error, + }, true); + this.props.history.push(sessions()); + } + + render() { + const { data: errors, loading } = this.props; + return ( + + +
    + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/errorInfo.css b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/errorInfo.css new file mode 100644 index 000000000..7aa0df799 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/errorInfo.css @@ -0,0 +1,11 @@ +.errorText { + font-family: 'menlo', 'monaco', 'consolas', monospace; + letter-spacing: -.04em; + font-size: .9rem; + cursor: pointer; +} + +.timings { + color: $gray-medium; + font-size: 12px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/index.js b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/index.js new file mode 100644 index 000000000..c072ed32c --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/MostImpactfulErrors/index.js @@ -0,0 +1 @@ +export { default } from './MostImpactfulErrors'; diff --git a/frontend/app/components/Dashboard/Widgets/OverviewWidgets/OverviewWidgets.js b/frontend/app/components/Dashboard/Widgets/OverviewWidgets/OverviewWidgets.js new file mode 100644 index 000000000..11d819175 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/OverviewWidgets/OverviewWidgets.js @@ -0,0 +1,105 @@ +import { widgetHOC } from '../common'; +import { TrendChart } from '../TrendChart'; +import { OVERVIEW_WIDGET_MAP } from 'Types/dashboard'; +import { camelCased } from 'App/utils'; +import { connect } from 'react-redux'; +import { updateAppearance } from 'Duck/user'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; +import cn from 'classnames'; +import stl from './overviewWidgets.css'; + +const customParams = rangeName => { + const params = { density: 16 } + + if (rangeName === LAST_24_HOURS) params.density = 16 + if (rangeName === LAST_30_MINUTES) params.density = 16 + if (rangeName === YESTERDAY) params.density = 16 + if (rangeName === LAST_7_DAYS) params.density = 16 + + return params +} + +@connect(state => ({ + dashboardAppearance: state.getIn([ 'user', 'account', 'appearance', 'dashboard' ]), + appearance: state.getIn([ 'user', 'account', 'appearance' ]), + comparing: state.getIn([ 'dashboard', 'comparing' ]), +}), { updateAppearance }) +@widgetHOC('overview', { customParams }, false) +export default class OverviewWidgets extends React.PureComponent { + handleRemove = widgetKey => { + const { appearance } = this.props; + this.props.updateAppearance(appearance.setIn([ 'dashboard', widgetKey ], false)); + } + render() { + const { data, dataCompare, loading, loadingCompare, dashboardAppearance, comparing } = this.props; + + const widgets = {} + const widgetsCompare = {} + data + .filter(item => dashboardAppearance[camelCased(item.key)]) // TODO should come filtered from API + .forEach(item => { + widgets[item.key] = item; + }) + + if (comparing) { + dataCompare + .filter(item => dashboardAppearance[camelCased(item.key)]) // TODO should come filtered from API + .forEach(item => { + widgetsCompare[item.key] = item; + }) + } + + return ( + + {Object.values(OVERVIEW_WIDGET_MAP).map(item => { + const widget = widgets[item.key] || {}; + item.data = widget ? widget.chart : {}; + + const widgetCompare = widgetsCompare[item.key] || {}; + if (comparing) { + item.dataCompare = widgetCompare ? widgetCompare.chart : {}; + } + if (!dashboardAppearance[item.key]) return; + + return ( +
    + this.handleRemove(item.key)} + comparing={comparing} + /> + {comparing && ( + +
    + this.handleRemove(item.key)} + comparing={comparing} + /> + + )} +
    + ) + })} +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/OverviewWidgets/overviewWidgets.css b/frontend/app/components/Dashboard/Widgets/OverviewWidgets/overviewWidgets.css new file mode 100644 index 000000000..c4f9d132c --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/OverviewWidgets/overviewWidgets.css @@ -0,0 +1,12 @@ +.wrapper { + border: dotted 2px transparent; + border-radius: 3px; + margin: -5px; + padding: 5px; + transition: all 0.3s; + + &:hover { + transition: all 0.2s; + border: dotted 2px $gray-medium; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PageMetrics.js b/frontend/app/components/Dashboard/Widgets/PageMetrics.js new file mode 100644 index 000000000..333b5b4cc --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PageMetrics.js @@ -0,0 +1,33 @@ +import { connect } from 'react-redux'; +import { Loader } from 'UI'; +import { CountBadge, Divider, widgetHOC } from './common'; + +@widgetHOC('pageMetrics') +export default class PageMetrics extends React.PureComponent { + render() { + const { data, loading } = this.props; + return ( +
    + + + + + +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/Performance/Performance.js b/frontend/app/components/Dashboard/Widgets/Performance/Performance.js new file mode 100644 index 000000000..7876f1ee8 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/Performance/Performance.js @@ -0,0 +1,199 @@ +import { connect } from 'react-redux'; +import { Map } from 'immutable'; +import cn from 'classnames'; +import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Legend } from 'recharts'; +import { Loader, TextEllipsis, Popup, Icon } from 'UI'; +import { TYPES } from 'Types/resource'; +import { LAST_24_HOURS, LAST_30_MINUTES, LAST_7_DAYS, LAST_30_DAYS } from 'Types/app/period'; +import { fetchPerformanseSearch } from 'Duck/dashboard'; +import { widgetHOC } from '../common'; + +import styles from './performance.css'; + +const BASE_KEY = 'resource'; + +const pagesColor = '#7FCC33'; +const imagesColor = '#40C4FF'; +const requestsColor = '#DAB72F'; + +@widgetHOC('performance', { fullwidth: true }) +@connect((state, props) => ({ + performanceChartSpecified: state.getIn([ 'dashboard', 'performanceChart' ]), + period: state.getIn([ 'dashboard', 'period' ]), + loading: state.getIn([ 'dashboard', 'performanceSearchRequest', 'loading' ]) || + props.loading, +}), { + fetchPerformanseSearch, +}) +export default class Performance extends React.PureComponent { + state = { + comparing: false, + resources: Map(), + opacity: {}, + } + + onResourceSelect = (resource) => { + if (!resource || this.state.resources.size > 1) return; + + resource.fillColor = this.getFillColor(resource); + resource.strokeColor = this.getStrokeColor(resource); + this.setResources(this.state.resources.set(this.state.resources.size, resource)); + } + + onResourceSelect0 = resource => this.onResourceSelect(0, resource) + onResourceSelect1 = resource => this.onResourceSelect(1, resource) + + getInterval = () => { + switch (this.props.period.rangeName) { + case LAST_30_MINUTES: + return 0; + case LAST_24_HOURS: + return 2; + case LAST_7_DAYS: + return 3; + case LAST_30_DAYS: + return 2; + default: + return 0; + } + } + + setResources = (resources) => { + this.setState({ + resources, + }); + this.props.fetchPerformanseSearch({ + ...this.props.period.toTimestamps(), + resources: resources.valueSeq().toJS(), + }); + } + + getFillColor = (resource) => { + switch (resource.type) { + case TYPES.IMAGE: + return 'url(#colorAvgImageLoadTime)'; + case TYPES.PAGE: + return 'url(#colorAvgPageLoadTime)'; + case TYPES.REQUEST: + return 'url(#colorAvgRequestLoadTime)'; + default: + return 'blue'; + } + } + + getStrokeColor = (resource) => { + switch (resource.type) { + case TYPES.IMAGE: + return imagesColor; + case TYPES.PAGE: + return pagesColor; + case TYPES.REQUEST: + return requestsColor; + default: + return 'blue'; + } + } + + removeResource = (index) => { + this.setResources(this.state.resources.remove(index)); + } + + compare = () => this.setState({ comparing: true }) + + legendPopup = (component, trigger) => + + legendFormatter = (value, entry, index) => { + const { opacity } = this.state; + + if (value === 'avgPageLoadTime') return (this.legendPopup(opacity.avgPageLoadTime === 0 ? 'Show' : 'Hide', {'Pages'})); + if (value === 'avgRequestLoadTime') return (this.legendPopup(opacity.avgRequestLoadTime === 0 ? 'Show' : 'Hide', {'Requests'})); + if (value === 'avgImageLoadTime') return (this.legendPopup(opacity.avgImageLoadTime === 0 ? 'Show' : 'Hide', {'Images'})); + // if (value === 'avgImageLoadTime') return ({'Images'}); + if (value.includes(BASE_KEY)) { + const resourceIndex = Number.parseInt(value.substr(BASE_KEY.length)); + return ( + + } + wide + content={ this.state.resources.getIn([ resourceIndex, 'value' ]) } + /> + ); + } + } + + handleLegendClick = (legend) => { + const { dataKey } = legend; + const { opacity } = this.state; + + if (dataKey === 'resource0') { + this.removeResource(0); + } else if (dataKey === 'resource1') { + this.removeResource(1); + } else { + this.setState({ + opacity: { ...opacity, [ dataKey ]: opacity[ dataKey ] === 0 ? 1 : 0 }, + }); + } + } + + // eslint-disable-next-line complexity + render() { + const { comparing, resources, opacity } = this.state; + const { data, performanceChartSpecified, loading } = this.props; + const r0Presented = !!resources.get(0); + const r1Presented = !!resources.get(1); + const resourcesPresented = r0Presented || r1Presented; + const defaultData = !resourcesPresented || performanceChartSpecified.length === 0; // TODO: more safe? + const interval = this.getInterval(); + + return ( + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + { defaultData && } + { defaultData && } + { defaultData && } + { !defaultData && r0Presented && } + { !defaultData && r1Presented && } + + + + +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/Performance/index.js b/frontend/app/components/Dashboard/Widgets/Performance/index.js new file mode 100644 index 000000000..63b30d682 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/Performance/index.js @@ -0,0 +1 @@ +export { default } from './Performance'; diff --git a/frontend/app/components/Dashboard/Widgets/Performance/performance.css b/frontend/app/components/Dashboard/Widgets/Performance/performance.css new file mode 100644 index 000000000..ab974bdc3 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/Performance/performance.css @@ -0,0 +1,3 @@ +.muted { + color: rgba(0, 0, 0, 0.3); +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/ProcessedSessions.js b/frontend/app/components/Dashboard/Widgets/ProcessedSessions.js new file mode 100644 index 000000000..9155e89a7 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ProcessedSessions.js @@ -0,0 +1,45 @@ +import { connect } from 'react-redux'; +import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area } from 'recharts'; +import { Loader } from 'UI'; +import { CountBadge, domain, widgetHOC, Styles } from './common'; + +@widgetHOC('sessions', { trendChart: true, fitContent: true }) +export default class ProcessedSessions extends React.PureComponent { + render() { + const { data, loading } = this.props; + const isMoreThanK = data.count > 1000; + const countView = isMoreThanK ? Math.trunc(data.count / 1000) : data.count; + + return ( +
    + + + + + + + + + + + + + + + + +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsResponseEnd/ResourceLoadedVsResponseEnd.js b/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsResponseEnd/ResourceLoadedVsResponseEnd.js new file mode 100644 index 000000000..23ed0047b --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsResponseEnd/ResourceLoadedVsResponseEnd.js @@ -0,0 +1,75 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { ComposedChart, Bar, CartesianGrid, Line, Legend, ResponsiveContainer, + XAxis, YAxis, Tooltip +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 30 } + + if (rangeName === LAST_24_HOURS) params.density = 24 + if (rangeName === LAST_30_MINUTES) params.density = 18 + if (rangeName === YESTERDAY) params.density = 24 + if (rangeName === LAST_7_DAYS) params.density = 30 + + return params +} + +@widgetHOC('resourceTypeVsResponseEnd', { customParams }) +export default class ResourceLoadedVsResponseEnd extends React.PureComponent { + render() { + const { data, loading, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + + return ( + + + + + + + Styles.tickFormatter(val, 'ms')} + yAxisId="left" + /> + Styles.tickFormatter(val, 'ms')} + label={{ + ...Styles.axisLabelLeft, + offset: 70, + value: "Response End (ms)" + }} + yAxisId="right" + orientation="right" + /> + + + + + + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsResponseEnd/index.js b/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsResponseEnd/index.js new file mode 100644 index 000000000..e56d66bcd --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsResponseEnd/index.js @@ -0,0 +1 @@ +export { default } from './ResourceLoadedVsResponseEnd'; diff --git a/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsVisuallyComplete/ResourceLoadedVsVisuallyComplete.js b/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsVisuallyComplete/ResourceLoadedVsVisuallyComplete.js new file mode 100644 index 000000000..ba5651c55 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsVisuallyComplete/ResourceLoadedVsVisuallyComplete.js @@ -0,0 +1,85 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { + ComposedChart, Bar, CartesianGrid, Line, Legend, ResponsiveContainer, + XAxis, YAxis, Tooltip +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 21 } + + if (rangeName === LAST_24_HOURS) params.density = 21 + if (rangeName === LAST_30_MINUTES) params.density = 21 + if (rangeName === YESTERDAY) params.density = 21 + if (rangeName === LAST_7_DAYS) params.density = 21 + + return params +} + +@widgetHOC('resourcesVsVisuallyComplete', { customParams }) +export default class ResourceLoadedVsVisuallyComplete extends React.PureComponent { + render() { + const {className, data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + + return ( + + + + + + + Styles.tickFormatter(val, 'ms')} + /> + Styles.tickFormatter(val)} + /> + + + + + + + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsVisuallyComplete/index.js b/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsVisuallyComplete/index.js new file mode 100644 index 000000000..6f3621b2e --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResourceLoadedVsVisuallyComplete/index.js @@ -0,0 +1 @@ +export { default } from './ResourceLoadedVsVisuallyComplete'; diff --git a/frontend/app/components/Dashboard/Widgets/ResourceLoadingTime/ResourceLoadingTime.js b/frontend/app/components/Dashboard/Widgets/ResourceLoadingTime/ResourceLoadingTime.js new file mode 100644 index 000000000..83f0a7625 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResourceLoadingTime/ResourceLoadingTime.js @@ -0,0 +1,133 @@ +import { Loader, NoContent, DropdownPlain } from 'UI'; +import { widgetHOC, Styles, AvgLabel } from '../common'; +import { withRequest } from 'HOCs'; +import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; +import WidgetAutoComplete from 'Shared/WidgetAutoComplete'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const WIDGET_KEY = 'resourcesLoadingTime'; +const toUnderscore = s => s.split(/(?=[A-Z])/).join('_').toLowerCase(); + +// other' = -1, 'script' = 0, 'stylesheet' = 1, 'fetch' = 2, 'img' = 3, 'media' = 4 +export const RESOURCE_OPTIONS = [ + { text: 'All', value: 'all', }, + { text: 'JS', value: "SCRIPT", }, + { text: 'CSS', value: "STYLESHEET", }, + { text: 'Fetch', value: "REQUEST", }, + { text: 'Image', value: "IMG", }, + { text: 'Media', value: "MEDIA", }, + { text: 'Other', value: "OTHER", }, +]; + +const customParams = rangeName => { + const params = {density: 70, type: null } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@withRequest({ + dataName: "options", + initialData: [], + dataWrapper: data => data, + loadingName: 'optionsLoading', + requestName: "fetchOptions", + endpoint: '/dashboard/' + toUnderscore(WIDGET_KEY) + '/search', + method: 'GET' +}) +@widgetHOC(WIDGET_KEY, { customParams }) +export default class ResourceLoadingTime extends React.PureComponent { + state = { autoCompleteSelected: null, type: null } + onSelect = (params) => { + const _params = customParams(this.props.period.rangeName) + this.setState({ autoCompleteSelected: params.value }); + this.props.fetchWidget(WIDGET_KEY, this.props.period, this.props.platform, { ..._params, url: params.value }) + } + + writeOption = (e, { name, value }) => { + this.setState({ [name]: value }) + const _params = customParams(this.props.period.rangeName) + this.props.fetchWidget(WIDGET_KEY, this.props.period, this.props.platform, { ..._params, [ name ]: value === 'all' ? null : value }) + } + + render() { + const { data, loading, period, optionsLoading, compare = false, showSync = false } = this.props; + const { autoCompleteSelected, type } = this.state; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + const gradientDef = Styles.gradientDef(); + + return ( + + +
    + + + +
    + + + + + {gradientDef} + + + Styles.tickFormatter(val)} + label={{ ...Styles.axisLabelLeft, value: "Resource Fetch Time (ms)" }} + /> + + + + + + +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ResourceLoadingTime/index.js b/frontend/app/components/Dashboard/Widgets/ResourceLoadingTime/index.js new file mode 100644 index 000000000..91072b5ec --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResourceLoadingTime/index.js @@ -0,0 +1 @@ +export { default } from './ResourceLoadingTime'; diff --git a/frontend/app/components/Dashboard/Widgets/ResponseTime/ResponseTime.js b/frontend/app/components/Dashboard/Widgets/ResponseTime/ResponseTime.js new file mode 100644 index 000000000..60f23042a --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResponseTime/ResponseTime.js @@ -0,0 +1,96 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, domain, Styles, AvgLabel } from '../common'; +import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; +import WidgetAutoComplete from 'Shared/WidgetAutoComplete'; +import { withRequest } from 'HOCs'; +import { toUnderscore } from 'App/utils'; + +const WIDGET_KEY = 'pagesResponseTime'; + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@withRequest({ + dataName: "options", + initialData: [], + dataWrapper: data => data, + // resetBeforeRequest: true, + loadingName: "optionsLoading", + requestName: "fetchOptions", + endpoint: '/dashboard/' + toUnderscore(WIDGET_KEY) + '/search', + method: 'GET' +}) +@widgetHOC(WIDGET_KEY, { customParams }) +export default class ResponseTime extends React.PureComponent { + onSelect = (params) => { + const _params = customParams(this.props.period.rangeName) + this.props.fetchWidget(WIDGET_KEY, this.props.period, this.props.platform, {..._params, url: params.value }, this.props.filters) + } + + render() { + const { data, loading, optionsLoading, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const gradientDef = Styles.gradientDef(); + + return ( + +
    + +
    + +
    +
    + + + + + {gradientDef} + + + `${val}` } + label={{ ...Styles.axisLabelLeft, value: "Page Response Time (ms)" }} + /> + + + + + + +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ResponseTime/index.js b/frontend/app/components/Dashboard/Widgets/ResponseTime/index.js new file mode 100644 index 000000000..c4228f56e --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResponseTime/index.js @@ -0,0 +1 @@ +export { default } from './ResponseTime'; diff --git a/frontend/app/components/Dashboard/Widgets/ResponseTimeDistribution/ResponseTimeDistribution.js b/frontend/app/components/Dashboard/Widgets/ResponseTimeDistribution/ResponseTimeDistribution.js new file mode 100644 index 000000000..10373abe6 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResponseTimeDistribution/ResponseTimeDistribution.js @@ -0,0 +1,139 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, domain, Styles, AvgLabel } from '../common'; +import { numberWithCommas } from 'App/utils'; +import { + ComposedChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, + XAxis, YAxis, ReferenceLine, Tooltip, Legend +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 40 } + + if (rangeName === LAST_24_HOURS) params.density = 40 + if (rangeName === LAST_30_MINUTES) params.density = 40 + if (rangeName === YESTERDAY) params.density = 40 + if (rangeName === LAST_7_DAYS) params.density = 40 + + return params +} + +const PercentileLine = props => { + const { + viewBox: { x, y }, + xoffset, + yheight, + height, + label + } = props; + return ( + + + + {label} + + + ); +}; + +@widgetHOC('pagesResponseTimeDistribution', { customParams }) +export default class ResponseTimeDistribution extends React.PureComponent { + render() { + const { data, loading, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + + return ( + + +
    + +
    +
    + + + + + + + 'Page Response Time: ' + val} /> + { data.percentiles.map((item, i) => ( + + } + allowDecimals={false} + x={item.responseTime} + strokeWidth={0} + strokeOpacity={1} + /> + ))} + + + + + + + + + + + +
    +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/ResponseTimeDistribution/index.js b/frontend/app/components/Dashboard/Widgets/ResponseTimeDistribution/index.js new file mode 100644 index 000000000..2ddc12a3c --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/ResponseTimeDistribution/index.js @@ -0,0 +1 @@ +export { default } from './ResponseTimeDistribution'; diff --git a/frontend/app/components/Dashboard/Widgets/SessionsAffectedByJSErrors/SessionsAffectedByJSErrors.js b/frontend/app/components/Dashboard/Widgets/SessionsAffectedByJSErrors/SessionsAffectedByJSErrors.js new file mode 100644 index 000000000..3fdffe6fd --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SessionsAffectedByJSErrors/SessionsAffectedByJSErrors.js @@ -0,0 +1,64 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles, AvgLabel } from '../common'; +import { + ComposedChart, Bar, CartesianGrid, Legend, ResponsiveContainer, + XAxis, YAxis, Tooltip +} from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 28 } + + if (rangeName === LAST_24_HOURS) params.density = 28 + if (rangeName === LAST_30_MINUTES) params.density = 28 + if (rangeName === YESTERDAY) params.density = 28 + if (rangeName === LAST_7_DAYS) params.density = 28 + + return params +} + +@widgetHOC('impactedSessionsByJsErrors', { customParams }) +export default class SessionsAffectedByJSErrors extends React.PureComponent { + render() { + const { data, loading, period, compare, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + + return ( + +
    +
    + +
    +
    + + + + + + + + + + + + + +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/SessionsAffectedByJSErrors/index.js b/frontend/app/components/Dashboard/Widgets/SessionsAffectedByJSErrors/index.js new file mode 100644 index 000000000..2af7f10db --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SessionsAffectedByJSErrors/index.js @@ -0,0 +1 @@ +export { default } from './SessionsAffectedByJSErrors'; diff --git a/frontend/app/components/Dashboard/Widgets/SessionsImpactedBySlowRequests/SessionsImpactedBySlowRequests.js b/frontend/app/components/Dashboard/Widgets/SessionsImpactedBySlowRequests/SessionsImpactedBySlowRequests.js new file mode 100644 index 000000000..743c8c57e --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SessionsImpactedBySlowRequests/SessionsImpactedBySlowRequests.js @@ -0,0 +1,62 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@widgetHOC('impactedSessionsBySlowPages', { customParams }) +export default class SessionsImpactedBySlowRequests extends React.PureComponent { + render() { + const { data, loading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + const gradientDef = Styles.gradientDef(); + + return ( + + + + + {gradientDef} + + + + + + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/SessionsImpactedBySlowRequests/index.js b/frontend/app/components/Dashboard/Widgets/SessionsImpactedBySlowRequests/index.js new file mode 100644 index 000000000..7e4adcc74 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SessionsImpactedBySlowRequests/index.js @@ -0,0 +1 @@ +export { default } from './SessionsImpactedBySlowRequests'; diff --git a/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/Bar.css b/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/Bar.css new file mode 100644 index 000000000..cf1b14578 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/Bar.css @@ -0,0 +1,20 @@ +.bar { + height: 10px; + width: 100%; + border-radius: 3px; + display: flex; + align-items: center; + & div { + padding: 0 5px; + height: 20px; + color: #FFF; + } + & div:first-child { + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + } + & div:last-child { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/Bar.js b/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/Bar.js new file mode 100644 index 000000000..f09b5c2ec --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/Bar.js @@ -0,0 +1,34 @@ +import React from 'react' +import stl from './Bar.css' +import { Styles } from '../common' +import { TextEllipsis } from 'UI'; + +const Bar = ({ className = '', versions = [], width = 0, avg, domain, colors }) => { + return ( +
    +
    +
    + {versions.map((v, i) => { + const w = (v.value * 100)/ avg; + return ( +
    + +
    Version: {v.key}
    +
    Sessions: {v.value}
    +
    + } /> +
    + ) + })} +
    +
    + {`${avg}`} +
    +
    +
    {domain}
    +
    + ) +} + +export default Bar \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/SessionsPerBrowser.js b/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/SessionsPerBrowser.js new file mode 100644 index 000000000..e2080f930 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/SessionsPerBrowser.js @@ -0,0 +1,42 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, AvgLabel, Styles } from '../common'; +import Bar from './Bar'; + +@widgetHOC('sessionsPerBrowser') +export default class SessionsPerBrowser extends React.PureComponent { + + getVersions = item => { + return Object.keys(item) + .filter(i => i !== 'browser' && i !== 'count') + .map(i => ({ key: 'v' +i, value: item[i]})) + } + + render() { + const { data, loading, compare = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const firstAvg = data.chart[0] && data.chart[0].count; + + return ( + + +
    + {data.chart.map((item, i) => + + )} +
    +
    +
    + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/index.js b/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/index.js new file mode 100644 index 000000000..facd495bd --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SessionsPerBrowser/index.js @@ -0,0 +1 @@ +export { default } from './SessionsPerBrowser'; diff --git a/frontend/app/components/Dashboard/Widgets/SlowestDomains/Bar.css b/frontend/app/components/Dashboard/Widgets/SlowestDomains/Bar.css new file mode 100644 index 000000000..d3d399918 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestDomains/Bar.css @@ -0,0 +1,6 @@ +.bar { + height: 10px; + background-color: red; + width: 100%; + border-radius: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SlowestDomains/Bar.js b/frontend/app/components/Dashboard/Widgets/SlowestDomains/Bar.js new file mode 100644 index 000000000..66e0875e1 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestDomains/Bar.js @@ -0,0 +1,19 @@ +import React from 'react' +import stl from './Bar.css' + +const Bar = ({ className = '', width = 0, avg, domain, color }) => { + return ( +
    +
    +
    +
    + {avg} + ms +
    +
    +
    {domain}
    +
    + ) +} + +export default Bar diff --git a/frontend/app/components/Dashboard/Widgets/SlowestDomains/SlowestDomains.js b/frontend/app/components/Dashboard/Widgets/SlowestDomains/SlowestDomains.js new file mode 100644 index 000000000..cff121f21 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestDomains/SlowestDomains.js @@ -0,0 +1,33 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import Bar from './Bar'; +import { numberWithCommas } from 'App/utils'; + +@widgetHOC('slowestDomains') +export default class ResponseTime extends React.PureComponent { + render() { + const { data, loading, compare = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const firstAvg = data.partition.first() && data.partition.first().avg; + + return ( + + +
    + {data.partition && data.partition.map((item, i) => + + )} +
    +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/SlowestDomains/index.js b/frontend/app/components/Dashboard/Widgets/SlowestDomains/index.js new file mode 100644 index 000000000..87f1e002a --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestDomains/index.js @@ -0,0 +1 @@ +export { default } from './SlowestDomains'; diff --git a/frontend/app/components/Dashboard/Widgets/SlowestImages/Chart.js b/frontend/app/components/Dashboard/Widgets/SlowestImages/Chart.js new file mode 100644 index 000000000..2a23c4f47 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestImages/Chart.js @@ -0,0 +1,13 @@ +import { AreaChart, Area } from 'recharts'; + +const Chart = ({ data }) => { + return ( + + + + ); +} + +Chart.displayName = 'Chart'; + +export default Chart; diff --git a/frontend/app/components/Dashboard/Widgets/SlowestImages/ImageInfo.js b/frontend/app/components/Dashboard/Widgets/SlowestImages/ImageInfo.js new file mode 100644 index 000000000..ad8c4294b --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestImages/ImageInfo.js @@ -0,0 +1,28 @@ +import { Popup, Icon } from 'UI'; +import styles from './imageInfo.css'; + +const ImageInfo = ({ data }) => ( +
    + + +
    { 'Preview' }
    +
    + } + content={ One of the slowest images } + /> + { data.name } + } + disabled + content={ data.url } + /> + +); + +ImageInfo.displayName = 'ImageInfo'; + +export default ImageInfo; diff --git a/frontend/app/components/Dashboard/Widgets/SlowestImages/SlowestImages.js b/frontend/app/components/Dashboard/Widgets/SlowestImages/SlowestImages.js new file mode 100644 index 000000000..fe48ceb81 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestImages/SlowestImages.js @@ -0,0 +1,53 @@ +import { connect } from 'react-redux'; +import { Loader, NoContent } from 'UI'; +import { Table, widgetHOC } from '../common'; +import Chart from './Chart'; +import ImageInfo from './ImageInfo'; + +const cols = [ + { + key: 'image', + title: 'Image', + Component: ImageInfo, + width: '40%', + }, + { + key: 'avgDuration', + title: 'Load Time', + toText: time => `${ Math.trunc(time) }ms`, + width: '25%', + }, + { + key: 'trend', + title: 'Trend', + Component: Chart, + width: '20%', + }, + { + key: 'sessions', + title: 'Sessions', + width: '15%', + toText: count => `${ count > 1000 ? Math.trunc(count / 1000) : count }${ count > 1000 ? 'k' : '' }`, + className: 'text-left' + }, +]; + +@widgetHOC('slowestImages', { fitContent: true }) +export default class SlowestImages extends React.PureComponent { + render() { + const { data: images, loading } = this.props; + return ( + + +
    + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/SlowestImages/imageInfo.css b/frontend/app/components/Dashboard/Widgets/SlowestImages/imageInfo.css new file mode 100644 index 000000000..69030a582 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestImages/imageInfo.css @@ -0,0 +1,39 @@ +.name { + display: flex; + align-items: center; + + & > span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 60%; + } +} + +.imagePreview { + max-width: 200px; + max-height: 200px; +} + +.imageWrapper { + display: flex; + flex-flow: column; + align-items: center; + width: 40px; + text-align: center; + margin-right: 10px; + & > span { + height: 16px; + } + & .label { + font-size: 9px; + color: $gray-light; + } +} + +.popup { + background-color: #f5f5f5 !important; + &:before { + background-color: #f5f5f5 !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SlowestImages/index.js b/frontend/app/components/Dashboard/Widgets/SlowestImages/index.js new file mode 100644 index 000000000..54bcac137 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestImages/index.js @@ -0,0 +1 @@ +export { default } from './SlowestImages'; diff --git a/frontend/app/components/Dashboard/Widgets/SlowestResources/Chart.js b/frontend/app/components/Dashboard/Widgets/SlowestResources/Chart.js new file mode 100644 index 000000000..6697b6fb4 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestResources/Chart.js @@ -0,0 +1,15 @@ +import { AreaChart, Area } from 'recharts'; +import { Styles } from '../common'; + +const Chart = ({ data, compare }) => { + const colors = compare ? Styles.compareColors : Styles.colors; + return ( + + + + ); +} + +Chart.displayName = 'Chart'; + +export default Chart; diff --git a/frontend/app/components/Dashboard/Widgets/SlowestResources/CopyPath.js b/frontend/app/components/Dashboard/Widgets/SlowestResources/CopyPath.js new file mode 100644 index 000000000..6b7e709e7 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestResources/CopyPath.js @@ -0,0 +1,23 @@ +import React from 'react' +import copy from 'copy-to-clipboard' +import { useState } from 'react' + +const CopyPath = ({ data }) => { + const [copied, setCopied] = useState(false) + + const copyHandler = () => { + copy(data.url); + setCopied(true); + setTimeout(function() { + setCopied(false) + }, 500); + } + + return ( +
    + { copied ? 'Copied' : 'Copy Path'} +
    + ) +} + +export default CopyPath diff --git a/frontend/app/components/Dashboard/Widgets/SlowestResources/ImageInfo.js b/frontend/app/components/Dashboard/Widgets/SlowestResources/ImageInfo.js new file mode 100644 index 000000000..fed6b71b6 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestResources/ImageInfo.js @@ -0,0 +1,27 @@ +import { Popup } from 'UI'; +import cn from 'classnames'; +import styles from './imageInfo.css'; + +const supportedTypes = ['png', 'jpg', 'jpeg', 'svg']; + +const ImageInfo = ({ data }) => { + const canPreview = supportedTypes.includes(data.type); + return ( +
    + +
    {data.name}
    +
    + } + disabled={!canPreview} + content={ One of the slowest images } + /> + + ) +}; + +ImageInfo.displayName = 'ImageInfo'; + +export default ImageInfo; diff --git a/frontend/app/components/Dashboard/Widgets/SlowestResources/ResourceType.js b/frontend/app/components/Dashboard/Widgets/SlowestResources/ResourceType.js new file mode 100644 index 000000000..9803a050f --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestResources/ResourceType.js @@ -0,0 +1,12 @@ +import React from 'react' +import cn from 'classnames' + +const ResourceType = ({ data : { type = 'js' }, compare }) => { + return ( +
    + { type.toUpperCase() } +
    + ) +} + +export default ResourceType diff --git a/frontend/app/components/Dashboard/Widgets/SlowestResources/SlowestResources.css b/frontend/app/components/Dashboard/Widgets/SlowestResources/SlowestResources.css new file mode 100644 index 000000000..42a6c55a1 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestResources/SlowestResources.css @@ -0,0 +1,7 @@ +.topActions { + position: absolute; + top: 0px; + right: 50px; + display: flex; + justify-content: flex-end; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SlowestResources/SlowestResources.js b/frontend/app/components/Dashboard/Widgets/SlowestResources/SlowestResources.js new file mode 100644 index 000000000..830326b87 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestResources/SlowestResources.js @@ -0,0 +1,96 @@ +import { Loader, NoContent, DropdownPlain } from 'UI'; +import { Table, widgetHOC } from '../common'; +import Chart from './Chart'; +import ImageInfo from './ImageInfo'; +import { getRE } from 'App/utils'; +import cn from 'classnames'; +import stl from './SlowestResources.css'; +import ResourceType from './ResourceType'; +import CopyPath from './CopyPath'; +import { numberWithCommas } from 'App/utils'; + +export const RESOURCE_OPTIONS = [ + { text: 'All', value: 'ALL', }, + { text: 'CSS', value: 'STYLESHEET', }, + { text: 'JS', value: 'SCRIPT', }, +]; + +const cols = [ + { + key: 'type', + title: 'Type', + Component: ResourceType, + className: 'text-center justify-center', + cellClass: 'ml-2', + width: '8%', + }, + { + key: 'name', + title: 'File Name', + Component: ImageInfo, + cellClass: '-ml-2', + width: '40%', + }, + { + key: 'avg', + title: 'Load Time', + toText: avg => `${ avg ? numberWithCommas(Math.trunc(avg)) : 0} ms`, + className: 'justify-center', + width: '15%', + }, + { + key: 'trend', + title: 'Trend', + Component: Chart, + width: '15%', + }, + { + key: 'copy-path', + title: '', + Component: CopyPath, + cellClass: 'invisible group-hover:visible text-right', + width: '15%', + } +]; +const WIDGET_KEY = 'slowestResources' + +@widgetHOC(WIDGET_KEY, { fitContent: true }) +export default class SlowestResources extends React.PureComponent { + state = { resource: 'all', search: ''} + + test = (key, value = '') => getRE(key, 'i').test(value); + + write = ({ target: { name, value } }) => { + this.setState({ [ name ]: value }) + }; + + writeOption = (e, { name, value }) => { + this.setState({ [ name ]: value }) + this.props.fetchWidget(WIDGET_KEY, this.props.period, this.props.platform, { [ name ]: value === 'all' ? null : value }) + } + + render() { + const { data, loading, compare } = this.props; + + return ( +
    +
    + +
    + + +
    + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/SlowestResources/imageInfo.css b/frontend/app/components/Dashboard/Widgets/SlowestResources/imageInfo.css new file mode 100644 index 000000000..1de36b529 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestResources/imageInfo.css @@ -0,0 +1,52 @@ +.name { + display: flex; + align-items: center; + + & > span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 60%; + } + + & .label { + max-width: 300px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.hasPreview { + /* text-decoration: underline; */ + border-bottom: 1px dotted; + cursor: pointer; +} + +.imagePreview { + max-width: 200px; + max-height: 200px; +} + +.imageWrapper { + display: flex; + flex-flow: column; + align-items: center; + width: 40px; + text-align: center; + margin-right: 10px; + & > span { + height: 16px; + } + & .label { + font-size: 9px; + color: $gray-light; + } +} + +.popup { + background-color: #f5f5f5 !important; + &:before { + background-color: #f5f5f5 !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SlowestResources/index.js b/frontend/app/components/Dashboard/Widgets/SlowestResources/index.js new file mode 100644 index 000000000..22fd02391 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SlowestResources/index.js @@ -0,0 +1 @@ +export { default } from './SlowestResources'; diff --git a/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Bar.css b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Bar.css new file mode 100644 index 000000000..d3d399918 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Bar.css @@ -0,0 +1,6 @@ +.bar { + height: 10px; + background-color: red; + width: 100%; + border-radius: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Bar.js b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Bar.js new file mode 100644 index 000000000..4da50d6ae --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Bar.js @@ -0,0 +1,16 @@ +import React from 'react' +import stl from './Bar.css' + +const Bar = ({ className = '', width = 0, avg, domain, color }) => { + return ( +
    +
    +
    +
    {avg}
    +
    +
    {domain}
    +
    + ) +} + +export default Bar diff --git a/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Scale.js b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Scale.js new file mode 100644 index 000000000..7bf6f8f5d --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/Scale.js @@ -0,0 +1,24 @@ +import React from 'react' +import { Styles } from '../common'; +import cn from 'classnames'; +import stl from './scale.css'; + +function Scale({ colors }) { + const lastIndex = (Styles.colors.length - 1) + return ( +
    + {colors.map((c, i) => ( +
    + { i === 0 &&
    Slow
    } + { i === lastIndex &&
    Fast
    } +
    + ))} +
    + ) +} + +export default Scale diff --git a/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/SpeedIndexLocation.js b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/SpeedIndexLocation.js new file mode 100644 index 000000000..86a5419e1 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/SpeedIndexLocation.js @@ -0,0 +1,96 @@ +import { widgetHOC, AvgLabel, Styles } from '../common'; +import * as DataMap from "datamaps"; +import { threeLetter } from 'App/constants/countries'; +import Scale from './Scale'; +import { numberWithCommas } from 'App/utils'; +import stl from './speedIndexLocation.css'; +import { colorScale } from 'App/utils'; + +@widgetHOC('speedLocation', { fitContent: false }) +export default class SpeedIndexLocation extends React.PureComponent { + wrapper = React.createRef() + map = null; + + getSeries = data => { + const series = []; + data.chart.forEach(item => { + const d = [threeLetter[item.userCountry], Math.round(item.avg)] + series.push(d) + }) + + return series; + } + + componentDidUpdate(prevProps) { + if (this.map) { + this.map.updateChoropleth(this.getDataset(), { reset: true}); + } + } + + getDataset = () => { + const { data, compare } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + + var dataset = {}; + const series = this.getSeries(data); + var onlyValues = series.map(function(obj){ return obj[1]; }); + const paletteScale = colorScale(onlyValues, [...colors].reverse()); + + // fill dataset in appropriate format + series.forEach(function(item){ + var iso = item[0], value = item[1]; + dataset[iso] = { numberOfThings: value, fillColor: paletteScale(value) }; + }); + return dataset; + } + + render() { + const { data, loading, compare = false } = this.props; + + + if (this.wrapper.current && !this.map && data.chart.length > 0) { + const dataset = this.getDataset(); + this.map = new DataMap({ + element: this.wrapper.current, + fills: { defaultFill: '#E8E8E8' }, + data: dataset, + // responsive: true, + // height: null, //if not null, datamaps will grab the height of 'element' + // width: null, //if not null, datamaps will grab the width of 'element' + geographyConfig: { + borderColor: '#FFFFFF', + borderWidth: 0.5, + highlightBorderWidth: 1, + popupOnHover: true, + // don't change color on mouse hover + highlightFillColor: function(geo) { + return '#999999'; + // return geo['fillColor'] || '#F5F5F5'; + }, + // only change border + highlightBorderColor: '#B7B7B7', + // show desired information in tooltip + popupTemplate: function(geo, data) { + // don't show tooltip if country don't present in dataset + if (!data) { return ; } + // tooltip content + return ['
    ', + '', geo.properties.name, '', + 'Avg: ', numberWithCommas(data.numberOfThings), '', + '
    '].join(''); + } + } + }); + } + + return ( + <> +
    + +
    + +
    + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/index.js b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/index.js new file mode 100644 index 000000000..d62ce8efc --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/index.js @@ -0,0 +1 @@ +export { default } from './SpeedIndexLocation'; diff --git a/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/scale.css b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/scale.css new file mode 100644 index 000000000..5aa34f966 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/scale.css @@ -0,0 +1,11 @@ +.bars { + & div:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; + } + + & div:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/speedIndexLocation.css b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/speedIndexLocation.css new file mode 100644 index 000000000..1a433dc85 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/SpeedIndexLocation/speedIndexLocation.css @@ -0,0 +1,6 @@ +.mapWrapper { + height: 220px; + width: 90%; + margin: 0 auto; + display: flex; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/TimeToRender/TimeToRender.js b/frontend/app/components/Dashboard/Widgets/TimeToRender/TimeToRender.js new file mode 100644 index 000000000..a6589a7da --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/TimeToRender/TimeToRender.js @@ -0,0 +1,95 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles, AvgLabel } from '../common'; +import { withRequest } from 'HOCs'; +import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; +import WidgetAutoComplete from 'Shared/WidgetAutoComplete'; +import { toUnderscore } from 'App/utils'; +import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; + +const WIDGET_KEY = 'timeToRender'; +const customParams = rangeName => { + const params = { density: 70 } + + if (rangeName === LAST_24_HOURS) params.density = 70 + if (rangeName === LAST_30_MINUTES) params.density = 70 + if (rangeName === YESTERDAY) params.density = 70 + if (rangeName === LAST_7_DAYS) params.density = 70 + + return params +} + +@withRequest({ + dataName: "options", + initialData: [], + dataWrapper: data => data, + loadingName: "optionsLoading", + requestName: "fetchOptions", + endpoint: '/dashboard/' + toUnderscore(WIDGET_KEY) + '/search', + method: 'GET' +}) +@widgetHOC(WIDGET_KEY, { customParams }) +export default class TimeToRender extends React.PureComponent { + onSelect = (params) => { + const _params = customParams(this.props.period.rangeName) + this.props.fetchWidget(WIDGET_KEY, this.props.period, this.props.platform, { ..._params, url: params.value }, this.props.filters) + } + + render() { + const { data, loading, optionsLoading, period, compare = false, showSync = false } = this.props; + const colors = compare ? Styles.compareColors : Styles.colors; + const params = customParams(period.rangeName) + const gradientDef = Styles.gradientDef(); + + return ( + +
    + +
    + +
    +
    + + + + + {gradientDef} + + + Styles.tickFormatter(val)} + /> + + + + + + +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/TimeToRender/index.js b/frontend/app/components/Dashboard/Widgets/TimeToRender/index.js new file mode 100644 index 000000000..9c4c77c12 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/TimeToRender/index.js @@ -0,0 +1 @@ +export { default } from './TimeToRender'; diff --git a/frontend/app/components/Dashboard/Widgets/TopDomains/TopDomains.js b/frontend/app/components/Dashboard/Widgets/TopDomains/TopDomains.js new file mode 100644 index 000000000..e5994da01 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/TopDomains/TopDomains.js @@ -0,0 +1,61 @@ +import { Loader, NoContent } from 'UI'; +import { widgetHOC, Styles } from '../common'; +import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, + LineChart, Line, Legend, Tooltip +} from 'recharts'; + +@widgetHOC('domainsErrors', { fitContent: true }) +export default class TopDomains extends React.PureComponent { + render() { + const { data, loading, key = '4xx' } = this.props; + + const namesMap = data.chart[key] + .map(i => Object.keys(i)) + .flat() + .filter(i => i !== 'time' && i !== 'timestamp') + .reduce( + (unique, item) => (unique.includes(item) ? unique : [...unique, item]), + [] + ); + + return ( + + + + + + + + + + + + + + + + { namesMap.map((key, index) => ( + + ))} + + + + + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/TopDomains/index.js b/frontend/app/components/Dashboard/Widgets/TopDomains/index.js new file mode 100644 index 000000000..33cefa725 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/TopDomains/index.js @@ -0,0 +1 @@ +export { default } from './TopDomains'; diff --git a/frontend/app/components/Dashboard/Widgets/TopMetrics.js b/frontend/app/components/Dashboard/Widgets/TopMetrics.js new file mode 100644 index 000000000..2134b3e1e --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/TopMetrics.js @@ -0,0 +1,56 @@ +import { connect } from 'react-redux'; +import { Loader } from 'UI'; +import { msToSec } from 'App/date'; +import { CountBadge, Divider, widgetHOC } from './common'; + +@widgetHOC('topMetrics') +export default class TopMetrics extends React.PureComponent { + render() { + const { data, loading } = this.props; + return ( +
    + +
    + + + + {/* */} +
    +
    + + + +
    +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/TrendChart/TrendChart.js b/frontend/app/components/Dashboard/Widgets/TrendChart/TrendChart.js new file mode 100644 index 000000000..a9f305b0f --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/TrendChart/TrendChart.js @@ -0,0 +1,107 @@ +import React from 'react'; +import { Styles, CountBadge } from '../common'; +import { CloseButton, Loader } from 'UI'; +import { ResponsiveContainer, AreaChart, XAxis, YAxis, Area, Tooltip } from 'recharts'; +import { numberWithCommas } from 'App/utils'; +import cn from 'classnames'; +import stl from './trendChart.css'; + +const loadChart = (data, loading, unit, syncId, compare, tooltipLael) => { + const gradientDef = Styles.gradientDef(); + return ( +
    + + + + {gradientDef} + + + + + + + +
    + ) +} + +const countView = (avg, unit) => { + if (unit === 'mb') { + if (!avg) return 0; + const count = Math.trunc(avg / 1024 / 1024); + return numberWithCommas(count); + } + if (unit === 'min') { + if (!avg) return 0; + const count = Math.trunc(avg); + return numberWithCommas(count > 1000 ? count +'k' : count); + } + return avg ? numberWithCommas(avg): 0; +} + +function TrendChart({ + loading = true, + title, + avg, + progress, + unit = false, + subtext, + data, + handleRemove, + compare = false, + comparing = false, + syncId = '', + tooltipLael = '', + textClass ='', + prefix = '', + canRemove = true +}) { + return ( +
    + { canRemove && ( + + )} +
    +
    + {comparing &&
    } +
    { title }
    +
    +
    + {prefix} + {/*
    */} + {/*
    */} + {/*
    */} + +
    +
    + { loadChart(data, loading, unit, syncId, compare, tooltipLael) } +
    + ) +} + +export default TrendChart diff --git a/frontend/app/components/Dashboard/Widgets/TrendChart/index.js b/frontend/app/components/Dashboard/Widgets/TrendChart/index.js new file mode 100644 index 000000000..bdf7f32b2 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/TrendChart/index.js @@ -0,0 +1 @@ +export { default as TrendChart } from './TrendChart'; diff --git a/frontend/app/components/Dashboard/Widgets/TrendChart/trendChart.css b/frontend/app/components/Dashboard/Widgets/TrendChart/trendChart.css new file mode 100644 index 000000000..e69fb4878 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/TrendChart/trendChart.css @@ -0,0 +1,6 @@ +.circle { + width: 8px; + height: 8px; + border-radius: 50%; + margin-right: 5px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/UserActivity.js b/frontend/app/components/Dashboard/Widgets/UserActivity.js new file mode 100644 index 000000000..48952315c --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/UserActivity.js @@ -0,0 +1,31 @@ +import { connect } from 'react-redux'; +import { msToMin } from 'App/date'; +import { Loader } from 'UI'; +import { CountBadge, Divider, widgetHOC } from './common'; + +@widgetHOC('userActivity') +export default class UserActivity extends React.PureComponent { + render() { + const { data, loading } = this.props; + return ( +
    + + + + + +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/common/AutoComplete/AutoComplete.js b/frontend/app/components/Dashboard/Widgets/common/AutoComplete/AutoComplete.js new file mode 100644 index 000000000..5923d4c5d --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/AutoComplete/AutoComplete.js @@ -0,0 +1,86 @@ +import React, { useState } from 'react'; +import { Icon, CircularLoader, Button } from 'UI'; +import cn from 'classnames'; +import stl from './autoComplete.css'; +import { debounce } from 'App/utils'; + +const AutoComplete = props => { + const { className, placeholder = "Search for Resource", itemStyle = {}, filterParams = {} } = props; + const [selected, setSelected] = useState(null) + const [focused, setFocused] = useState(props.autoFocus) + + const fetchOptions = debounce(props.fetchOptions, 300) + + const handleChange = ({ target: { name, value } }) => { + fetchOptions({ ...filterParams, q: value }); + } + + const onSelected = opt => { + setSelected(opt); + props.onSelect(opt); + } + + const onItemClick = (e, { name, value }) => { + props.onSelect({ url: value }); + setSelected(value); + } + + const onClearHandle = (e) => { + e.preventDefault(); + e.stopPropagation(); + + setSelected(null); + props.onSelect({}); + } + + return ( +
    +
    !focused && setFocused(true)} + > + { !focused && selected && ( +
    + {selected.value} + +
    + )} + { (focused || !selected) && ( + setFocused(true)} + onBlur={() => setFocused(false)} + /> + )} +
    + { props.loading && } +
    +
    + { focused && props.options.length > 0 && ( +
    + { + props.options.map(opt => ( +
    onSelected(opt)} + style={itemStyle} + > + {opt.value} +
    + )) + } +
    + )} +
    + ) +} + +export default AutoComplete diff --git a/frontend/app/components/Dashboard/Widgets/common/AutoComplete/autoComplete.css b/frontend/app/components/Dashboard/Widgets/common/AutoComplete/autoComplete.css new file mode 100644 index 000000000..fc2b23384 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/AutoComplete/autoComplete.css @@ -0,0 +1,85 @@ +.searchWrapper { + width: 250px; + padding: 10px 5px; + height: 30px; + border-radius: 3px; + cursor: pointer; + border: solid thin transparent; + margin: 0 -5px; + &:after { + content: ''; + width: 100%; + border-bottom: dotted thin $gray-light; + position: absolute; + right: 5px; + bottom: 0; + } + & input { + padding: 0 5px; + } + &:hover { + border: solid thin $gray-light; + &:after { + display: none; + } + } + &.focused { + background-color: $gray-light; + &:after { + display: none; + } + } +} + +.selected { + width: 100%; + & span { + max-width: 210px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.search { + padding: 8px 0; + border: none; + &:focus, &:active { + border: none !important; + } +} + +.menuWrapper { + display: flex; + flex-direction: column; + & > div { + flex-shrink: 0; + } + + border: solid thin $gray-light; + top: 31px; + z-index: 1; + margin-left: -5px; + max-height: 180px; + overflow-y: auto; + &::-webkit-scrollbar { + width: 1px; + } +} + +.optionItem { + border-bottom: solid thin $gray-light; + padding: 8px; + max-width: 250px; + /* max-width: 90%; */ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + &:last-child { + border-bottom: none; + } + &:hover { + background-color: $gray-lightest; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/AutoComplete/index.js b/frontend/app/components/Dashboard/Widgets/common/AutoComplete/index.js new file mode 100644 index 000000000..7560dd22b --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/AutoComplete/index.js @@ -0,0 +1 @@ +export { default } from './AutoComplete'; diff --git a/frontend/app/components/Dashboard/Widgets/common/AvgLabel.js b/frontend/app/components/Dashboard/Widgets/common/AvgLabel.js new file mode 100644 index 000000000..a5424597a --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/AvgLabel.js @@ -0,0 +1,13 @@ +import React from 'react' +import { numberWithCommas } from 'App/utils'; + +const AvgLabel = ({ className, text, count, unit}) => +
    + {text} + + {count ? numberWithCommas(Math.round(count)) : 0} + + {unit && {unit}} +
    + +export default AvgLabel diff --git a/frontend/app/components/Dashboard/Widgets/common/CountBadge.js b/frontend/app/components/Dashboard/Widgets/common/CountBadge.js new file mode 100644 index 000000000..86e93ebd5 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/CountBadge.js @@ -0,0 +1,49 @@ +import { Icon } from 'UI'; +import styles from './countBadge.css'; +import cn from 'classnames'; + +const getFixedValue = (val) => { + let accuracy = 0; + while (Math.trunc(val * Math.pow(10, accuracy)) === 0) { + accuracy += 1; + } + const parsed = parseFloat(val).toFixed(accuracy).toString(); + return parsed; +}; + +// eslint-disable-next-line complexity +const CountBadge = ({ + title, + icon, + count = '', + unit = '', + change, + oppositeColors = false, + component, + className +}) => { + const viewChange = typeof change === 'number' && change !== 0 ; + const changeIncrease = change > 0; + const colorGreen = oppositeColors ? !changeIncrease : changeIncrease; + return ( +
    +
    + { icon && } + { component || count } + { unit } +
    +
    + { viewChange && +
    + + { `${ getFixedValue(change) }%` } +
    + } +
    +
    + ); +} + +CountBadge.displayName = 'CountBadge'; + +export default CountBadge; diff --git a/frontend/app/components/Dashboard/Widgets/common/CustomTooltip.js b/frontend/app/components/Dashboard/Widgets/common/CustomTooltip.js new file mode 100644 index 000000000..035388fda --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/CustomTooltip.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { numberWithCommas } from 'App/utils'; + +const TooltipLabel = ({ payload, unit = false }) => { + if (!payload) return ''; + const value = numberWithCommas(Math.round(payload.value)); + return ( +
    + {`${payload.name}: ${value}`} + { unit && ms} +
    + ) +} + +const CustomTooltip = ({ active, payload, label, unit }) => { + if (active && payload && payload[0]) { + return ( +
    +
    {`${label}`}
    + {payload.map(p => ( ))} +
    + ); + } + + return null; +} + +export default CustomTooltip diff --git a/frontend/app/components/Dashboard/Widgets/common/Divider.js b/frontend/app/components/Dashboard/Widgets/common/Divider.js new file mode 100644 index 000000000..e5e2147e3 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/Divider.js @@ -0,0 +1,11 @@ +const Divider = () => ( +
    +); + +export default Divider; diff --git a/frontend/app/components/Dashboard/Widgets/common/SessionLine.js b/frontend/app/components/Dashboard/Widgets/common/SessionLine.js new file mode 100644 index 000000000..8322c1fc9 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/SessionLine.js @@ -0,0 +1,37 @@ +import cn from 'classnames'; +import { session as sessionRoute } from 'App/routes'; +import { Link, Icon, TextEllipsis } from 'UI'; +import stl from './sessionLine.css'; + +const FeedbackLine = ({ + icon, + info, + subInfo, + sessionId, +}) => { + + return ( +
    + { icon && } +
    + { info && + + { info } + + } + { subInfo && +
    + { subInfo } +
    + } +
    + + + +
    + ); +} + +FeedbackLine.displayName = 'FeedbackLine'; + +export default FeedbackLine; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/Styles.js b/frontend/app/components/Dashboard/Widgets/common/Styles.js new file mode 100644 index 000000000..21bcfbde7 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/Styles.js @@ -0,0 +1,82 @@ +import { numberWithCommas } from 'App/utils'; + +const colors = ['#3EAAAF', '#5FBABF', '#7BCBCF', '#96DCDF', '#ADDCDF']; +const colorsx = ['#256669', '#38999e', '#3eaaaf', '#51b3b7', '#78c4c7', '#9fd5d7', '#c5e6e7'].reverse(); +const compareColors = ['#394EFF', '#4D5FFF', '#808DFF', '#B3BBFF', '#E5E8FF']; +const compareColorsx = ["#222F99", "#2E3ECC", "#394EFF", "#6171FF", "#8895FF", "#B0B8FF", "#D7DCFF"].reverse(); + +const countView = count => { + const isMoreThanK = count >= 1000; + return numberWithCommas(isMoreThanK ? Math.trunc(count / 1000) + 'k' : count); +} + +export default { + colors, + colorsx, + compareColors, + compareColorsx, + lineColor: '#2A7B7F', + lineColorCompare: '#394EFF', + xaxis: { + axisLine: { stroke: '#CCCCCC' }, + interval: 0, + dataKey: "time", + tick: { fill: '#999999', fontSize: 9 }, + tickLine: { stroke: '#CCCCCC' }, + strokeWidth: 0.5 + }, + yaxis: { + axisLine: { stroke: '#CCCCCC' }, + tick: { fill: '#999999', fontSize: 9 }, + tickLine: { stroke: '#CCCCCC' }, + }, + axisLabelLeft: { + angle: -90, + fill: '#999999', + offset: 10, + style: { textAnchor: 'middle' }, + position: 'insideLeft', + fontSize: 11 + }, + tickFormatter: val => `${countView(val)}`, + tickFormatterBytes: val => Math.round(val / 1024 / 1024), + chartMargins: { left: 0, right: 20, top: 10, bottom: 5 }, + tooltip: { + cursor: { + fill: '#f6f6f6' + }, + contentStyle: { + padding: '5px', + background: 'white', + border: '1px solid #DDD', + borderRadius: '3px', + lineHeight: '1.25rem', + color: '#888', + fontSize: '10px' + }, + labelStyle: {}, + formatter: (value, name, { unit }) => { + if (unit && unit.trim() === 'mb') { + return numberWithCommas(Math.round(value / 1024 / 1024)) + } + return numberWithCommas(Math.round(value)) + }, + itemStyle: { + lineHeight: '0.75rem', + color: '#000', + fontSize: '12px' + } + }, + gradientDef: () => ( + + + + + + + + + + + ) +}; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/Table.js b/frontend/app/components/Dashboard/Widgets/common/Table.js new file mode 100644 index 000000000..0aecca5ea --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/Table.js @@ -0,0 +1,62 @@ +import cn from 'classnames'; +import { Button } from 'UI'; +import stl from './table.css'; + +export default class Table extends React.PureComponent { + state = { showAll: false }; + + onLoadMoreClick = () => { + this.setState({ showAll: true }); + } + + render() { + const { + cols, + rows = [], + rowProps, + rowClass = '', + small = false, + compare = false + } = this.props; + const { showAll } = this.state; + + return ( +
    +
    + { + cols.map(({ + key, title, width, + }) => +
    { title }
    ) + } +
    +
    + { rows.take(showAll ? 10 : (small ? 3 : 5)).map(row => ( +
    + { cols.map(({ cellClass = '', className = '', Component, key, toText = t => t, width }) => ( +
    { Component + ? + :
    { toText(row[ key ]) }
    + } +
    + )) } +
    + )) } + + { rows.size > (small ? 3 : 5) && !showAll && +
    + +
    + } +
    +
    + ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/common/Title.js b/frontend/app/components/Dashboard/Widgets/common/Title.js new file mode 100644 index 000000000..e8b31422e --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/Title.js @@ -0,0 +1,12 @@ +import styles from './title.css'; + +const Title = ({ title, sub }) => ( +
    +

    { title }

    + { sub } +
    +); + +Title.displayName = 'Title'; + +export default Title; diff --git a/frontend/app/components/Dashboard/Widgets/common/countBadge.css b/frontend/app/components/Dashboard/Widgets/common/countBadge.css new file mode 100644 index 000000000..5b6c54d64 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/countBadge.css @@ -0,0 +1,40 @@ +.title { + color: $gray-medium; + font-size: 11px; + margin-bottom: 15px; +} + +.icon { + height: 16px; +} + +.countWrapper { + height: 24px; + margin-top: -5px; +} +.count { + font-size: 20px; + font-weight: 500; +} + +.unit { + font-size: 15px; + align-self: flex-end; + margin-left: 5px; + margin-bottom: 3px; +} + +.change { + font-size: 12px; + min-height: 20px; + & > div { + display: flex; + align-items: center; + } + &[data-colorgreen=true] { + color: $green; + } + &[data-colorgreen=false] { + color: $red; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/domain.js b/frontend/app/components/Dashboard/Widgets/common/domain.js new file mode 100644 index 000000000..f00ac7395 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/domain.js @@ -0,0 +1,5 @@ +export default [ 0, dataMax => { + if (dataMax === 0) return 10; + if (dataMax > 100 || dataMax < 0) return dataMax; + return dataMax * (5.7 - Math.log(dataMax)); +} ]; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/index.js b/frontend/app/components/Dashboard/Widgets/common/index.js new file mode 100644 index 000000000..52ca30580 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/index.js @@ -0,0 +1,9 @@ +export { default as Title } from './Title'; +export { default as CountBadge } from './CountBadge'; +export { default as Table } from './Table'; +export { default as Divider } from './Divider'; +export { default as domain } from './domain'; +export { default as widgetHOC } from './widgetHOC'; +export { default as SessionLine } from './SessionLine'; +export { default as Styles } from './Styles'; +export { default as AvgLabel } from './AvgLabel'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/sessionLine.css b/frontend/app/components/Dashboard/Widgets/common/sessionLine.css new file mode 100644 index 000000000..3855aef0d --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/sessionLine.css @@ -0,0 +1,30 @@ +.wrapper { + padding: 12px 0 8px; + margin: 0 5px; + border-bottom: 1px solid $gray-light; +} + +.info { + font-size: 15px; +} + +.subInfo { + color: $gray-medium; + font-size: 12px; +} + +.link { + position: absolute; + right: 0; + opacity: 0; +} + +.wrapper:hover { + & .link { + opacity: 1; + } +} + +.ellipsisWrapper { + overflow: hidden; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/table.css b/frontend/app/components/Dashboard/Widgets/common/table.css new file mode 100644 index 000000000..648f5bba5 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/table.css @@ -0,0 +1,39 @@ +.header { + padding: 10px 0; + font-weight: 500; + flex-grow: 0; + flex-shrink: 0; +} + +.topBorder { + height: 1px; + background-color: $gray-light-shade; + margin-top: 6px; + width: 100%; +} + +.content { + overflow-y: auto; + max-height: 340px; + &.small { + height: 201px; + } +} + +.row { + display: flex; + border-bottom: 1px solid #EFEFEF; + align-items: center; + min-height: 54px; + font-size: 13px; + + & .cell { + flex-grow: 0; + flex-shrink: 0; + padding-right: 10px; + } + + &:hover { + background-color: $gray-lightest; + } +} diff --git a/frontend/app/components/Dashboard/Widgets/common/title.css b/frontend/app/components/Dashboard/Widgets/common/title.css new file mode 100644 index 000000000..a349ff5c8 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/title.css @@ -0,0 +1,14 @@ +.title { + display: flex; + align-items: center; + + & h4 { + margin: 0; + padding-right: 10px; + } + + & > span { + font-size: 14px; + color: $gray-medium; + } +} diff --git a/frontend/app/components/Dashboard/Widgets/common/widgetHOC.css b/frontend/app/components/Dashboard/Widgets/common/widgetHOC.css new file mode 100644 index 000000000..10d3a63da --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/widgetHOC.css @@ -0,0 +1,44 @@ +@import 'mixins.css'; + +.circle { + width: 8px; + height: 8px; + border-radius: 50%; + margin-right: 5px; +} + +.panel { + border-radius: 5px; + border: solid thin #EEEEEE; + background: $white; + padding: 15px; + + &:hover { + & .closeButton { + opacity: 1; + transition: all 0.2s; + } + } + + &.fullwidth { + width: 100%; + } + + &.minHeight { + height: 300px; + } + + &.fitContent { + height: fit-content; + } + + & .closeButton { + opacity: 0; + } + + & .trendChart { + margin-left: -15px; + margin-right: -15px; + margin-bottom: -15px; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/widgetHOC.js b/frontend/app/components/Dashboard/Widgets/common/widgetHOC.js new file mode 100644 index 000000000..34df08a2a --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/common/widgetHOC.js @@ -0,0 +1,107 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { CloseButton } from 'UI'; +import { fetchWidget } from 'Duck/dashboard'; +import { updateAppearance } from 'Duck/user'; +import { WIDGET_MAP } from 'Types/dashboard'; +import Title from './Title'; +import stl from './widgetHOC.css'; + +export default ( + widgetKey, + panelProps = {}, + wrapped = true, + allowedFilters = [], +) => BaseComponent => + @connect((state, props) => { + const compare = props && props.compare; + const key = compare ? '_' + widgetKey : widgetKey; + + return { + loading: state.getIn([ 'dashboard', 'fetchWidget', key, 'loading' ]), + data: state.getIn([ 'dashboard', key ]), + comparing: state.getIn([ 'dashboard', 'comparing' ]), + filtersSize: state.getIn([ 'dashboard', 'filters' ]).size, + filters: state.getIn([ 'dashboard', compare ? 'filtersCompare' : 'filters' ]), + period: state.getIn([ 'dashboard', compare ? 'periodCompare' : 'period' ]), //TODO: filters + platform: state.getIn([ 'dashboard', 'platform' ]), + appearance: state.getIn([ 'user', 'account', 'appearance' ]), + + dataCompare: state.getIn([ 'dashboard', '_' + widgetKey ]), // only for overview + loadingCompare: state.getIn([ 'dashboard', 'fetchWidget', '_' + widgetKey, 'loading' ]), + filtersCompare: state.getIn([ 'dashboard', 'filtersCompare' ]), + periodCompare: state.getIn([ 'dashboard', 'periodCompare' ]), //TODO: filters + } + }, { + fetchWidget, + updateAppearance, + }) + class WidgetWrapper extends React.PureComponent { + constructor(props) { + super(props); + const params = panelProps.customParams ? panelProps.customParams(this.props.period.rangeName) : {}; + if(props.testId) { + params.testId = parseInt(props.testId); + } + params.compare = this.props.compare; + const filters = allowedFilters.length > 0 ? props.filters.filter(f => allowedFilters.includes(f.key)) : props.filters; + props.fetchWidget(widgetKey, props.period, props.platform, params, filters); + } + + componentDidUpdate(prevProps) { + if (prevProps.period !== this.props.period || + prevProps.platform !== this.props.platform || + prevProps.filters.size !== this.props.filters.size) { + const params = panelProps.customParams ? panelProps.customParams(this.props.period.rangeName) : {}; + if(this.props.testId) { + params.testId = parseInt(this.props.testId); + } + params.compare = this.props.compare; + const filters = allowedFilters.length > 0 ? this.props.filters.filter(f => allowedFilters.includes(f.key)) : this.props.filters; + this.props.fetchWidget(widgetKey, this.props.period, this.props.platform, params, filters); + } + + // handling overview widgets + if ((!prevProps.comparing || prevProps.periodCompare !== this.props.periodCompare || prevProps.filtersCompare.size !== this.props.filtersCompare.size) && + this.props.comparing && this.props.isOverview + ) { + const params = panelProps.customParams ? panelProps.customParams(this.props.period.rangeName) : {}; + params.compare = true; + const filtersCompare = allowedFilters.length > 0 ? this.props.filtersCompare.filter(f => allowedFilters.includes(f.key)) : this.props.filtersCompare; + this.props.fetchWidget(widgetKey, this.props.periodCompare, this.props.platform, params, filtersCompare); + } + } + + handleRemove = () => { + const { appearance } = this.props; + this.props.updateAppearance(appearance.setIn([ 'dashboard', widgetKey ], false)); + } + + render() { + const { comparing, compare } = this.props; + + return ( + wrapped ? +
    +
    +
    + {comparing &&
    } + + { <CloseButton className={ cn(stl.closeButton, 'ml-auto') } onClick={ this.handleRemove } size="17" /> } + </div> + <div className="flex-1 flex flex-col"> + <BaseComponent { ...this.props } /> + </div> + </div> + </div> + : + <BaseComponent { ...this.props } /> + ) + } + } \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/index.js b/frontend/app/components/Dashboard/Widgets/index.js new file mode 100644 index 000000000..559dd09b9 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/index.js @@ -0,0 +1,37 @@ +export { default as ApplicationActivity } from './ApplicationActivity'; +export { default as ProcessedSessions } from './ProcessedSessions'; +export { default as Errors } from './Errors'; +export { default as UserActivity } from './UserActivity'; +export { default as Performance } from './Performance'; +export { default as SlowestImages } from './SlowestImages'; +export { default as PageMetrics } from './PageMetrics'; +export { default as LastFrustrations } from './LastFrustrations'; +export { default as MissingResources } from './MissingResources'; +export { default as ResourceLoadingTime } from './ResourceLoadingTime'; +export { default as SlowestResources } from './SlowestResources'; +export { default as DomBuildingTime } from './DomBuildingTime'; +export { default as BusiestTimeOfTheDay } from './BusiestTimeOfTheDay'; +export { default as ResponseTime } from './ResponseTime'; +export { default as ResponseTimeDistribution } from './ResponseTimeDistribution'; +export { default as TimeToRender } from './TimeToRender'; +export { default as SessionsImpactedBySlowRequests } from './SessionsImpactedBySlowRequests'; +export { default as MemoryConsumption } from './MemoryConsumption'; +export { default as FPS } from './FPS'; +export { default as CpuLoad } from './CpuLoad'; +export { default as Crashes } from './Crashes'; +export { default as TopDomains } from './TopDomains'; +export { default as SlowestDomains } from './SlowestDomains'; +export { default as ErrorsPerDomain } from './ErrorsPerDomain'; +export { default as CallWithErrors } from './CallWithErrors'; +export { default as ErrorsByType } from './ErrorsByType'; +export { default as ErrorsByOrigin } from './ErrorsByOrigin'; +export { default as ResourceLoadedVsResponseEnd } from './ResourceLoadedVsResponseEnd'; +export { default as ResourceLoadedVsVisuallyComplete } from './ResourceLoadedVsVisuallyComplete'; +export { default as SessionsAffectedByJSErrors } from './SessionsAffectedByJSErrors'; +export { default as BreakdownOfLoadedResources } from './BreakdownOfLoadedResources'; +export { default as TopMetrics } from './TopMetrics'; +export { default as SpeedIndexLocation } from './SpeedIndexLocation'; +export { default as SessionsPerBrowser } from './SessionsPerBrowser'; +export { default as CallsErrors5xx } from './CallsErrors5xx'; +export { default as CallsErrors4xx } from './CallsErrors4xx'; +export { default as TrendChart } from './TrendChart'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/addWidgets.css b/frontend/app/components/Dashboard/addWidgets.css new file mode 100644 index 000000000..452ee92b7 --- /dev/null +++ b/frontend/app/components/Dashboard/addWidgets.css @@ -0,0 +1,48 @@ +.widgetCard { + min-height: 110px; + padding: 15px; + width: 100%; + border: 1px solid $gray-light; + border-bottom: none; + + &:last-child { + border-bottom: 1px solid $gray-light; + } + & h4 { + margin-bottom: 10px; + } + & p { + color: $gray-medium; + font-weight: 300; + font-size: 12px; + } +} + +.thumb { + border: solid thin $gray-light; + margin-right: 10px; + width: 170px; +} + +.menuWrapper { + max-height: 300px; + overflow-y: auto; + &::-webkit-scrollbar { + width: 2px; + } +} + +.menuItem { + transition: all .2s; + border-bottom: solid thin $gray-light; + padding: 8px 10px; + overflow: hidden; + text-overflow: ellipsis; + &:last-child { + border-bottom: none; + } + &:hover { + transition: all .4s; + background-color: $gray-lightest; + } +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/dashboard.css b/frontend/app/components/Dashboard/dashboard.css new file mode 100644 index 000000000..8c6eff3fc --- /dev/null +++ b/frontend/app/components/Dashboard/dashboard.css @@ -0,0 +1,18 @@ +.header { + padding: 0px 0 15px; +} + +.dateInput { + width: 180px !important; + border-radius: 3px; + border: solid thin $gray-light; + text-align: center; + margin-left: 10px; + background-color: white; + height: 38px; + color: $gray-darkest; + + &[disabled] { + opacity: 0.5; + } +} \ No newline at end of file diff --git a/frontend/app/components/Errors/Error/DateAgo.js b/frontend/app/components/Errors/Error/DateAgo.js new file mode 100644 index 000000000..0d4379a74 --- /dev/null +++ b/frontend/app/components/Errors/Error/DateAgo.js @@ -0,0 +1,15 @@ +import { resentOrDate } from 'App/date'; + +function DateAgo({ className, title, timestamp }) { + return ( + <div className={className}> + <h4 className="font-medium">{ title }</h4> + <span className="text-sm"> + { `${ resentOrDate(timestamp) }` } + </span> + </div> + ); +} + +DateAgo.displayName = "DateAgo"; +export default DateAgo; \ No newline at end of file diff --git a/frontend/app/components/Errors/Error/DistributionBar.js b/frontend/app/components/Errors/Error/DistributionBar.js new file mode 100644 index 000000000..8e3c168b2 --- /dev/null +++ b/frontend/app/components/Errors/Error/DistributionBar.js @@ -0,0 +1,54 @@ +import cn from 'classnames'; +import { Popup } from 'UI'; +import { Styles } from '../../Dashboard/Widgets/common'; +import cls from './distributionBar.css'; +import { colorScale } from 'App/utils'; + +function DistributionBar({ className, title, partitions }) { + if (partitions.length === 0) { + return null; + } + + const values = Array(partitions.length).fill().map((element, index) => index + 0); + const colors = colorScale(values, Styles.colors); + + return ( + <div className={ className } > + <div className="flex justify-between text-sm mb-1"> + <span className="capitalize">{ title }</span> + <span> + <span className="font-thin capitalize">{ partitions[0].label }</span> + <span className="ml-2">{ `${ Math.round(partitions[0].prc) }% ` }</span> + </span> + </div> + <div className={ cn("border-radius-3 overflow-hidden flex", cls.bar) }> + { partitions.map((p, index) => + <Popup + key={p.label} + inverted + size="mini" + trigger={ + <div + className="h-full bg-tealx" + style={{ + marginLeft: '1px', + width: `${ p.prc }%`, + backgroundColor: colors(index) + }} + /> + } + content={ + <div className="text-center"> + <span className="capitalize">{ p.label }</span><br/> + {`${ Math.round(p.prc) }%`} + </div> + } + /> + )} + </div> + </div> + ); +} + +DistributionBar.displayName = "DistributionBar"; +export default DistributionBar; \ No newline at end of file diff --git a/frontend/app/components/Errors/Error/ErrorInfo.js b/frontend/app/components/Errors/Error/ErrorInfo.js new file mode 100644 index 000000000..c9681f25d --- /dev/null +++ b/frontend/app/components/Errors/Error/ErrorInfo.js @@ -0,0 +1,122 @@ +import { connect } from 'react-redux'; +import withSiteIdRouter from 'HOCs/withSiteIdRouter'; +import { errors as errorsRoute, error as errorRoute } from 'App/routes'; +import { NoContent , Loader, IconButton, Icon, Popup, BackLink, } from 'UI'; +import { fetch, fetchTrace } from 'Duck/errors'; +import MainSection from './MainSection'; +import SideSection from './SideSection'; + +@connect(state =>({ + errorIdInStore: state.getIn(["errors", "instance"]).errorId, + loading: state.getIn([ "errors", "fetch", "loading" ]) || state.getIn([ "errors", "fetchTrace", "loading" ]), + errorOnFetch: state.getIn(["errors", "fetch", "errors"]) || state.getIn([ "errors", "fetchTrace", "errors" ]), +}), { + fetch, + fetchTrace, +}) +@withSiteIdRouter +export default class ErrorInfo extends React.PureComponent { + ensureInstance() { + const { errorId, loading, errorOnFetch } = this.props; + if (!loading && !errorOnFetch && + this.props.errorIdInStore !== errorId && + errorId != null) { + this.props.fetch(errorId); + this.props.fetchTrace(errorId) + } + } + componentDidMount() { + this.ensureInstance(); + } + componentDidUpdate() { + this.ensureInstance(); + } + next = () => { + const { list, errorId } = this.props; + const curIndex = list.findIndex(e => e.errorId === errorId); + const next = list.get(curIndex + 1); + if (next != null) { + this.props.history.push(errorRoute(next.errorId)) + } + } + prev = () => { + const { list, errorId } = this.props; + const curIndex = list.findIndex(e => e.errorId === errorId); + const prev = list.get(curIndex - 1); + if (prev != null) { + this.props.history.push(errorRoute(prev.errorId)) + } + + } + render() { + const { + loading, + errorIdInStore, + list, + errorId, + } = this.props; + + let nextDisabled = true, + prevDisabled = true; + if (list.size > 0) { + nextDisabled = loading || list.last().errorId === errorId; + prevDisabled = loading || list.first().errorId === errorId; + } + + return ( + <NoContent + title="No Error Found!" + subtext="Please try to find existing one." + icon="exclamation-circle" + show={ !loading && errorIdInStore == null } + > + <div className="w-9/12 mb-4 flex justify-between"> + <BackLink to={ errorsRoute() } label="Back" /> + <div className="flex items-center"> + <Popup + pinned + position="bottom center" + inverted + trigger={ + <IconButton + // className="mr-3" + outline + compact + size="small" + icon="prev1" + disabled={ prevDisabled } + onClick={this.prev} + /> + } + content="Prev Error" + /> + <div className="mr-3" /> + + <Popup + pinned + inverted + position="bottom center" + trigger={ + <IconButton + outline + compact + size="small" + icon="next1" + disabled={ nextDisabled } + onClick={this.next} + /> + } + content="Next Error" + /> + </div> + </div> + <div className="flex" > + <Loader loading={ loading } className="w-9/12"> + <MainSection className="w-9/12" /> + <SideSection className="w-3/12" /> + </Loader> + </div> + </NoContent> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Errors/Error/IconCard.js b/frontend/app/components/Errors/Error/IconCard.js new file mode 100644 index 000000000..fe7ad2825 --- /dev/null +++ b/frontend/app/components/Errors/Error/IconCard.js @@ -0,0 +1,19 @@ +import cn from 'classnames'; +import { Icon } from 'UI'; + +function IconCard({ className, title, text, icon, avatarIcon }) { + return ( + <div className={ cn(className, "flex items-center") }> + { avatarIcon && avatarIcon} + { !avatarIcon && <Icon name={ icon } size={27} /> } + <div className="ml-2 leading-none"> + <h6> { title } </h6> + <span className="font-thin text-sm"> { text }</span> + </div> + </div> + ); +} + +IconCard.displayName = "IconCard"; + +export default IconCard; \ No newline at end of file diff --git a/frontend/app/components/Errors/Error/MainSection.js b/frontend/app/components/Errors/Error/MainSection.js new file mode 100644 index 000000000..5930bc8ce --- /dev/null +++ b/frontend/app/components/Errors/Error/MainSection.js @@ -0,0 +1,193 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import withSiteIdRouter from 'HOCs/withSiteIdRouter'; +import { ErrorDetails, IconButton, Icon, Loader } from 'UI'; +import { sessions as sessionsRoute } from 'App/routes'; +import { TYPES as EV_FILER_TYPES } from 'Types/filter/event'; +import { UNRESOLVED, RESOLVED, IGNORED } from "Types/errorInfo"; +import { addEvent } from 'Duck/filters'; +import { resolve,unresolve,ignore, toggleFavorite } from "Duck/errors"; +import { resentOrDate } from 'App/date'; +import Divider from 'Components/Errors/ui/Divider'; +import ErrorName from 'Components/Errors/ui/ErrorName'; +import Label from 'Components/Errors/ui/Label'; +import SharePopup from 'Shared/SharePopup' + +import SessionBar from './SessionBar'; + +@withSiteIdRouter +@connect(state => ({ + error: state.getIn([ "errors", "instance" ]), + trace: state.getIn([ "errors", "instanceTrace" ]), + sourcemapUploaded: state.getIn([ "errors", "sourcemapUploaded" ]), + resolveToggleLoading: state.getIn(["errors", "resolve", "loading"]) || + state.getIn(["errors", "unresolve", "loading"]), + ignoreLoading: state.getIn([ "errors", "ignore", "loading" ]), + toggleFavoriteLoading: state.getIn([ "errors", "toggleFavorite", "loading" ]), + traceLoading: state.getIn([ "errors", "fetchTrace", "loading"]), +}),{ + resolve, + unresolve, + ignore, + toggleFavorite, + addEvent, +}) +export default class MainSection extends React.PureComponent { + resolve = () => { + const { error } = this.props; + this.props.resolve(error.errorId) + } + + unresolve = () => { + const { error } = this.props; + this.props.unresolve(error.errorId) + } + + ignore = () => { + const { error } = this.props; + this.props.ignore(error.errorId) + } + bookmark = () => { + const { error } = this.props; + this.props.toggleFavorite(error.errorId); + } + + findSessions = () => { + this.props.addEvent({ + type: EV_FILER_TYPES.CONSOLE, + value: this.props.error.message, + }, true); + this.props.history.push(sessionsRoute()); + } + + render() { + const { + error, + trace, + sourcemapUploaded, + ignoreLoading, + resolveToggleLoading, + toggleFavoriteLoading, + className, + traceLoading, + } = this.props; + + return ( + <div className={cn(className, "bg-white border-radius-3 thin-gray-border mb-6")} > + <div className="m-4"> + <ErrorName + className="text-lg leading-relaxed" + name={ error.name } + message={ error.stack0InfoString } + lineThrough={ error.status === RESOLVED } + /> + <div className="flex justify-between items-center"> + <div className="flex items-center color-gray-dark" style={{ wordBreak: 'break-all'}}> + { error.message } + </div> + <div className="text-center"> + <div className="flex"> + <Label + topValue={ error.sessions } + topValueSize="text-lg" + bottomValue="Sessions" + /> + <Label + topValue={ error.users } + topValueSize="text-lg" + bottomValue="Users" + /> + </div> + <div className="text-xs color-gray-medium">Over the past 30 days</div> + </div> + </div> + + </div> + + <Divider /> + <div className="flex m-4"> + { error.status === UNRESOLVED + ? <IconButton + outline + className="mr-3" + label="Resolve" + size="small" + icon="check" + loading={ resolveToggleLoading } + onClick={ this.resolve } + /> + : <IconButton + outline + className="mr-3" + label="Unresolve" + size="small" + icon="exclamation-circle" + loading={ resolveToggleLoading } + onClick={ this.unresolve } + /> + } + { error.status !== IGNORED && + <IconButton + outline + className="mr-3" + label="Ignore" + size="small" + icon="ban" + loading={ ignoreLoading } + onClick={ this.ignore } + /> + } + <IconButton + primaryText + label="Bookmark" + size="small" + compact + icon={ error.favorite ? "star-solid" : "star" } + loading={ toggleFavoriteLoading } + onClick={ this.bookmark } + /> + <SharePopup + entity="errors" + id={ error.errorId } + trigger={ + <IconButton + primaryText + label="Share" + size="small" + icon="share-alt" + /> + } + /> + </div> + <Divider /> + <div className="m-4"> + <h3 className="text-xl inline-block mr-2">Last session with this error</h3> + <span className="font-thin text-sm">{ resentOrDate(error.lastOccurrence) }</span> + <SessionBar + className="my-4" + session={ error.lastHydratedSession } + /> + <button + className="color-teal cursor-pointer flex items-center" + onClick={ this.findSessions } + > + Find all sessions with this error + <Icon className="ml-1" name="next1" color="teal" /> + </button> + </div> + <Divider /> + <div className="m-4"> + <Loader loading={ traceLoading }> + <ErrorDetails + name={error.name} + message={error.message} + errorStack={trace} + sourcemapUploaded={sourcemapUploaded} + /> + </Loader> + </div> + + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Errors/Error/SessionBar.js b/frontend/app/components/Errors/Error/SessionBar.js new file mode 100644 index 000000000..716ca5a2d --- /dev/null +++ b/frontend/app/components/Errors/Error/SessionBar.js @@ -0,0 +1,62 @@ +import cn from 'classnames'; +import { capitalize } from 'App/utils'; +import { session as sessionRoute } from 'App/routes'; +import { Icon, Avatar, Link } from 'UI'; +import { deviceTypeIcon, osIcon, browserIcon } from 'App/iconNames'; +import IconCard from './IconCard'; +import stl from './sessionBar.css'; + +function SessionBar({ + className, + session: { + sessionId, + viewed=false, + userBrowser, + userBrowserVersion, + userOs, + userOsVersion, + userDeviceType, + userDevice, + userDisplayName, + userNumericHash, + } +}) { + return ( + <Link + to={ sessionRoute(sessionId) } + className={ cn( + className, + "block border-radius-3 thin-blue-border flex justify-between items-center p-4", + stl.wrapper + )} + > + <IconCard + avatarIcon={ <Avatar seed={ userNumericHash } /> } + title={ userDisplayName } + /> + <IconCard + icon={ browserIcon(userBrowser) } + title={ userBrowser } + text={ userBrowserVersion } + /> + <IconCard + icon={ osIcon(userOs) } + title={ userOs } + text={ userOsVersion } + /> + <IconCard + icon={ deviceTypeIcon(userDeviceType) } + title={ capitalize(userDeviceType) } + text={ userDevice } + /> + + <Icon + name={ viewed ? 'play-fill' : 'play-circle-light' } + size="30" + color="teal" + /> + </Link> + ); +} +SessionBar.displayName = "SessionBar"; +export default SessionBar; \ No newline at end of file diff --git a/frontend/app/components/Errors/Error/SideSection.js b/frontend/app/components/Errors/Error/SideSection.js new file mode 100644 index 000000000..9e9faac5f --- /dev/null +++ b/frontend/app/components/Errors/Error/SideSection.js @@ -0,0 +1,124 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import withRequest from 'HOCs/withRequest'; +import { Loader } from 'UI'; +import { countries } from 'App/constants'; +import Trend from './Trend'; +import DateAgo from './DateAgo'; +import DistributionBar from './DistributionBar'; + +const MAX_PERCENTAGE = 3; +const MIN_COUNT = 4; +const MAX_COUNT = 10; +function hidePredicate(percentage, index) { + if (index < MIN_COUNT) return false; + if (index < MAX_COUNT && percentage < MAX_PERCENTAGE) return false; + return true; +} +function partitionsWrapper(partitions = [], mapCountry = false) { + const counts = partitions.map(({ count }) => count); + const sum = counts.reduce((a,b)=>parseInt(a)+parseInt(b),0); + if (sum === 0) { + return []; + } + const otherPrcs = counts + .map(c => c/sum * 100) + .filter(hidePredicate); + const otherPrcsSum = otherPrcs.reduce((a,b)=>a+b,0); + const showLength = partitions.length - otherPrcs.length; + const show = partitions + .sort((a, b) => b.count - a.count) + .slice(0, showLength) + .map(p => ({ + label: mapCountry + ? (countries[p.name] || "Unknown") + : p.name, + prc: p.count/sum * 100, + })) + + if (otherPrcsSum > 0) { + show.push({ + label: "Other", + prc: otherPrcsSum, + other: true, + }) + } + return show; +} +function tagsWrapper(tags = []) { + return tags.map(({ name, partitions }) => ({ + name, + partitions: partitionsWrapper(partitions, name === "country") + })) +} + +function dataWrapper(data = {}) { + return { + chart24: data.chart24 || [], + chart30: data.chart30 || [], + tags: tagsWrapper(data.tags), + }; +} + +@connect(state => ({ + error: state.getIn([ "errors", "instance" ]) +})) +@withRequest({ + initialData: props => dataWrapper(props.error), + endpoint: props => `/errors/${ props.error.errorId }/stats`, + dataWrapper, +}) +export default class SideSection extends React.PureComponent { + onDateChange = ({ startDate, endDate }) => { + this.props.request({ startDate, endDate }); + } + + render() { + const { + className, + error, + data, + loading, + } = this.props; + + return ( + <div className={ cn(className, "pl-5") }> + <h3 className="text-xl mb-2">Overview</h3> + <Trend + chart={ data.chart24 } + title="Last 24 hours" + /> + <div className="mb-6" /> + <Trend + chart={ data.chart30 } + title="Last 30 days" + timeFormat={'l'} + /> + <div className="mb-6" /> + <DateAgo + className="my-4" + title="First Seen" + timestamp={ error.firstOccurrence } + /> + <DateAgo + className="my-4" + title="Last Seen" + timestamp={ error.lastOccurrence } + /> + { data.tags.length > 0 && <h4 className="text-xl mt-6 mb-3">Tags</h4> } + <Loader loading={loading}> + { data.tags.map(({ name, partitions }) => + <DistributionBar + key={ name } + title={name} + partitions={partitions} + className="mb-6" + /> + )} + </Loader> + </div> + ); + } +} + + diff --git a/frontend/app/components/Errors/Error/Trend.js b/frontend/app/components/Errors/Error/Trend.js new file mode 100644 index 000000000..e6dcc1445 --- /dev/null +++ b/frontend/app/components/Errors/Error/Trend.js @@ -0,0 +1,82 @@ +import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Tooltip, BarChart, Bar } from 'recharts'; +import domain from "Components/Dashboard/Widgets/common/domain"; +import moment from 'moment'; + +const CustomTooltip = ({ active, payload, label, timeFormat = 'hh:mm a' }) => { + if (active) { + const p = payload[0].payload; + return ( + <div className="rounded border bg-white p-2"> + <p className="label text-sm color-gray-medium">{`${moment(p.timestamp).format(timeFormat)}`}</p> + <p className="text-sm">Sessions: {p.count}</p> + </div> + ); + } + + return null; +}; + +function Trend({ title = '', chart, onDateChange, timeFormat = 'hh:mm a' }) { + if (!Array.isArray(chart)) return null + + const getDateFormat = val => { + console.log(val); + const d = new Date(val); + return (d.getMonth()+ 1) + '/' + d.getDate() + } + + return ( + <> + <div className="flex justify-between"> + <h4 className="font-medium">{title}</h4> + {/* <DateRangeDropdown + button + onChange={ onDateChange } + direction="left" + customHidden + /> */} + </div> + <ResponsiveContainer height={ 100 } width="100%"> + <BarChart data={ chart } margin={0} > + <defs> + <linearGradient id="colorCount" x1="0" y1="0" x2="0" y2="1"> + <stop offset="5%" stopColor="#A8E0DA" stopOpacity={ 0.9 } /> + <stop offset="95%" stopColor="#A8E0DA" stopOpacity={ 0.2 } /> + </linearGradient> + </defs> + <Tooltip cursor = {{ fill: '#ddd' }} content={<CustomTooltip timeFormat={timeFormat} />} /> + <XAxis + interval={ 0 } + dataKey="time" + // tick={ { fill: '#999999', fontSize: 9 } } + // tickLine = {{ stroke: '#CCCCCC' }} + strokeWidth = { 0 } + hide + /> + <YAxis + hide + interval={ 0 } + domain={ domain } + /> + <CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" /> + <Bar + name="Sessions" + type="monotone" + dataKey="count" + // stroke="#3EAAAF" + minPointSize={1} + fillOpacity={ 1 } + // strokeWidth={ 1 } + // strokeOpacity={ 0.8 } + fill="#3EAAAF" + // fill="url(#colorCount)" + /> + + </BarChart> + </ResponsiveContainer> + </> + ); +} + +Trend.displayName = "Trend"; +export default Trend; diff --git a/frontend/app/components/Errors/Error/distributionBar.css b/frontend/app/components/Errors/Error/distributionBar.css new file mode 100644 index 000000000..543606923 --- /dev/null +++ b/frontend/app/components/Errors/Error/distributionBar.css @@ -0,0 +1,3 @@ +.bar { + height: 10px; +} diff --git a/frontend/app/components/Errors/Error/sessionBar.css b/frontend/app/components/Errors/Error/sessionBar.css new file mode 100644 index 000000000..49c58fa6c --- /dev/null +++ b/frontend/app/components/Errors/Error/sessionBar.css @@ -0,0 +1,10 @@ +.wrapper { + color: $gray-medium; + &:hover { + background-color: $active-blue !important; + color: $gray-medium !important; + } + & > div { + background-color: transparent !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Errors/Errors.js b/frontend/app/components/Errors/Errors.js new file mode 100644 index 000000000..b4c5fce92 --- /dev/null +++ b/frontend/app/components/Errors/Errors.js @@ -0,0 +1,174 @@ +import { connect } from 'react-redux'; +import withSiteIdRouter from 'HOCs/withSiteIdRouter'; +import { UNRESOLVED, RESOLVED, IGNORED } from "Types/errorInfo"; +import { getRE } from 'App/utils'; +import { fetchBookmarks } from "Duck/errors"; +import { applyFilter } from 'Duck/filters'; +import { fetchList as fetchSlackList } from 'Duck/integrations/slack'; +import { errors as errorsRoute, isRoute } from "App/routes"; +import EventFilter from 'Components/BugFinder/EventFilter'; +import DateRange from 'Components/BugFinder/DateRange'; + +import { SavedSearchList } from 'UI'; + +import List from './List/List'; +import ErrorInfo from './Error/ErrorInfo'; +import Header from './Header'; +import SideMenuSection from './SideMenu/SideMenuSection'; +import SideMenuHeader from './SideMenu/SideMenuHeader'; +import SideMenuDividedItem from './SideMenu/SideMenuDividedItem'; + +const ERRORS_ROUTE = errorsRoute(); + +function getStatusLabel(status) { + switch(status) { + case UNRESOLVED: + return "Unresolved"; + case RESOLVED: + return "Resolved"; + case IGNORED: + return "Ignored"; + default: + return ""; + } +} + +@withSiteIdRouter +@connect(state => ({ + list: state.getIn([ "errors", "list" ]), +}), { + fetchBookmarks, + applyFilter, + fetchSlackList, +}) +export default class Errors extends React.PureComponent { + state = { + status: UNRESOLVED, + bookmarksActive: false, + currentList: this.props.list.filter(e => e.status === UNRESOLVED), + filter: '', + } + + componentDidMount() { + this.props.fetchSlackList(); // Delete after implementing cache + } + + onFilterChange = ({ target: { value } }) => this.setState({ filter: value }) + + componentDidUpdate(prevProps, prevState) { + const { bookmarksActive, status, filter } = this.state; + const { list } = this.props; + if (prevProps.list !== list + || prevState.status !== status + || prevState.bookmarksActive !== bookmarksActive + || prevState.filter !== filter) { + const unfiltered = bookmarksActive + ? list + : list.filter(e => e.status === status); + const filterRE = getRE(filter); + this.setState({ + currentList: unfiltered + .filter(e => filterRE.test(e.name) || filterRE.test(e.message)), + }) + } + } + + ensureErrorsPage() { + const { history } = this.props; + if (!isRoute(ERRORS_ROUTE, history.location.pathname)) { + history.push(ERRORS_ROUTE); + } + } + + onStatusItemClick = ({ key }) => { + if (this.state.bookmarksActive) { + this.props.applyFilter(); + } + this.setState({ + status: key, + bookmarksActive: false, + }); + this.ensureErrorsPage(); + } + + onBookmarksClick = () => { + this.setState({ + bookmarksActive: true, + }); + this.props.fetchBookmarks(); + this.ensureErrorsPage(); + } + + + render() { + const { + count, + match: { + params: { errorId } + }, + } = this.props; + const { status, bookmarksActive, currentList } = this.state; + + return ( + <div className="page-margin container-90" > + <div className="side-menu"> + <SideMenuSection + title="Errors" + onItemClick={this.onStatusItemClick} + items={[ + { + key: UNRESOLVED, + icon: "exclamation-circle", + label: getStatusLabel(UNRESOLVED), + active: status === UNRESOLVED, + }, + { + key: RESOLVED, + icon: "check", + label: getStatusLabel(RESOLVED), + active: status === RESOLVED, + }, + { + key: IGNORED, + icon: "ban", + label: getStatusLabel(IGNORED), + active: status === IGNORED, + } + ]} + /> + <SideMenuDividedItem + className="mt-3 mb-4" + iconName="star" + title="Bookmarks" + active={ bookmarksActive } + onClick={ this.onBookmarksClick } + /> + </div> + + <div className="side-menu-margined"> + { errorId == null ? + <> + <div className="mb-5 flex"> + <Header + text={ bookmarksActive ? "Bookmarks" : getStatusLabel(status) } + count={ currentList.size } + /> + <div className="ml-3 flex items-center"> + <span className="mr-2 color-gray-medium">Seen in</span> + <DateRange /> + </div> + </div> + <List + status={ status } + list={ currentList } + onFilterChange={this.onFilterChange} + /> + </> + : + <ErrorInfo errorId={ errorId } list={ currentList } /> + } + </div> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Errors/Header.js b/frontend/app/components/Errors/Header.js new file mode 100644 index 000000000..a8844b98a --- /dev/null +++ b/frontend/app/components/Errors/Header.js @@ -0,0 +1,13 @@ +function Header({ text, count }) { + return ( + <h3 className="text-2xl capitalize"> + <span>{ text }</span> + { count != null && <span className="ml-2 font-normal color-gray-medium">{ count }</span> } + </h3> + ); +} + +Header.displayName = "Header"; + +export default Header; + \ No newline at end of file diff --git a/frontend/app/components/Errors/List/List.js b/frontend/app/components/Errors/List/List.js new file mode 100644 index 000000000..70b0953fb --- /dev/null +++ b/frontend/app/components/Errors/List/List.js @@ -0,0 +1,232 @@ +import cn from 'classnames'; +import { connect } from 'react-redux'; +import { Set, List as ImmutableList } from "immutable"; +import { NoContent, Loader, Checkbox, LoadMoreButton, IconButton, Input, DropdownPlain } from 'UI'; +import { merge, resolve,unresolve,ignore } from "Duck/errors"; +import { applyFilter } from 'Duck/filters'; +import { IGNORED, RESOLVED, UNRESOLVED } from 'Types/errorInfo'; +import SortDropdown from 'Components/BugFinder/Filters/SortDropdown'; +import Divider from 'Components/Errors/ui/Divider'; +import ListItem from './ListItem/ListItem'; + +const PER_PAGE = 5; +const DEFAULT_SORT = 'lastOccurrence'; +const DEFAULT_ORDER = 'desc'; +const sortOptionsMap = { + 'lastOccurrence-desc': 'Last Occurrence', + 'firstOccurrence-desc': 'First Occurrence', + 'sessions-asc': 'Sessions Ascending', + 'sessions-desc': 'Sessions Descending', + 'users-asc': 'Users Ascending', + 'users-desc': 'Users Descending', +}; +const sortOptions = Object.entries(sortOptionsMap) + .map(([ value, text ]) => ({ value, text })); + + +@connect(state => ({ + loading: state.getIn([ "errors", "loading" ]), + resolveToggleLoading: state.getIn(["errors", "resolve", "loading"]) || + state.getIn(["errors", "unresolve", "loading"]), + ignoreLoading: state.getIn([ "errors", "ignore", "loading" ]), + mergeLoading: state.getIn([ "errors", "merge", "loading" ]), +}), { + merge, + resolve, + unresolve, + ignore, + applyFilter +}) +export default class List extends React.PureComponent { + state = { + checkedAll: false, + checkedIds: Set(), + showPages: 1, + sort: {} + } + + componentDidMount() { + this.props.applyFilter({ sort: DEFAULT_SORT, order: DEFAULT_ORDER, events: ImmutableList(), filters: ImmutableList() }); + } + + check = ({ errorId }) => { + const { checkedIds } = this.state; + const newCheckedIds = checkedIds.contains(errorId) + ? checkedIds.remove(errorId) + : checkedIds.add(errorId); + this.setState({ + checkedAll: newCheckedIds.size === this.props.list.size, + checkedIds: newCheckedIds + }); + } + + checkAll = () => { + if (this.state.checkedAll) { + this.setState({ + checkedAll: false, + checkedIds: Set(), + }); + } else { + this.setState({ + checkedAll: true, + checkedIds: this.props.list.map(({ errorId }) => errorId).toSet(), + }); + } + } + + resetChecked = () => { + this.setState({ + checkedAll: false, + checkedIds: Set(), + }); + } + + currentCheckedIds() { + return this.state.checkedIds + .intersect(this.props.list.map(({ errorId }) => errorId).toSet()); + } + + merge = () => { + this.props.merge(currentCheckedIds().toJS()).then(this.resetChecked); + } + + applyToAllChecked(f) { + return Promise.all(this.currentCheckedIds().map(f).toJS()).then(this.resetChecked); + } + + resolve = () => { + this.applyToAllChecked(this.props.resolve); + } + + unresolve = () => { + this.applyToAllChecked(this.props.unresolve); + } + + ignore = () => { + this.applyToAllChecked(this.props.ignore); + } + + addPage = () => this.setState({ showPages: this.state.showPages + 1 }) + + writeOption = (e, { name, value }) => { + const [ sort, order ] = value.split('-'); + const sign = order === 'desc' ? -1 : 1; + this.setState({ sort: { sort, order }}) + } + + render() { + const { + list, + status, + loading, + ignoreLoading, + resolveToggleLoading, + mergeLoading, + onFilterChange, + } = this.props; + const { + checkedAll, + checkedIds, + showPages, + sort + } = this.state; + const someLoading = loading || ignoreLoading || resolveToggleLoading || mergeLoading; + const currentCheckedIds = this.currentCheckedIds(); + const displayedCount = Math.min(showPages * PER_PAGE, list.size); + let _list = sort.sort ? list.sortBy(i => i[sort.sort]) : list; + _list = sort.order === 'desc' ? _list.reverse() : _list; + + return ( + <div className="bg-white p-5 border-radius-3 thin-gray-border"> + <div className="flex items-center justify-between mb-4"> + <div className="flex items-center" style={{ height: "36px" }}> + <Checkbox + className="mr-3" + checked={ checkedAll } + onChange={ this.checkAll } + /> + { status === UNRESOLVED + ? <IconButton + outline + className="mr-3" + label="Resolve" + icon="check" + size="small" + loading={ resolveToggleLoading } + onClick={ this.resolve } + disabled={ someLoading || currentCheckedIds.size === 0} + /> + : <IconButton + outline + className="mr-3" + label="Unresolve" + icon="exclamation-circle" + size="small" + loading={ resolveToggleLoading } + onClick={ this.unresolve } + disabled={ someLoading || currentCheckedIds.size === 0} + /> + } + { status !== IGNORED && + <IconButton + outline + className="mr-3" + label="Ignore" + icon="ban" + size="small" + loading={ ignoreLoading } + onClick={ this.ignore } + disabled={ someLoading || currentCheckedIds.size === 0} + /> + } + </div> + <div className="flex items-center ml-6"> + <span className="mr-2 color-gray-medium">Sort By</span> + <DropdownPlain + name="type" + options={ sortOptions } + onChange={ this.writeOption } + /> + <Input + style={{ width: '350px'}} + className="input-small ml-3" + placeholder="Filter by Name or Message" + icon="search" + iconPosition="left" + name="filter" + onChange={ onFilterChange } + /> + </div> + </div> + <Divider /> + <NoContent + title="No Errors Found!" + subtext="Please try to change your search parameters." + icon="exclamation-circle" + show={ !loading && list.size === 0} + > + <Loader loading={ loading }> + { _list.take(displayedCount).map(e => + <> + <ListItem + disabled={someLoading} + key={e.errorId} + error={e} + checked={ checkedIds.contains(e.errorId) } + onCheck={ this.check } + /> + <Divider/> + </> + )} + <LoadMoreButton + className="mt-3" + displayedCount={displayedCount} + totalCount={list.size} + onClick={this.addPage} + /> + </Loader> + </NoContent> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Errors/List/ListItem/ListItem.js b/frontend/app/components/Errors/List/ListItem/ListItem.js new file mode 100644 index 000000000..994c15235 --- /dev/null +++ b/frontend/app/components/Errors/List/ListItem/ListItem.js @@ -0,0 +1,87 @@ +import { BarChart, Bar, YAxis, Tooltip, XAxis } from 'recharts'; +import cn from 'classnames'; +import moment from 'moment'; +import { diffFromNowString } from 'App/date'; +import { error as errorRoute } from 'App/routes'; +import { IGNORED, RESOLVED } from 'Types/errorInfo'; +import { diffFromNowShortString } from 'App/date'; +import { Checkbox, Link } from 'UI'; +import ErrorName from 'Components/Errors/ui/ErrorName'; +import Label from 'Components/Errors/ui/Label'; +import stl from './listItem.css'; +import { Styles } from '../../../Dashboard/Widgets/common'; + + +const CustomTooltip = ({ active, payload, label }) => { + if (active) { + const p = payload[0].payload; + return ( + <div className="rounded border bg-white p-2"> + <p className="label text-sm color-gray-medium">{`${moment(p.timestamp).format('l')}`}</p> + <p className="text-sm">Sessions: {p.count}</p> + </div> + ); + } + + return null; +}; + +function ListItem({ className, onCheck, checked, error, disabled }) { + + const getDateFormat = val => { + const d = new Date(val); + return (d.getMonth()+ 1) + '/' + d.getDate() + } + + return ( + <div className={ cn("flex justify-between cursor-pointer py-4", className) } id="error-item"> + <Checkbox + disabled={disabled} + checked={ checked } + onChange={ () => onCheck(error) } + /> + + <div className={ cn("ml-3 flex-1 leading-tight", stl.name) } > + <Link to={errorRoute(error.errorId)} > + <ErrorName + icon={error.status === IGNORED ? 'ban' : null } + lineThrough={error.status === RESOLVED} + name={ error.name } + message={ error.stack0InfoString } + bold={ !error.viewed } + /> + <div + className={ cn("truncate color-gray-medium", { "line-through" : error.status === RESOLVED}) } + > + { error.message } + </div> + </Link> + </div> + <BarChart width={ 150 } height={ 40 } data={ error.chart }> + <XAxis hide dataKey="timestamp" /> + <YAxis hide domain={[0, 'dataMax + 8']} /> + <Tooltip {...Styles.tooltip} label="Sessions" content={<CustomTooltip />} /> + <Bar name="Sessions" minPointSize={1} dataKey="count" fill="#A8E0DA" /> + </BarChart> + <Label + className={stl.sessions} + topValue={ error.sessions } + bottomValue="Sessions" + /> + <Label + className={stl.users} + topValue={ error.users } + bottomValue="Users" + /> + <Label + className={stl.occurrence} + topValue={ `${diffFromNowString(error.lastOccurrence)} ago` } + bottomValue="Last Seen" + /> + </div> + ); +} + + +ListItem.displayName = "ListItem"; +export default ListItem; \ No newline at end of file diff --git a/frontend/app/components/Errors/List/ListItem/listItem.css b/frontend/app/components/Errors/List/ListItem/listItem.css new file mode 100644 index 000000000..c9f7589b9 --- /dev/null +++ b/frontend/app/components/Errors/List/ListItem/listItem.css @@ -0,0 +1,16 @@ +.name { + min-width: 55%; +} + +.sessions { + width: 6%; +} + +.users { + width: 5%; +} + +.occurrence { + width: 15%; + min-width: 152px; +} diff --git a/frontend/app/components/Errors/SideMenu/SideMenuDividedItem.js b/frontend/app/components/Errors/SideMenu/SideMenuDividedItem.js new file mode 100644 index 000000000..7ae10668e --- /dev/null +++ b/frontend/app/components/Errors/SideMenu/SideMenuDividedItem.js @@ -0,0 +1,19 @@ +import { SideMenuitem } from "UI"; +import Divider from 'Components/Errors/ui/Divider'; +function SideMenuDividedItem({ className, noTopDivider = false, noBottomDivider = false, ...props }) { + return ( + <div className={className}> + { !noTopDivider && <Divider /> } + <SideMenuitem + className="my-3" + { ...props } + /> + { !noBottomDivider && <Divider /> } + </div> + ); +} + +SideMenuDividedItem.displayName = "SideMenuDividedItem"; + +export default SideMenuDividedItem; + diff --git a/frontend/app/components/Errors/SideMenu/SideMenuHeader.js b/frontend/app/components/Errors/SideMenu/SideMenuHeader.js new file mode 100644 index 000000000..7f237263a --- /dev/null +++ b/frontend/app/components/Errors/SideMenu/SideMenuHeader.js @@ -0,0 +1,13 @@ +import cn from 'classnames'; +import stl from './sideMenuHeader.css'; + +function SideMenuHeader({ text, className }) { + return ( + <div className={ cn(className, stl.label, "uppercase color-gray") }> + { text } + </div> + ) +} + +SideMenuHeader.displayName = "SideMenuHeader"; +export default SideMenuHeader; \ No newline at end of file diff --git a/frontend/app/components/Errors/SideMenu/SideMenuSection.js b/frontend/app/components/Errors/SideMenu/SideMenuSection.js new file mode 100644 index 000000000..18498daef --- /dev/null +++ b/frontend/app/components/Errors/SideMenu/SideMenuSection.js @@ -0,0 +1,23 @@ +import { SideMenuitem } from 'UI'; +import SideMenuHeader from './SideMenuHeader'; + +function SideMenuSection({ title, items, onItemClick }) { + return ( + <> + <SideMenuHeader className="mb-4" text={ title }/> + { items.map(item => + <SideMenuitem + key={ item.key } + active={ item.active } + title={ item.label } + iconName={ item.icon } + onClick={() => onItemClick(item)} + /> + )} + </> + ); +} + +SideMenuSection.displayName = "SideMenuSection"; + +export default SideMenuSection; \ No newline at end of file diff --git a/frontend/app/components/Errors/SideMenu/sideMenuHeader.css b/frontend/app/components/Errors/SideMenu/sideMenuHeader.css new file mode 100644 index 000000000..5dce4e250 --- /dev/null +++ b/frontend/app/components/Errors/SideMenu/sideMenuHeader.css @@ -0,0 +1,4 @@ +.label { + letter-spacing: 0.2em; + color: gray; +} \ No newline at end of file diff --git a/frontend/app/components/Errors/ui/Divider.js b/frontend/app/components/Errors/ui/Divider.js new file mode 100644 index 000000000..b77dd09e6 --- /dev/null +++ b/frontend/app/components/Errors/ui/Divider.js @@ -0,0 +1,10 @@ +import cn from 'classnames'; +import stl from './divider.css'; + +function Divider({ className, color="gray-light" }) { + return <div className={ cn(stl.divider, className, `bg-${color}`) }/> +} + +Divider.displayName = "Divider"; + +export default Divider; \ No newline at end of file diff --git a/frontend/app/components/Errors/ui/ErrorName.js b/frontend/app/components/Errors/ui/ErrorName.js new file mode 100644 index 000000000..700445cf8 --- /dev/null +++ b/frontend/app/components/Errors/ui/ErrorName.js @@ -0,0 +1,16 @@ +import { Icon } from 'UI'; +import cn from "classnames"; + +function ErrorText({ className, icon, name, message, bold, lineThrough = false }) { + return ( + <div className={ cn("mb-1 truncate", { "font-weight-bold": bold }) }> + { icon && <Icon name={icon} className="float-left mr-2" size="14" style={{ marginTop: '1px'}}/> } + <span className={cn("code-font color-red", className, { 'line-through' : lineThrough })}>{ name }</span> + <span className={cn('color-gray-darkest ml-2', { 'line-through' : lineThrough })}>{ message }</span> + </div> + ); +} + +ErrorText.displayName = "ErrorText"; + +export default ErrorText; \ No newline at end of file diff --git a/frontend/app/components/Errors/ui/Label.js b/frontend/app/components/Errors/ui/Label.js new file mode 100644 index 000000000..0c2347fbb --- /dev/null +++ b/frontend/app/components/Errors/ui/Label.js @@ -0,0 +1,14 @@ +import cn from "classnames"; + +function Label({ className, topValue, topValueSize = 'text-base', bottomValue, topMuted = false, bottomMuted = false }) { + return ( + <div className={ cn(className, "flex flex-col items-center px-4") } > + <div className={ cn(topValueSize, { "color-gray-medium": topMuted }) } >{ topValue }</div> + <div className={ cn("font-light text-sm", { "color-gray-medium": bottomMuted }) }>{ bottomValue }</div> + </div> + ); +} + +Label.displayName = "Label"; + +export default Label; \ No newline at end of file diff --git a/frontend/app/components/Errors/ui/divider.css b/frontend/app/components/Errors/ui/divider.css new file mode 100644 index 000000000..df883d534 --- /dev/null +++ b/frontend/app/components/Errors/ui/divider.css @@ -0,0 +1,4 @@ +.divider { + height: 1px; + width: 100%; +} \ No newline at end of file diff --git a/frontend/app/components/Errors/ui/errorName.css b/frontend/app/components/Errors/ui/errorName.css new file mode 100644 index 000000000..aacd7f7ef --- /dev/null +++ b/frontend/app/components/Errors/ui/errorName.css @@ -0,0 +1,5 @@ +.function { + max-width: 100% !important; + color: $gray-medium; + font-weight: 300; +} \ No newline at end of file diff --git a/frontend/app/components/ForgotPassword/ForgotPassword.js b/frontend/app/components/ForgotPassword/ForgotPassword.js new file mode 100644 index 000000000..5d9cc504f --- /dev/null +++ b/frontend/app/components/ForgotPassword/ForgotPassword.js @@ -0,0 +1,202 @@ +import { connect } from 'react-redux'; +import ReCAPTCHA from 'react-google-recaptcha'; +import withPageTitle from 'HOCs/withPageTitle'; +import { Loader, Button, Link, Icon, Message } from 'UI'; +import { requestResetPassword, resetPassword } from 'Duck/user'; +import { login as loginRoute } from 'App/routes'; +import cn from 'classnames'; +import stl from './forgotPassword.css'; + +const LOGIN = loginRoute(); +const recaptchaRef = React.createRef(); +const ERROR_DONT_MATCH = "Passwords don't match."; +const MIN_LENGTH = 8; +const PASSWORD_POLICY = `Password should contain at least ${ MIN_LENGTH } symbols.`; + +const checkDontMatch = (newPassword, newPasswordRepeat) => + newPasswordRepeat.length > 0 && newPasswordRepeat !== newPassword; + +@connect( + state => ({ + errors: state.getIn([ 'user', 'requestResetPassowrd', 'errors' ]), + resetErrors: state.getIn([ 'user', 'resetPassword', 'errors' ]), + loading: state.getIn([ 'user', 'requestResetPassowrd', 'loading' ]), + }), + { requestResetPassword, resetPassword }, +) +@withPageTitle("Password Reset - OpenReplay") +export default class ForgotPassword extends React.PureComponent { + state = { + email: '', + code: ' ', + password: '', + passwordRepeat: '', + requested: false, + updated: false, + }; + + handleSubmit = (token) => { + const { email, requested, code, password } = this.state; + + if (!requested) { + this.props.requestResetPassword({ email: email.trim(), 'g-recaptcha-response': token }).then(() => { + const { errors } = this.props; + if (!errors) this.setState({ requested: true }); + }); + } else { + if (this.isSubmitDisabled()) return; + this.props.resetPassword({ email: email.trim(), code, password }).then(() => { + const { resetErrors } = this.props; + if (!resetErrors) this.setState({ updated: true }); + }); + } + } + + isSubmitDisabled() { + const { password, passwordRepeat } = this.state; + if (password !== passwordRepeat || + password.length < MIN_LENGTH) return true; + return false; + } + + write = ({ target: { value, name } }) => this.setState({ [ name ]: value }) + + shouldShouwPolicy() { + const { password } = this.state; + if (password.length > 7) return false; + if (password === '') return false; + return true; + } + + onSubmit = e => { + e.preventDefault(); + if (window.ENV.CAPTCHA_ENABLED && recaptchaRef.current) { + recaptchaRef.current.execute() + } else if (!window.ENV.CAPTCHA_ENABLED) { + this.handleSubmit(); + } + } + + render() { + const { errors, loading } = this.props; + const { requested, updated, password, passwordRepeat, code } = this.state; + const dontMatch = checkDontMatch(password, passwordRepeat); + + return ( + <div className="flex" style={{ height: '100vh'}}> + <div className={cn("w-6/12", stl.left)}> + <div className="px-6 pt-10"> + <img src="/logo-white.svg" /> + </div> + <div className="color-white text-lg flex items-center"> + <div className="flex items-center justify-center w-full" style={{ height: 'calc(100vh - 130px)'}}> + <div className="text-4xl">Welcome Back!</div> + </div> + </div> + </div> + <div className="w-6/12 flex items-center justify-center"> + <form onSubmit={ this.onSubmit }> + <div className="mb-8"> + <h2 className="text-center text-3xl mb-6">Reset Password</h2> + </div> + <Loader loading={ loading }> + <div data-hidden={ updated }> + { window.ENV.CAPTCHA_ENABLED && ( + <div className={ stl.recaptcha }> + <ReCAPTCHA + ref={ recaptchaRef } + size="invisible" + data-hidden={ requested } + sitekey={ window.ENV.CAPTCHA_SITE_KEY } + onChange={ token => this.handleSubmit(token) } + /> + </div> + )} + + { !requested ? + <div className={ stl.inputWithIcon }> + <i className={ stl.inputIconUser } /> + <input + autoFocus={true} + autocomplete="email" + type="text" + placeholder="Email" + name="email" + onChange={ this.write } + className={ stl.input } + /> + </div> + : + <React.Fragment> + <div className={ stl.inputWithIcon } > + <i className={ stl.inputIconPassword } /> + <input + autocomplete="new-password" + type="text" + placeholder="Code" + name="code" + onChange={ this.write } + className={ stl.input } + /> + </div> + + <div className={ stl.inputWithIcon } > + <i className={ stl.inputIconPassword } /> + <input + autocomplete="new-password" + type="password" + placeholder="New Password" + name="password" + onChange={ this.write } + className={ stl.input } + /> + </div> + <div className={ stl.passwordPolicy } data-hidden={ !this.shouldShouwPolicy() }> + { PASSWORD_POLICY } + </div> + <div className={ stl.inputWithIcon } > + <i className={ stl.inputIconPassword } /> + <input + autocomplete="new-password" + type="password" + placeholder="Repeat New Password" + name="passwordRepeat" + onChange={ this.write } + className={ stl.input } + /> + </div> + </React.Fragment> + } + + <Message error hidden={ !dontMatch }> + { ERROR_DONT_MATCH } + </Message> + </div> + </Loader> + <div className="mt-4"> + { errors && + <div className={ stl.errors }> + { errors.map(error => <span>{ error }<br /></span>) } + </div> + } + <div data-hidden={ !updated } className={ stl.success }> + <Icon name="check" size="30" color="green" /> + { 'Your password has been updated sucessfully.' } + </div> + </div> + <div className={ stl.formFooter }> + <Button data-hidden={ updated } type="submit" primary >{ 'Reset' }</Button> + + <div className={ stl.links }> + <Link to={ LOGIN }> + <Button data-hidden={ !updated } type="submit" primary >{ 'Login' }</Button> + <div data-hidden={ updated }>{'Back to Login'}</div> + </Link> + </div> + </div> + </form> + </div> + </div> + ); + } +} diff --git a/frontend/app/components/ForgotPassword/ReCaptcha.js b/frontend/app/components/ForgotPassword/ReCaptcha.js new file mode 100644 index 000000000..f8d69b2f3 --- /dev/null +++ b/frontend/app/components/ForgotPassword/ReCaptcha.js @@ -0,0 +1,49 @@ +class ReCaptcha extends Component { + constructor(props) { + super(props); + + this.loadRecaptcha = this.loadRecaptcha.bind(this); + this.handleChange = this.handleChange.bind(this); + } + + componentDidMount() { + if (document.readyState === 'complete') { + // Window was already loaded (the component is rendered later on) + // ReCaptacha can be safely loaded + this.loadRecaptcha(); + } else { + // Wait that the window gets loaded to load the ReCaptcha + window.onload = this.loadRecaptcha; + } + } + + getValue() { + window.grecaptcha.getResponse(this.recatchaElt); + } + + loadRecaptcha() { + const { id, apiKey, theme } = this.props; + + this.recatchaElt = window.grecaptcha.render(id, { + sitekey: apiKey, + size: 'invisible', + callback: this.handleChange, + }, true); + } + + handleChange() { + const { onChange } = this.props; + + onChange(this.getValue()); + } + + render() { + const { id } = this.props; + + return ( + <div id={ id } /> + ); + } +} + +export default ReCaptcha; diff --git a/frontend/app/components/ForgotPassword/forgotPassword.css b/frontend/app/components/ForgotPassword/forgotPassword.css new file mode 100644 index 000000000..bd270c4e9 --- /dev/null +++ b/frontend/app/components/ForgotPassword/forgotPassword.css @@ -0,0 +1,160 @@ +@import "icons.css"; + +.form { + position: absolute; + top: 50%; + margin-top: -300px; + width: 520px; + left: 50%; + margin-left: -260px; + + & .passwordPolicy { + color: $gray-medium; + padding: 5px 0 10px; + font-size: 13px; + } + + & form { + padding: 10px 70px; + border: solid 2px $gray-light; + border-radius: 2px; + background-color: white; + } + & h2 { + text-align: center; + font-size: 20px; + color: #555555; + margin: 35px 0; + font-weight: 300; + } +} + +.formFooter { + text-align: center; + padding: 15px 0; +} + +.links { + display: flex; + align-items: center; + justify-content: center; + padding: 10px 0; + margin-top: 20px; + + & .divider { + width: 1px; + height: 12px; + background-color: $gray-medium; + margin: 0 5px; + } +} + +.logo { + background-image: svg-load('logo.svg'); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + height: 50px; + margin-bottom: 20px; +} + + +.input { + display: block; + width: 100%; + height: 45px; + line-height: 45px; + border: $gray-light solid 1px; + border-radius: 3px; + font-size: 14px; + padding: 0 10px; + transition: all 0.2s; + margin-top: 15px; + + &::placeholder { + color: #AAA; + } + + &:focus { + border-color: $teal; + transition: all 0.2s; + } +} + +.errors { + border-radius: 5px; + width: 400px; + margin: auto; + border: 2px solid $red; + padding: 15px; + background-color: $white; +} + +.submit { + display: block; + border-radius: 5px; + background: $teal; + width: 135px; + height: 45px; + margin: 20px auto; + color: $white; + font-size: 16px; + cursor: pointer; +} + +.inputWithIcon { + position: relative; + + & input { + padding-left: 45px; + } +} + +@define-mixin inputIcon $name { + position: absolute; + left: 15px; + top: calc(50% - 8px); + @mixin icon $name, $gray-medium, 15px; +} + +.inputIconUser { + @mixin inputIcon user-alt; +} + +.inputIconPassword { + @mixin inputIcon lock-alt; +} + +.recaptcha { + display: flex; + justify-content: center; +} + +.success { + padding: 10px; + text-align: center; + display: flex; + flex-flow: column; + justify-content: center; + align-items: center; + line-height: 45px; +} + +.left { + background: rgb(57,78,255); + background: linear-gradient(135deg, rgba(57,78,255,1) 0%, rgba(58,89,245,1) 21%, rgba(62,161,183,1) 69%, rgba(62,170,175,1) 100%); + background-image: svg-load(pattern-login.svg), linear-gradient(135deg, rgba(57,78,255,1) 0%, rgba(58,89,245,1) 21%, rgba(62,161,183,1) 69%, rgba(62,170,175,1) 100%); + background-size: cover; + background-position: center center; + position: relative; + & .bottom { + background-color: black; + } +} + +.formField { + margin-bottom: 20px; + > & label { + margin-bottom: 10px !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelDetails/FunnelDetails.js b/frontend/app/components/Funnels/FunnelDetails/FunnelDetails.js new file mode 100644 index 000000000..18702f5aa --- /dev/null +++ b/frontend/app/components/Funnels/FunnelDetails/FunnelDetails.js @@ -0,0 +1,158 @@ +import React, { useState, useEffect } from 'react' +import { Tabs, Loader } from 'UI' +import FunnelHeader from 'Components/Funnels/FunnelHeader' +import FunnelGraph from 'Components/Funnels/FunnelGraph' +import FunnelSessionList from 'Components/Funnels/FunnelSessionList' +import FunnelOverview from 'Components/Funnels/FunnelOverview' +import FunnelIssues from 'Components/Funnels/FunnelIssues' +import { connect } from 'react-redux'; +import { + fetch, fetchInsights, fetchList, fetchFiltered, fetchIssuesFiltered, fetchSessionsFiltered, fetchIssueTypes, resetFunnel +} from 'Duck/funnels'; +import { applyFilter, setFilterOptions, resetFunnelFilters, setInitialFilters } from 'Duck/funnelFilters'; +import { withRouter } from 'react-router'; +import { sessions as sessionsRoute, funnel as funnelRoute, withSiteId } from 'App/routes'; +import EventFilter from 'Shared/EventFilter'; +import cn from 'classnames'; +import IssuesEmptyMessage from 'Components/Funnels/IssuesEmptyMessage' + +const TAB_ISSUES = 'ANALYSIS'; +const TAB_SESSIONS = 'SESSIONS'; + +const TABS = [ TAB_ISSUES, TAB_SESSIONS ].map(tab => ({ + text: tab, + disabled: false, + key: tab, +})); + +const FunnelDetails = (props) => { + const { insights, funnels, funnel, funnelId, loading, liveFilters, issuesLoading, sessionsLoading } = props; + const [activeTab, setActiveTab] = useState(TAB_ISSUES) + const [showFilters, setShowFilters] = useState(false) + const [mounted, setMounted] = useState(false); + const onTabClick = activeTab => setActiveTab(activeTab) + + useEffect(() => { + if (funnels.size === 0) { + props.fetchList(); + props.fetchIssueTypes() + } + + props.fetch(funnelId).then(() => { + setMounted(true); + }) + + props.fetchInsights(funnelId, {}) + }, []); + + useEffect(() => { + if (funnel && funnel.filter && liveFilters.events.size === 0) { + props.setInitialFilters(); + } + }, [funnel]) + + const onBack = () => { + props.history.push(sessionsRoute()); + } + + const redirect = funnelId => { + const { siteId, history } = props; + props.resetFunnel(); + props.resetFunnelFilters(); + + history.push(withSiteId(funnelRoute(parseInt(funnelId)), siteId)); + } + + const renderActiveTab = (tab, hasNoStages) => { + switch(tab) { + case TAB_ISSUES: + return !hasNoStages && <FunnelIssues funnelId={funnelId} /> + case TAB_SESSIONS: + return <FunnelSessionList funnelId={funnelId} /> + } + } + + const hasNoStages = !loading && insights.stages.length <= 1; + const showEmptyMessage = hasNoStages && activeTab === TAB_ISSUES && !loading; + + return ( + <div className="page-margin container-70" > + <FunnelHeader + funnel={funnel} + insights={insights} + redirect={redirect} + funnels={funnels} + onBack={onBack} + funnelId={funnelId} + toggleFilters={() => setShowFilters(!showFilters)} + showFilters={showFilters} + /> + <div className="my-3" /> + {showFilters && + <EventFilter + funnel={funnel} + onHide={() => setShowFilters(!showFilters)} + />} + <div className="my-3" /> + <Tabs + tabs={ TABS } + active={ activeTab } + onClick={ onTabClick } + /> + <div className="my-8" /> + <Loader loading={loading}> + <IssuesEmptyMessage onAddEvent={() => setShowFilters(true)} show={showEmptyMessage}> + <div> + <div className={cn("flex items-start", { 'hidden' : activeTab === TAB_SESSIONS || hasNoStages })}> + <div className="flex-1"> + <FunnelGraph data={insights.stages} funnelId={funnelId} /> + </div> + <div style={{ width: '35%'}} className="px-14"> + <FunnelOverview funnel={insights} /> + </div> + </div> + <div className="my-8" /> + <Loader loading={issuesLoading || sessionsLoading}> + { renderActiveTab(activeTab, hasNoStages) } + </Loader> + </div> + </IssuesEmptyMessage> + </Loader> + + </div> + ) +} + +export default connect((state, props) => { + const insightsLoading = state.getIn(['funnels', 'fetchInsights', 'loading']); + const issuesLoading = state.getIn(['funnels', 'fetchIssuesRequest', 'loading']); + const funnelLoading = state.getIn(['funnels', 'fetchRequest', 'loading']); + const sessionsLoading = state.getIn(['funnels', 'fetchSessionsRequest', 'loading']); + return { + funnels: state.getIn(['funnels', 'list']), + funnel: state.getIn(['funnels', 'instance']), + insights: state.getIn(['funnels', 'insights']), + loading: funnelLoading || (insightsLoading && (issuesLoading || sessionsLoading)), + issuesLoading, + sessionsLoading, + funnelId: props.match.params.funnelId, + activeStages: state.getIn(['funnels', 'activeStages']), + funnelFilters: state.getIn(['funnels', 'funnelFilters']), + siteId: state.getIn([ 'user', 'siteId' ]), + liveFilters: state.getIn(['funnelFilters', 'appliedFilter']), + } +}, { + fetch, + fetchInsights, + fetchFiltered, + fetchIssuesFiltered, + fetchList, + applyFilter, + setFilterOptions, + fetchIssuesFiltered, + fetchSessionsFiltered, + fetchIssueTypes, + resetFunnel, + resetFunnelFilters, + setInitialFilters +})(withRouter((FunnelDetails))) diff --git a/frontend/app/components/Funnels/FunnelDetails/index.js b/frontend/app/components/Funnels/FunnelDetails/index.js new file mode 100644 index 000000000..c77dc8854 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelDetails/index.js @@ -0,0 +1 @@ +export { default } from './FunnelDetails' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelGraph/FunnelGraph.js b/frontend/app/components/Funnels/FunnelGraph/FunnelGraph.js new file mode 100644 index 000000000..ec94451d7 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelGraph/FunnelGraph.js @@ -0,0 +1,235 @@ +import React, { useState } from 'react' +import { Icon, Popup } from 'UI' +import { numberCompact } from 'App/utils'; +import { BarChart, Bar, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, LabelList, Label } from 'recharts'; +import { connect } from 'react-redux'; +import { setActiveStages } from 'Duck/funnels'; +import { Styles } from '../../Dashboard/Widgets/common'; +import { numberWithCommas } from 'App/utils' + +const MIN_BAR_HEIGHT = 20; + +function FunnelGraph(props) { + const { data, activeStages, funnelId, liveFilters } = props; + const [activeIndex, setActiveIndex] = useState(activeStages) + + const renderPercentage = (props) => { + const { + x, y, width, height, value, + } = props; + const radius = 10; + const _x = (x + width / 2) + 45; + + return ( + <g> + <svg width="46px" height="21px" version="1.1"> + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <path d="M37.2387001,0.5 L45.3588127,10.5034561 L37.4215407,20.5 L0.5,20.5 L0.5,0.5 L37.2387001,0.5 Z" id="Rectangle" stroke="#AFACAC" fill="#FFFFFF"></path> + </g> + </svg> + <text x={x} y={70} fill="#000" textAnchor="middle" dominantBaseline="middle"> + {numberCompact(value)} + </text> + </g> + ); + }; + + const renderCustomizedLabel = (props) => { + const { + x, y, width, height, value, textColor = '#fff' + } = props; + const radius = 10; + + if (value === 0) return; + + return ( + <g> + <text x={x + width / 2} y={(y - radius) + 20} fill={ textColor } font-size="12" textAnchor="middle" dominantBaseline="middle"> + {numberCompact(value)} + </text> + </g> + ); + }; + + const handleClick= (data, index) => { + if (activeStages.length === 1 && activeStages.includes(index)) { // selecting the same bar + props.setActiveStages([], null); + return; + } + + if (activeStages.length === 2) { // already having two bars + return; + } + + // new selection + const arr = activeStages.concat([index]); + props.setActiveStages(arr.sort(), arr.length === 2 && liveFilters, funnelId); + }; + + const resetActiveSatges = () => { + props.setActiveStages([], liveFilters, funnelId, true); + } + + const renderDropLabel = ({ x, y, width, value }) => { + if (value === 0) return; + return ( + <text fill="#cc0000" x={x + width / 2} y={y - 5} textAnchor="middle" fontSize="12">{value}</text> + ) + } + + const renderMainLabel = ({ x, y, width, value }) => { + return ( + <text fill="#FFFFFF" x={x + width / 2} y={y + 14} textAnchor="middle" fontSize="12">{numberWithCommas(value)}</text> + ) + } + + + const CustomBar = (props) => { + const { fill, x, y, width, height, sessionsCount, index, dropDueToIssues } = props; + const yp = sessionsCount < MIN_BAR_HEIGHT ? (MIN_BAR_HEIGHT - 1): dropDueToIssues + const tmp = (height <= 20 ? 20 : height) - (TEMP[index].height > 20 ? 0 : TEMP[index].height); + return ( + <svg > + <rect x={x} y={y} width={width} height={tmp} fill={fill} /> + </svg> + ) + } + const MainBar = (props) => { + const { fill, x, y, width, height, sessionsCount, index, dropDueToIssues, hasSelection = false } = props; + const yp = sessionsCount < MIN_BAR_HEIGHT ? (MIN_BAR_HEIGHT - 1): dropDueToIssues + + TEMP[index] = {height,y}; + + return ( + <svg style={{ cursor: hasSelection ? '' : 'pointer' }}> + <rect x={x} y={y} width={width} height={height} fill={fill} /> + </svg> + ) + } + + const renderDropPct = (props) => { // TODO + const { fill, x, y, width, height, value, totalBars } = props; + const barW = x + ((730 / totalBars) / 2); + + return ( + <svg > + <rect x={barW} y={80} width={width} height={20} fill='red' /> + </svg> + ) + } + + const CustomTooltip = ({ active, payload, msg = '' }) => { + return ( + <div className="rounded border bg-white p-2"> + <p className="text-sm">{msg}</p> + </div> + ); + }; + + const TEMP = {} + + return ( + <div className="relative"> + { activeStages.length === 2 && ( + <div + className="absolute right-0 top-0 cursor-pointer z-10" + style={{marginRight: '60px', marginTop: '0' }} + onClick={resetActiveSatges} + > + <Popup + trigger={ + <Icon name="sync-alt" size="15" color="teal" /> + } + content={ `Reset Selection` } + size="tiny" + inverted + position="top center" + /> + </div> + )} + <BarChart width={800} height={190} data={data} + margin={{top: 20, right: 20, left: 0, bottom: 0}} + background={'transparent'} + > + <CartesianGrid strokeDasharray="1 3" stroke="#BBB" vertical={false} /> + {activeStages.length < 2 && <Tooltip cursor={{ fill: 'transparent' }} content={<CustomTooltip msg={activeStages.length > 0 ? 'Select one more event.' : 'Select any two events to analyze in depth.'} />} />} + <Bar + dataKey="sessionsCount" + onClick={handleClick} + maxBarSize={80} + stackId="a" + shape={<MainBar hasSelection={activeStages.length === 2} />} + cursor="pointer" + minPointSize={MIN_BAR_HEIGHT} + background={false} + > + <LabelList dataKey="sessionsCount" content={renderMainLabel} /> + { + data.map((entry, index) => { + const selected = activeStages.includes(index) || (index > activeStages[0] && index < activeStages[1]); + const opacity = activeStages.length > 0 && !selected ? 0.4 : 1; + return ( + <Cell + cursor="pointer" + fill={selected ? '#394EFF' : (opacity === 1 ? '#3EAAAF' : '#CCC') } + key={`cell-${index}`} + /> + ) + }) + } + </Bar> + + <Bar + hide={activeStages.length !== 2} + dataKey="dropDueToIssues" + onClick={handleClick} + maxBarSize={80} + stackId="a" + shape={<CustomBar />} + minPointSize={MIN_BAR_HEIGHT} + > + <LabelList dataKey="dropDueToIssues" content={renderDropLabel} /> + { + data.map((entry, index) => { + const selected = activeStages.includes(index) || (index > activeStages[0] && index < activeStages[1]); + const opacity = activeStages.length > 0 && !selected ? 0.4 : 1; + return ( + <Cell + opacity={opacity} + cursor="pointer" + fill={ activeStages[1] === index ? '#cc000040' : 'transparent' } + key={`cell-${index}`} + /> + ) + }) + } + </Bar> + + <XAxis + stroke={0} + dataKey="label" + strokeWidth={0} + interval={0} + tick ={{ fill: '#666', fontSize: 12 }} + xAxisId={0} + /> + <XAxis + stroke={0} + xAxisId={1} + dataKey="value" + strokeWidth={0} + interval={0} + dy={-15} dx={0} + tick ={{ fill: '#666', fontSize: 12 }} + tickFormatter={val => '"' + val + '"'} + /> + <YAxis interval={ 0 } strokeWidth={0} tick ={{ fill: '#999999', fontSize: 11 }} tickFormatter={val => Styles.tickFormatter(val)} /> + </BarChart> + </div> + ) +} + +export default connect(state => ({ + activeStages: state.getIn(['funnels', 'activeStages']).toJS(), + liveFilters: state.getIn(['funnelFilters', 'appliedFilter']), +}), { setActiveStages })(FunnelGraph) diff --git a/frontend/app/components/Funnels/FunnelGraph/index.js b/frontend/app/components/Funnels/FunnelGraph/index.js new file mode 100644 index 000000000..990d34099 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelGraph/index.js @@ -0,0 +1 @@ +export { default } from './FunnelGraph' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelGraphSmall/FunnelGraphSmall.js b/frontend/app/components/Funnels/FunnelGraphSmall/FunnelGraphSmall.js new file mode 100644 index 000000000..375af9813 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelGraphSmall/FunnelGraphSmall.js @@ -0,0 +1,27 @@ +import React from 'react' +import { BarChart, Bar, Cell } from 'recharts'; + +function FunnelGraphSmall({ data }) { + return ( + <div + className="rounded-md flex items-center justify-center p-2" + style={{ backgroundColor: 'rgba(62, 170, 175, 0.2)'}} + > + <BarChart width={50} height={40} data={data}> + <Bar + dataKey='sessionsCount' + maxBarSize={6} + background={{ fill: '#DDDDDD' }} + > + { + data.map((entry, index) => ( + <Cell cursor="pointer" fill={'#3EAAAF'} key={`cell-${index}`}/> + )) + } + </Bar> + </BarChart> + </div> + ) +} + +export default FunnelGraphSmall diff --git a/frontend/app/components/Funnels/FunnelGraphSmall/index.js b/frontend/app/components/Funnels/FunnelGraphSmall/index.js new file mode 100644 index 000000000..b90d0224d --- /dev/null +++ b/frontend/app/components/Funnels/FunnelGraphSmall/index.js @@ -0,0 +1 @@ +export { default } from './FunnelGraphSmall' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelHeader/FunnelDropdown.js b/frontend/app/components/Funnels/FunnelHeader/FunnelDropdown.js new file mode 100644 index 000000000..88715c174 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelHeader/FunnelDropdown.js @@ -0,0 +1,38 @@ +import React from 'react' +import { connect } from 'react-redux' +import { withRouter } from 'react-router' +import { Dropdown } from 'UI' +import { funnel as funnelRoute, withSiteId } from 'App/routes'; + +function FunnelDropdown(props) { + const { options, funnel } = props; + + const writeOption = (e, { name, value }) => { + const { siteId, history } = props; + console.log(value) + history.push(withSiteId(funnelRoute(parseInt(value)), siteId)); + } + + return ( + <div> + <Dropdown + selection + basic + options={ options.toJS() } + name="funnel" + value={ funnel.funnelId || ''} + defaultValue={ funnel.funnelId } + icon={null} + style={{ border: 'none' }} + onChange={ writeOption } + selectOnBlur={false} + /> + </div> + ) +} + +export default connect((state, props) => ({ + funnels: state.getIn(['funnels', 'list']), + funnel: state.getIn(['funnels', 'instance']), + siteId: state.getIn([ 'user', 'siteId' ]), +}), { })(withRouter(FunnelDropdown)) diff --git a/frontend/app/components/Funnels/FunnelHeader/FunnelHeader.js b/frontend/app/components/Funnels/FunnelHeader/FunnelHeader.js new file mode 100644 index 000000000..a747c9905 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelHeader/FunnelHeader.js @@ -0,0 +1,120 @@ +import React, { useEffect, useState } from 'react'; +import { Icon, BackLink, IconButton, Dropdown, Popup, TextEllipsis, Button } from 'UI'; +import { remove as deleteFunnel, fetch, fetchInsights, fetchIssuesFiltered, fetchSessionsFiltered } from 'Duck/funnels'; +import { applyFilter } from 'Duck/funnelFilters'; +import DateRange from 'Shared/DateRange'; +import { connect } from 'react-redux'; +import { confirm } from 'UI/Confirmation'; +import FunnelSaveModal from 'Components/Funnels/FunnelSaveModal'; +import stl from './funnelHeader.css'; + +const Info = ({ label = '', value = '', className = 'mx-4' }) => { + return ( + <div className={className}> + <span className="color-gray-medium">{label}</span> + <span className="font-medium ml-2">{value}</span> + </div> + ) +} + +const FunnelHeader = (props) => { + const { funnelFilters, funnel, insights, funnels, onBack, funnelId, showFilters = false, renameHandler } = props; + + const [showSaveModal, setShowSaveModal] = useState(false) + + const writeOption = (e, { name, value }) => { + props.fetch(value) + props.redirect(value) + } + + useEffect(() => { + if (funnel.funnelId && funnel.funnelId !== funnelId) { + props.fetchInsights(funnel.funnelId, {}) + props.fetchIssuesFiltered(funnel.funnelId, {}) + props.fetchSessionsFiltered(funnel.funnelId, {}) + } + }, [funnel]) + + const deleteFunnel = async (e, funnel) => { + e.preventDefault(); + e.stopPropagation(); + + if (await confirm({ + header: 'Delete Funnel', + confirmButton: 'Delete', + confirmation: `Are you sure you want to permanently delete "${funnel.name}"?` + })) { + props.deleteFunnel(funnel.funnelId).then(props.onBack); + } else {} + } + + const onDateChange = (e) => { + props.applyFilter(e, funnel.funnelId) + } + + const options = funnels.map(({ funnelId, name }) => ({ text: name, value: funnelId })).toJS(); + const selectedFunnel = funnels.filter(i => i.funnelId === parseInt(funnelId)).first() || {}; + + return ( + <div> + <div className="bg-white border rounded flex items-center w-full relative group pr-2"> + <BackLink onClick={onBack} vertical className="absolute" style={{ left: '-50px', top: '8px' }} /> + <FunnelSaveModal + show={showSaveModal} + closeHandler={() => setShowSaveModal(false)} + /> + <div className="flex items-center mr-auto relative"> + <Dropdown + scrolling + trigger={ + <div className="text-xl capitalize font-medium" style={{ maxWidth: '300px', overflow: 'hidden'}}> + <TextEllipsis text={selectedFunnel.name} /> + </div> + } + options={options} + className={ stl.dropdown } + name="funnel" + value={ parseInt(funnelId) } + icon={null} + onChange={ writeOption } + selectOnBlur={false} + icon={ <Icon name="chevron-down" color="gray-dark" size="14" className={stl.dropdownIcon} /> } + /> + <Info label="Events" value={funnel.filter.events.size} /> + <span>-</span> + <Button plain onClick={props.toggleFilters}>{ showFilters ? 'HIDE' : 'EDIT FUNNEL' }</Button> + <Info label="Sessions" value={insights.sessionsCount} /> + <Info label="Conversion" value={`${insights.conversions}%`} /> + </div> + <div className="flex items-center"> + <div className="flex items-center invisible group-hover:visible"> + <Popup + trigger={<IconButton icon="edit" onClick={() => setShowSaveModal(true)} />} + content={ `Edit Funnel` } + size="tiny" + inverted + position="top center" + /> + <Popup + trigger={<IconButton icon="trash" onClick={(e) => deleteFunnel(e, funnel)} className="ml-2 mr-2" />} + content={ `Remove Funnel` } + size="tiny" + inverted + position="top center" + /> + </div> + <DateRange + rangeValue={funnelFilters.rangeValue} + startDate={funnelFilters.startDate} + endDate={funnelFilters.endDate} + onDateChange={onDateChange} + /> + </div> + </div> + </div> + ) +} + +export default connect(state => ({ + funnelFilters: state.getIn([ 'funnelFilters', 'appliedFilter']), +}), { applyFilter, deleteFunnel, fetch, fetchInsights, fetchIssuesFiltered, fetchSessionsFiltered })(FunnelHeader) diff --git a/frontend/app/components/Funnels/FunnelHeader/funnelHeader.css b/frontend/app/components/Funnels/FunnelHeader/funnelHeader.css new file mode 100644 index 000000000..7ab834b76 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelHeader/funnelHeader.css @@ -0,0 +1,30 @@ +.dropdown { + display: flex !important; + align-items: center; + padding: 0 20px; + border-radius: 0; + border-radius: 0; + color: $gray-darkest; + font-weight: 500; + height: 54px; + padding-right: 20px; + border-right: solid thin #eee; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + &:hover { + background-color: $gray-lightest; + } +} + +.dropdownTrigger { + padding: 4px 8px; + border-radius: 3px; + &:hover { + background-color: $gray-light; + } +} + +.dropdownIcon { + margin-top: 4px; + margin-left: 6px; +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelHeader/index.js b/frontend/app/components/Funnels/FunnelHeader/index.js new file mode 100644 index 000000000..a5efa97af --- /dev/null +++ b/frontend/app/components/Funnels/FunnelHeader/index.js @@ -0,0 +1 @@ +export { default } from './FunnelHeader'; \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelIssueDetails/FunnelIssueDetails.js b/frontend/app/components/Funnels/FunnelIssueDetails/FunnelIssueDetails.js new file mode 100644 index 000000000..0bb049d24 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssueDetails/FunnelIssueDetails.js @@ -0,0 +1,43 @@ +import React, { useEffect } from 'react' +import IssueItem from 'Components/Funnels/IssueItem' +import FunnelSessionList from 'Components/Funnels/FunnelSessionList' +import { connect } from 'react-redux' +import { withRouter } from 'react-router' +import { fetchIssue, setNavRef, resetIssue } from 'Duck/funnels' +import { funnel as funnelRoute, withSiteId } from 'App/routes' +import { Loader } from 'UI' + +function FunnelIssueDetails(props) { + const { issue, issueId, funnelId, loading = false } = props; + + useEffect(() => { + props.fetchIssue(funnelId, issueId) + + return () => { + props.resetIssue(); + } + }, [issueId]) + + const onBack = () => { + const { siteId, history } = props; + history.push(withSiteId(funnelRoute(parseInt(funnelId)), siteId)); + } + + return ( + <div className="page-margin container-70" > + <Loader loading={loading}> + <IssueItem issue={issue} inDetails onBack={onBack} /> + <div className="my-6" /> + <FunnelSessionList issuId={issueId} inDetails /> + </Loader> + </div> + ) +} + +export default connect((state, props) => ({ + loading: state.getIn(['funnels', 'fetchIssueRequest', 'loading']), + issue: state.getIn(['funnels', 'issue']), + issueId: props.match.params.issueId, + funnelId: props.match.params.funnelId, + siteId: state.getIn([ 'user', 'siteId' ]), +}), { fetchIssue, setNavRef, resetIssue })(withRouter(FunnelIssueDetails)) diff --git a/frontend/app/components/Funnels/FunnelIssueDetails/index.js b/frontend/app/components/Funnels/FunnelIssueDetails/index.js new file mode 100644 index 000000000..3ac32a034 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssueDetails/index.js @@ -0,0 +1 @@ +export { default } from './FunnelIssueDetails' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelIssues/FunnelIssues.js b/frontend/app/components/Funnels/FunnelIssues/FunnelIssues.js new file mode 100644 index 000000000..82d39037c --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssues/FunnelIssues.js @@ -0,0 +1,83 @@ +import React, { useState } from 'react' +import { connect } from 'react-redux' +import { fetchIssues, fetchIssuesFiltered } from 'Duck/funnels' +import { LoadMoreButton, NoContent, Loader } from 'UI' +import FunnelIssuesHeader from '../FunnelIssuesHeader' +import IssueItem from '../IssueItem'; +import { funnelIssue as funnelIssueRoute, withSiteId } from 'App/routes' +import { withRouter } from 'react-router' +import IssueFilter from '../IssueFilter'; +import SortDropdown from './SortDropdown'; + +const PER_PAGE = 10; + +function FunnelIssues(props) { + const { + funnel, list, loading = false, + criticalIssuesCount, issueFilters, sort + } = props; + + const [showPages, setShowPages] = useState(1) + + const addPage = () => setShowPages(showPages + 1); + + const onClick = ({ issueId }) => { + const { siteId, history } = props; + history.push(withSiteId(funnelIssueRoute(funnel.funnelId, issueId), siteId)); + } + + let filteredList = issueFilters.size > 0 ? list.filter(item => issueFilters.includes(item.type)) : list; + filteredList = sort.sort ? filteredList.sortBy(i => i[sort.sort]) : filteredList; + filteredList = sort.order === 'desc' ? filteredList.reverse() : filteredList; + const displayedCount = Math.min(showPages * PER_PAGE, filteredList.size); + + return ( + <div> + <FunnelIssuesHeader criticalIssuesCount={criticalIssuesCount} /> + <div className="my-5 flex items-start justify-between"> + <IssueFilter /> + <div className="flex items-center ml-6 flex-shrink-0"> + <span className="mr-2 color-gray-medium">Sort By</span> + <SortDropdown /> + </div> + </div> + <NoContent + title="No Issues Found!" + subtext="Please try changing your search parameters." + icon="exclamation-circle" + show={ !loading && filteredList.size === 0} + > + { filteredList.take(displayedCount).map(issue => ( + <div className="mb-4"> + <IssueItem + key={ issue.issueId } + issue={ issue } + onClick={() => onClick(issue)} + /> + </div> + ))} + + <LoadMoreButton + className="mt-12 mb-12" + displayedCount={displayedCount} + totalCount={filteredList.size} + loading={loading} + onClick={addPage} + /> + </NoContent> + </div> + ) +} + +export default connect(state => ({ + list: state.getIn(['funnels', 'issues']), + criticalIssuesCount: state.getIn(['funnels', 'criticalIssuesCount']), + loading: state.getIn(['funnels', 'fetchIssuesRequest', 'loading']), + siteId: state.getIn([ 'user', 'siteId' ]), + funnel: state.getIn(['funnels', 'instance']), + activeStages: state.getIn(['funnels', 'activeStages']), + funnelFilters: state.getIn(['funnels', 'funnelFilters']), + liveFilters: state.getIn(['funnelFilters', 'appliedFilter']), + issueFilters: state.getIn(['funnels', 'issueFilters', 'filters']), + sort: state.getIn(['funnels', 'issueFilters', 'sort']), +}), { fetchIssues, fetchIssuesFiltered })(withRouter(FunnelIssues)) diff --git a/frontend/app/components/Funnels/FunnelIssues/SortDropdown/SortDropdown.js b/frontend/app/components/Funnels/FunnelIssues/SortDropdown/SortDropdown.js new file mode 100644 index 000000000..aa263f0d4 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssues/SortDropdown/SortDropdown.js @@ -0,0 +1,51 @@ +import { connect } from 'react-redux'; +import { Dropdown } from 'semantic-ui-react'; +import { Icon } from 'UI'; +import { sort } from 'Duck/sessions'; +import { applyIssueFilter } from 'Duck/funnels'; +import stl from './sortDropdown.css'; + +const sortOptionsMap = { + 'afectedUsers-desc': 'Affected Users (High)', + 'afectedUsers-asc': 'Affected Users (Low)', + 'conversionImpact-desc': 'Conversion Impact (High)', + 'conversionImpact-asc': 'Conversion Impact (Low)', + 'lostConversions-desc': 'Lost Conversions (High)', + 'lostConversions-asc': 'Lost Conversions (Low)', +}; + +const sortOptions = Object.entries(sortOptionsMap) + .map(([ value, text ]) => ({ value, text })); + +@connect(state => ({ + sorts: state.getIn(['funnels', 'issueFilters', 'sort']) +}), { sort, applyIssueFilter }) +export default class SortDropdown extends React.PureComponent { + state = { value: null } + sort = (e, { value }) => { + this.setState({ value: value }) + const [ sort, order ] = value.split('-'); + const sign = order === 'desc' ? -1 : 1; + this.props.applyIssueFilter({ sort: { order, sort } }); + + this.props.sort(sort, sign) + setTimeout(() => this.props.sort(sort, sign), 3000); //AAA + } + + render() { + const { sorts } = this.props; + + return ( + <Dropdown + name="sortSessions" + className={ stl.dropdown } + direction="left" + options={ sortOptions } + onChange={ this.sort } + defaultValue={sorts.sort + '-' + sorts.order} + icon={null} + icon={ <Icon name="chevron-down" color="gray-dark" size="14" className={stl.dropdownIcon} /> } + /> + ); + } +} diff --git a/frontend/app/components/Funnels/FunnelIssues/SortDropdown/index.js b/frontend/app/components/Funnels/FunnelIssues/SortDropdown/index.js new file mode 100644 index 000000000..9018d24ac --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssues/SortDropdown/index.js @@ -0,0 +1 @@ +export { default } from './SortDropdown'; diff --git a/frontend/app/components/Funnels/FunnelIssues/SortDropdown/sortDropdown.css b/frontend/app/components/Funnels/FunnelIssues/SortDropdown/sortDropdown.css new file mode 100644 index 000000000..87e26bc68 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssues/SortDropdown/sortDropdown.css @@ -0,0 +1,23 @@ +.dropdown { + display: flex !important; + padding: 4px 6px; + border-radius: 3px; + color: $gray-darkest; + font-weight: 500; + &:hover { + background-color: $gray-light; + } +} + +.dropdownTrigger { + padding: 4px 8px; + border-radius: 3px; + &:hover { + background-color: $gray-light; + } +} + +.dropdownIcon { + margin-top: 2px; + margin-left: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelIssues/index.js b/frontend/app/components/Funnels/FunnelIssues/index.js new file mode 100644 index 000000000..051a19336 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssues/index.js @@ -0,0 +1 @@ +export { default } from './FunnelIssues' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelIssuesHeader/DateRange.js b/frontend/app/components/Funnels/FunnelIssuesHeader/DateRange.js new file mode 100644 index 000000000..e80b8d1d8 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssuesHeader/DateRange.js @@ -0,0 +1,26 @@ +import { connect } from 'react-redux'; +import { applyFilter, fetchList } from 'Duck/filters'; +import { fetchList as fetchFunnelsList } from 'Duck/funnels'; +import DateRangeDropdown from 'Shared/DateRangeDropdown'; + +@connect(state => ({ + rangeValue: state.getIn([ 'filters', 'appliedFilter', 'rangeValue' ]), + startDate: state.getIn([ 'filters', 'appliedFilter', 'startDate' ]), + endDate: state.getIn([ 'filters', 'appliedFilter', 'endDate' ]), +}), { + applyFilter, fetchList, fetchFunnelsList +}) +export default class DateRange extends React.PureComponent { + render() { + const { startDate, endDate, rangeValue, className } = this.props; + return ( + <DateRangeDropdown + button + rangeValue={ rangeValue } + startDate={ startDate } + endDate={ endDate } + className={ className } + /> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelIssuesHeader/FunnelIssuesHeader.js b/frontend/app/components/Funnels/FunnelIssuesHeader/FunnelIssuesHeader.js new file mode 100644 index 000000000..c8155f6c8 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssuesHeader/FunnelIssuesHeader.js @@ -0,0 +1,19 @@ +import React from 'react' +import { connect } from 'react-redux'; + +function FunnelIssuesHeader({ criticalIssuesCount, filters }) { + return ( + <div className="flex items-center"> + <div className="flex items-center mr-auto text-xl"> + <div className="font-medium mr-2"> + Most significant issues + </div> + <div className="mr-2">identified in this funnel</div> + </div> + </div> + ) +} + +export default connect(state => ({ + filters: state.getIn(['funnels', 'issueFilters']) +}))(FunnelIssuesHeader) diff --git a/frontend/app/components/Funnels/FunnelIssuesHeader/index.js b/frontend/app/components/Funnels/FunnelIssuesHeader/index.js new file mode 100644 index 000000000..fc29e310d --- /dev/null +++ b/frontend/app/components/Funnels/FunnelIssuesHeader/index.js @@ -0,0 +1 @@ +export { default } from './FunnelIssuesHeader'; \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelItem/FunnelItem.js b/frontend/app/components/Funnels/FunnelItem/FunnelItem.js new file mode 100644 index 000000000..3cb024a69 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelItem/FunnelItem.js @@ -0,0 +1,32 @@ +import React from 'react' +import FunnelGraphSmall from '../FunnelGraphSmall' + +function FunnelItem({ funnel, onClick = () => null }) { + return ( + <div className="w-full flex items-center p-4 bg-white rounded border cursor-pointer" onClick={onClick}> + <div className="mr-4"> + <FunnelGraphSmall data={funnel.stages} /> + </div> + + <div className="mr-auto"> + <div className="text-xl mb-2">{funnel.name}</div> + <div className="flex items-center text-sm"> + <div className="mr-3"><span className="font-medium">{funnel.stepsCount}</span> Steps</div> + <div><span className="font-medium">{funnel.sessionsCount}</span> Sessions</div> + </div> + </div> + + <div className="text-center text-sm px-6"> + <div className="text-xl mb-2 color-red">{funnel.criticalIssuesCount}</div> + <div>Critical Issues</div> + </div> + + <div className="text-center text-sm px-6"> + <div className="text-xl mb-2">{funnel.missedConversions}%</div> + <div>Missed Conversions</div> + </div> + </div> + ) +} + +export default FunnelItem diff --git a/frontend/app/components/Funnels/FunnelItem/index.js b/frontend/app/components/Funnels/FunnelItem/index.js new file mode 100644 index 000000000..75af60792 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelItem/index.js @@ -0,0 +1 @@ +export { default } from './FunnelItem' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelList/FunnelList.js b/frontend/app/components/Funnels/FunnelList/FunnelList.js new file mode 100644 index 000000000..f7e3c70de --- /dev/null +++ b/frontend/app/components/Funnels/FunnelList/FunnelList.js @@ -0,0 +1,32 @@ +import React from 'react' +import FunnelItem from 'Components/Funnels/FunnelItem' +import FunnelListHeader from '../FunnelListHeader' +import { connect } from 'react-redux' +import { withRouter } from 'react-router' +import { funnel as funnelRoute, withSiteId } from 'App/routes' + +function FunnelList(props) { + const { list = []} = props; + + const onFlowClick = ({ funnelId }) => { + const { siteId, history } = props; + history.push(withSiteId(funnelRoute(funnelId), siteId)); + } + + return ( + <div> + <FunnelListHeader sessionsCount={300} /> + <div className="my-3" /> + { list.map(funnel => ( + <div className="mb-3"> + <FunnelItem funnel={funnel} onClick={() => onFlowClick(funnel)} /> + </div> + ))} + </div> + ) +} + +export default connect(state => ({ + list: state.getIn(['funnels', 'list']), + siteId: state.getIn([ 'user', 'siteId' ]), +}))(withRouter(FunnelList)) diff --git a/frontend/app/components/Funnels/FunnelList/index.js b/frontend/app/components/Funnels/FunnelList/index.js new file mode 100644 index 000000000..bf019d7dd --- /dev/null +++ b/frontend/app/components/Funnels/FunnelList/index.js @@ -0,0 +1 @@ +export { default } from './FunnelList' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelListHeader/DateRange.js b/frontend/app/components/Funnels/FunnelListHeader/DateRange.js new file mode 100644 index 000000000..4f2ce8e22 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelListHeader/DateRange.js @@ -0,0 +1,32 @@ +import { connect } from 'react-redux'; +import { applyFilter, fetchList } from 'Duck/filters'; +import { fetchList as fetchFunnelsList } from 'Duck/funnels'; +import DateRangeDropdown from 'Shared/DateRangeDropdown'; + +@connect(state => ({ + rangeValue: state.getIn([ 'filters', 'appliedFilter', 'rangeValue' ]), + startDate: state.getIn([ 'filters', 'appliedFilter', 'startDate' ]), + endDate: state.getIn([ 'filters', 'appliedFilter', 'endDate' ]), +}), { + applyFilter, fetchList, fetchFunnelsList +}) +export default class DateRange extends React.PureComponent { + onDateChange = (e) => { + this.props.fetchList(e.rangeValue) + this.props.fetchFunnelsList(e.rangeValue) + this.props.applyFilter(e) + } + render() { + const { startDate, endDate, rangeValue, className } = this.props; + return ( + <DateRangeDropdown + button + onChange={ this.onDateChange } + rangeValue={ rangeValue } + startDate={ startDate } + endDate={ endDate } + className={ className } + /> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelListHeader/Filters/SortDropdown.js b/frontend/app/components/Funnels/FunnelListHeader/Filters/SortDropdown.js new file mode 100644 index 000000000..a3a17458f --- /dev/null +++ b/frontend/app/components/Funnels/FunnelListHeader/Filters/SortDropdown.js @@ -0,0 +1,37 @@ +import { connect } from 'react-redux'; +import { Dropdown } from 'semantic-ui-react'; +import { Icon } from 'UI'; +import { sort } from 'Duck/sessions'; +import { applyFilter } from 'Duck/filters'; +import stl from './sortDropdown.css'; + +@connect(null, { sort, applyFilter }) +export default class SortDropdown extends React.PureComponent { + state = { value: null } + sort = (e, { value }) => { + this.setState({ value: value }) + const [ sort, order ] = value.split('-'); + const sign = order === 'desc' ? -1 : 1; + this.props.applyFilter({ order, sort }); + + this.props.sort(sort, sign) + setTimeout(() => this.props.sort(sort, sign), 3000); //AAA + } + + render() { + const { options } = this.props; + const { value = 'startTs-desc' } = this.state; + return ( + <Dropdown + name="sortSessions" + className={ stl.dropdown } + direction="left" + options={ options } + onChange={ this.sort } + defaultValue={ options[ 0 ].value } + icon={null} + icon={ <Icon name="chevron-down" color="gray-dark" size="14" className={stl.dropdownIcon} /> } + /> + ); + } +} diff --git a/frontend/app/components/Funnels/FunnelListHeader/Filters/index.js b/frontend/app/components/Funnels/FunnelListHeader/Filters/index.js new file mode 100644 index 000000000..5b18d95f3 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelListHeader/Filters/index.js @@ -0,0 +1 @@ +export { default } from './Filters'; diff --git a/frontend/app/components/Funnels/FunnelListHeader/Filters/sortDropdown.css b/frontend/app/components/Funnels/FunnelListHeader/Filters/sortDropdown.css new file mode 100644 index 000000000..87e26bc68 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelListHeader/Filters/sortDropdown.css @@ -0,0 +1,23 @@ +.dropdown { + display: flex !important; + padding: 4px 6px; + border-radius: 3px; + color: $gray-darkest; + font-weight: 500; + &:hover { + background-color: $gray-light; + } +} + +.dropdownTrigger { + padding: 4px 8px; + border-radius: 3px; + &:hover { + background-color: $gray-light; + } +} + +.dropdownIcon { + margin-top: 2px; + margin-left: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelListHeader/FunnelListHeader.js b/frontend/app/components/Funnels/FunnelListHeader/FunnelListHeader.js new file mode 100644 index 000000000..534b3010c --- /dev/null +++ b/frontend/app/components/Funnels/FunnelListHeader/FunnelListHeader.js @@ -0,0 +1,64 @@ +import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; +import { applyFilter } from 'Duck/funnels'; +import SortDropdown from './Filters/SortDropdown'; +import DateRange from 'Shared/DateRange'; +import { TimezoneDropdown } from 'UI'; +import { numberWithCommas } from 'App/utils'; + +const DEFAULT_SORT = 'startTs'; +const DEFAULT_ORDER = 'desc'; +const sortOptionsMap = { + 'startTs-desc': 'Newest', + 'startTs-asc': 'Oldest', + 'eventsCount-asc': 'Events Ascending', + 'eventsCount-desc': 'Events Descending', +}; +const sortOptions = Object.entries(sortOptionsMap) + .map(([ value, text ]) => ({ value, text })); + + +function FunnelListHeader(props) { + const { activeTab, count, applyFilter, funnelFilters } = props; + + useEffect(() => { applyFilter({ sort: DEFAULT_SORT, order: DEFAULT_ORDER }) }, []) + + const onDateChange = (e) => { + applyFilter(e) + } + + return ( + <div className="flex mb-6 justify-between items-end"> + <div className="flex items-baseline"> + <h3 className="text-2xl capitalize"> + <span>{ activeTab.name }</span> + { count ? <span className="ml-2 font-normal color-gray-medium">{ numberWithCommas(count) }</span> : '' } + </h3> + <div className="ml-3 flex items-center"> + <span className="mr-2 color-gray-medium">Sessions Captured in</span> + <DateRange + rangeValue={funnelFilters.rangeValue} + startDate={funnelFilters.startDate} + endDate={funnelFilters.endDate} + onDateChange={onDateChange} + /> + </div> + </div> + <div className="flex items-center"> + <div className="flex items-center"> + <span className="mr-2 color-gray-medium">Timezone</span> + <TimezoneDropdown /> + </div> + <div className="flex items-center ml-6"> + <span className="mr-2 color-gray-medium">Sort By</span> + <SortDropdown options={ sortOptions }/> + </div> + </div> + </div> + ); +}; + +export default connect(state => ({ + activeTab: state.getIn([ 'sessions', 'activeTab' ]), + funnelFilters: state.getIn([ 'funnels', 'funnelFilters']), +}), { applyFilter })(FunnelListHeader); diff --git a/frontend/app/components/Funnels/FunnelListHeader/index.js b/frontend/app/components/Funnels/FunnelListHeader/index.js new file mode 100644 index 000000000..5a2cf84f3 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelListHeader/index.js @@ -0,0 +1 @@ +export { default } from './FunnelListHeader' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelMenuItem/FunnelMenuItem.js b/frontend/app/components/Funnels/FunnelMenuItem/FunnelMenuItem.js new file mode 100644 index 000000000..b43d83708 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelMenuItem/FunnelMenuItem.js @@ -0,0 +1,50 @@ +import React from 'react' +import cn from 'classnames' +import stl from './funnelMenuItem.css' +import { Icon, ItemMenu, Popup } from 'UI' + +function FunnelMenuItem({ + iconName = 'info', + className, + title, + active = false, + disabled = false, + isPublic = false, + onClick, +}) { + return ( + <div + className={ cn( + className, + stl.menuItem, + "flex items-center py-1 justify-between group", + { [stl.active] : active } + )} + onClick={disabled ? null : onClick} + > + <div className={ cn(stl.iconLabel, 'flex items-center', { [stl.disabled] : disabled })}> + <div className="flex items-center justify-center w-8 h-8 flex-shrink-0"> + <Icon name={ iconName } size={ 16 } color={'gray-dark'} className="absolute" /> + </div> + <span className={cn(stl.title, 'cap-first')}>{ title }</span> + </div> + <div className="flex items-center"> + <div className={cn("mx-2", { 'invisible': !isPublic })}> + <Popup + trigger={ + <div className={cn("bg-gray-light h-8 w-8 rounded-full flex items-center justify-center", stl.teamIcon)} style={{ opacity: '0.3'}}> + <Icon name="user-friends" color="gray-dark" size={16} /> + </div> + } + content={ `Shared with team` } + size="tiny" + inverted + position="top right" + /> + </div> + </div> + </div> + ) +} + +export default FunnelMenuItem diff --git a/frontend/app/components/Funnels/FunnelMenuItem/funnelMenuItem.css b/frontend/app/components/Funnels/FunnelMenuItem/funnelMenuItem.css new file mode 100644 index 000000000..3af5fdee5 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelMenuItem/funnelMenuItem.css @@ -0,0 +1,43 @@ +.menuItem { + border-radius: 3px; + border: solid thin transparent; + color: $gray-dark; + cursor: pointer; + + &:hover { + color: $teal; + & svg { + fill: $teal; + } + & .actions { + opacity: 1; + } + } + &.active { + color: $teal; + } + + & .disabled { + opacity: 0.5; + } + + & .iconLabel { + min-width: 68%; + max-width: 68%; + } + & .title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-left: 10px; + margin-top: 1px; + } + + & .actions { + opacity: 0; + } +} + +.teamIcon { + +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelMenuItem/index.js b/frontend/app/components/Funnels/FunnelMenuItem/index.js new file mode 100644 index 000000000..6ce6f5334 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelMenuItem/index.js @@ -0,0 +1 @@ +export { default } from './FunnelMenuItem' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelOverview/FunnelOverview.js b/frontend/app/components/Funnels/FunnelOverview/FunnelOverview.js new file mode 100644 index 000000000..5e0beca21 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelOverview/FunnelOverview.js @@ -0,0 +1,22 @@ +import React from 'react' +import { Icon } from 'UI' +import { numberWithCommas } from 'App/utils' + +const style = { content: "\f10d", fontSize: "100px", color: "rgba(0,0,0,0.1)" }; +function FunnelOverview({ funnel }) { + return ( + <div className="p-4 py-5 bg-white border rounded flex flex-col justify-center" style={{ background: '#FFFEF9' }}> + <div className="uppercase flex items-center mb-4"> + <Icon name="lightbulb-on" className="mr-2" size="24" /> + <div className="text-lg font-bold color-gray-medium">Insights</div> + </div> + <div className="leading-6 relative"> + <div className="text-xl"> + <span className="">{numberWithCommas(funnel.affectedUsers)} users</span> who had this experience show a conversion impact of <span className="color-gray-darkest color-red">{funnel.conversionImpact}%</span> between <span className="font-bold color-gray-darkest">{funnel.firstStage}</span> and <span className="font-bold color-gray-darkest">{funnel.lastStage}</span> leading to an estimated <span className="color-gray-darkest color-red">{numberWithCommas(funnel.totalDropDueToIssues)}</span> lost conversions. + </div> + </div> + </div> + ) +} + +export default FunnelOverview diff --git a/frontend/app/components/Funnels/FunnelOverview/index.js b/frontend/app/components/Funnels/FunnelOverview/index.js new file mode 100644 index 000000000..c918b5d24 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelOverview/index.js @@ -0,0 +1 @@ +export { default } from './FunnelOverview' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelSaveModal/FunnelSaveModal.js b/frontend/app/components/Funnels/FunnelSaveModal/FunnelSaveModal.js new file mode 100644 index 000000000..2662c5a04 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSaveModal/FunnelSaveModal.js @@ -0,0 +1,106 @@ +import { connect } from 'react-redux'; +import { Button, Modal, Form, Icon, Checkbox } from 'UI'; +import styles from './funnelSaveModal.css'; +import { edit, save, fetchList as fetchFunnelsList } from 'Duck/funnels'; + +@connect(state => ({ + funnel: state.getIn(['funnels', 'instance']), + loading: state.getIn([ 'funnels', 'saveRequest', 'loading' ]) || + state.getIn([ 'funnels', 'updateRequest', 'loading' ]), +}), { edit, save, fetchFunnelsList }) +export default class FunnelSaveModal extends React.PureComponent { + state = { name: 'Untitled', isPublic: false }; + static getDerivedStateFromProps(props) { + if (!props.show) { + return { + name: props.funnel.name || 'Untitled', + isPublic: props.funnel.isPublic, + }; + } + return null; + } + + onNameChange = ({ target: { value } }) => { + this.props.edit({ name: value }); + }; + + onChangeOption = (e, { checked, name }) => this.props.edit({ [ name ]: checked }) + + onSave = () => { + const { funnel, closeHandler } = this.props; + if (funnel.name.trim() === '') return; + this.props.save(funnel).then(function() { + this.props.fetchFunnelsList(); + this.props.closeHandler(); + }.bind(this)); + } + + render() { + const { + show, + appliedFilter, + closeHandler, + loading, + funnel + } = this.props; + + return ( + <Modal size="tiny" open={ show }> + <Modal.Header className={ styles.modalHeader }> + <div>{ 'Save Funnel' }</div> + <Icon + role="button" + tabIndex="-1" + color="gray-dark" + size="18" + name="close" + onClick={ closeHandler } + /> + </Modal.Header> + + <Modal.Content> + <Form onSubmit={this.onSave}> + <Form.Field> + <label>{'Title:'}</label> + <input + autoFocus={ true } + className={ styles.name } + name="name" + value={ funnel.name } + onChange={ this.onNameChange } + placeholder="Title" + /> + </Form.Field> + + <Form.Field> + <div className="flex items-center"> + <Checkbox + name="isPublic" + className="font-medium" + type="checkbox" + checked={ funnel.isPublic } + onClick={ this.onChangeOption } + className="mr-3" + /> + <div className="flex items-center cursor-pointer" onClick={ () => this.props.edit({ 'isPublic' : !funnel.isPublic }) }> + <Icon name="user-friends" size="16" /> + <span className="ml-2"> Team Funnel</span> + </div> + </div> + </Form.Field> + </Form> + </Modal.Content> + <Modal.Actions className=""> + <Button + primary + onClick={ this.onSave } + loading={ loading } + > + { funnel.exists() ? 'Modify' : 'Save' } + </Button> + <Button className={ styles.cancelButton } marginRight onClick={ closeHandler }>{ 'Cancel' }</Button> + </Modal.Actions> + </Modal> + ); + } +} diff --git a/frontend/app/components/Funnels/FunnelSaveModal/funnelSaveModal.css b/frontend/app/components/Funnels/FunnelSaveModal/funnelSaveModal.css new file mode 100644 index 000000000..ed2600745 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSaveModal/funnelSaveModal.css @@ -0,0 +1,15 @@ +@import 'mixins.css'; + +.modalHeader { + display: flex !important; + align-items: center; + justify-content: space-between; +} + +.cancelButton { + @mixin plainButton; +} + +.applyButton { + @mixin basicButton; +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelSaveModal/index.js b/frontend/app/components/Funnels/FunnelSaveModal/index.js new file mode 100644 index 000000000..1265b5b10 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSaveModal/index.js @@ -0,0 +1 @@ +export { default } from './FunnelSaveModal' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelSessionList/FunnelSessionList.js b/frontend/app/components/Funnels/FunnelSessionList/FunnelSessionList.js new file mode 100644 index 000000000..191c7821b --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSessionList/FunnelSessionList.js @@ -0,0 +1,54 @@ +import React, { useState, useEffect } from 'react' +import { connect } from 'react-redux' +import SessionItem from 'Shared/SessionItem' +import { fetchSessions, fetchSessionsFiltered } from 'Duck/funnels' +import { LoadMoreButton, NoContent, Loader } from 'UI' +import FunnelSessionsHeader from '../FunnelSessionsHeader' + +const PER_PAGE = 10; + +function FunnelSessionList(props) { + const { list, sessionsTotal, sessionsSort, inDetails = false } = props; + + const [showPages, setShowPages] = useState(1) + const displayedCount = Math.min(showPages * PER_PAGE, list.size); + + const addPage = () => setShowPages(showPages + 1); + + return ( + <div> + <FunnelSessionsHeader sessionsCount={inDetails ? sessionsTotal : list.size} inDetails={inDetails} /> + <div className="mb-4" /> + <NoContent + title="No Sessions Found!" + subtext="Please try changing your search parameters." + icon="exclamation-circle" + show={ list.size === 0} + > + { list.take(displayedCount).map(session => ( + <SessionItem + key={ session.sessionId } + session={ session } + /> + ))} + + <LoadMoreButton + className="mt-12 mb-12" + displayedCount={displayedCount} + totalCount={list.size} + onClick={addPage} + /> + </NoContent> + </div> + ) +} + +export default connect(state => ({ + list: state.getIn(['funnels', 'sessions']), + sessionsTotal: state.getIn(['funnels', 'sessionsTotal']), + funnel: state.getIn(['funnels', 'instance']), + activeStages: state.getIn(['funnels', 'activeStages']).toJS(), + liveFilters: state.getIn(['funnelFilters', 'appliedFilter']), + funnelFilters: state.getIn(['funnels', 'funnelFilters']), + sessionsSort: state.getIn(['funnels', 'sessionsSort']), +}), { fetchSessions, fetchSessionsFiltered })(FunnelSessionList) diff --git a/frontend/app/components/Funnels/FunnelSessionList/index.js b/frontend/app/components/Funnels/FunnelSessionList/index.js new file mode 100644 index 000000000..45c8e472e --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSessionList/index.js @@ -0,0 +1 @@ +export { default } from './FunnelSessionList' \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelSessionsHeader/DateRange.js b/frontend/app/components/Funnels/FunnelSessionsHeader/DateRange.js new file mode 100644 index 000000000..66761ce9c --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSessionsHeader/DateRange.js @@ -0,0 +1,27 @@ +import { connect } from 'react-redux'; +import { applyFilter, fetchList } from 'Duck/filters'; +import { fetchList as fetchFunnelsList } from 'Duck/funnels'; +import DateRangeDropdown from 'Shared/DateRangeDropdown'; + +@connect(state => ({ + rangeValue: state.getIn([ 'filters', 'appliedFilter', 'rangeValue' ]), + startDate: state.getIn([ 'filters', 'appliedFilter', 'startDate' ]), + endDate: state.getIn([ 'filters', 'appliedFilter', 'endDate' ]), +}), { + applyFilter, fetchList, fetchFunnelsList +}) +export default class DateRange extends React.PureComponent { + render() { + const { startDate, endDate, rangeValue, className } = this.props; + return ( + <DateRangeDropdown + button + // onChange={ this.onDateChange } + rangeValue={ rangeValue } + startDate={ startDate } + endDate={ endDate } + className={ className } + /> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelSessionsHeader/FunnelSessionsHeader.js b/frontend/app/components/Funnels/FunnelSessionsHeader/FunnelSessionsHeader.js new file mode 100644 index 000000000..c598b1543 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSessionsHeader/FunnelSessionsHeader.js @@ -0,0 +1,32 @@ +import React from 'react' +import SortDropdown from './SortDropdown'; + +const sortOptionsMap = { + 'startedAt-desc': 'Newest', + 'startedAt-asc': 'Oldest', + 'eventsCount-asc': 'Events (Low)', + 'eventsCount-desc': 'Events (High)', +}; +const sortOptions = Object.entries(sortOptionsMap) + .map(([ value, text ]) => ({ value, text })); + +function FunnelSessionsHeader({ sessionsCount, inDetails = false }) { + const onSort = () => {} + return ( + <div className="flex items-center"> + <div className="flex items-center mr-auto text-xl"> + <div className="font-medium mr-2">{`${sessionsCount} Session${sessionsCount === 1 ? '' : 's' }`}</div> + <div className="mr-2">{ inDetails ? 'affected by this issue' : 'went through this funnel'}</div> + </div> + + <div> + <div className="flex items-center ml-6"> + <span className="mr-2 color-gray-medium">Sort By</span> + <SortDropdown options={ sortOptions } /> + </div> + </div> + </div> + ) +} + +export default FunnelSessionsHeader diff --git a/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/SortDropdown.js b/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/SortDropdown.js new file mode 100644 index 000000000..e022f8142 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/SortDropdown.js @@ -0,0 +1,36 @@ +import { connect } from 'react-redux'; +import { Dropdown } from 'semantic-ui-react'; +import { Icon } from 'UI'; +import { setSessionsSort as sort } from 'Duck/funnels'; +import { setSessionsSort } from 'Duck/funnels'; +import stl from './sortDropdown.css'; + +@connect(state => ({ + sessionsSort: state.getIn(['funnels','sessionsSort']) +}), { sort, setSessionsSort }) +export default class SortDropdown extends React.PureComponent { + state = { value: null } + sort = (e, { value }) => { + this.setState({ value: value }) + const [ sort, order ] = value.split('-'); + const sign = order === 'desc' ? -1 : 1; + setTimeout(() => this.props.sort(sort, sign), 100); + } + + render() { + const { options, issuesSort } = this.props; + const { value = 'startTs-desc' } = this.state; + return ( + <Dropdown + name="sortSessions" + className={ stl.dropdown } + direction="left" + options={ options } + onChange={ this.sort } + defaultValue={ options[ 0 ].value } + icon={null} + icon={ <Icon name="chevron-down" color="gray-dark" size="14" className={stl.dropdownIcon} /> } + /> + ); + } +} diff --git a/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/index.js b/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/index.js new file mode 100644 index 000000000..9018d24ac --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/index.js @@ -0,0 +1 @@ +export { default } from './SortDropdown'; diff --git a/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/sortDropdown.css b/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/sortDropdown.css new file mode 100644 index 000000000..87e26bc68 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSessionsHeader/SortDropdown/sortDropdown.css @@ -0,0 +1,23 @@ +.dropdown { + display: flex !important; + padding: 4px 6px; + border-radius: 3px; + color: $gray-darkest; + font-weight: 500; + &:hover { + background-color: $gray-light; + } +} + +.dropdownTrigger { + padding: 4px 8px; + border-radius: 3px; + &:hover { + background-color: $gray-light; + } +} + +.dropdownIcon { + margin-top: 2px; + margin-left: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelSessionsHeader/index.js b/frontend/app/components/Funnels/FunnelSessionsHeader/index.js new file mode 100644 index 000000000..cd3ebbc93 --- /dev/null +++ b/frontend/app/components/Funnels/FunnelSessionsHeader/index.js @@ -0,0 +1 @@ +export { default } from './FunnelSessionsHeader'; \ No newline at end of file diff --git a/frontend/app/components/Funnels/IssueFilter/IssueFilter.js b/frontend/app/components/Funnels/IssueFilter/IssueFilter.js new file mode 100644 index 000000000..f081318fe --- /dev/null +++ b/frontend/app/components/Funnels/IssueFilter/IssueFilter.js @@ -0,0 +1,55 @@ +import React from 'react' +import { connect } from 'react-redux'; +import { Icon, Dropdown, TagBadge } from 'UI' +import { applyIssueFilter, removeIssueFilter } from 'Duck/funnels'; +import cn from 'classnames'; +import stl from './issueFilter.css'; +import { List } from 'immutable'; + +function IssueFilter(props) { + const { filters, issueTypes, issueTypesMap } = props; + + const onChangeFilter = (e, { name, value }) => { + const errors = filters.toJS(); + errors.push(value); + props.applyIssueFilter({ filters: List(errors) }); + } + + return ( + <div className="flex items-start"> + <Dropdown + trigger={ + <div className={cn("py-2 px-3 bg-white rounded-full flex items-center text-sm mb-2", stl.filterBtn)}> + <Icon name="filter" size="12" color="teal" /> + <span className="ml-2 font-medium leading-none">Filter</span> + </div> + } + options={ issueTypes.filter(i => !filters.includes(i.value)) } + name="change" + icon={null} + onChange={onChangeFilter} + basic + scrolling + selectOnBlur={false} + /> + <div className="flex items-center ml-3 flex-wrap"> + {filters.map(err => ( + <TagBadge + className="mb-2" + key={ err } + hashed={false} + text={ issueTypesMap[err] } + onRemove={ () => props.removeIssueFilter(err) } + outline + /> + ))} + </div> + </div> + ) +} + +export default connect(state => ({ + filters: state.getIn(['funnels', 'issueFilters', 'filters']), + issueTypes: state.getIn(['funnels', 'issueTypes']).toJS(), + issueTypesMap: state.getIn(['funnels', 'issueTypesMap']), +}), { applyIssueFilter, removeIssueFilter })(IssueFilter) diff --git a/frontend/app/components/Funnels/IssueFilter/index.js b/frontend/app/components/Funnels/IssueFilter/index.js new file mode 100644 index 000000000..ac69d0f3e --- /dev/null +++ b/frontend/app/components/Funnels/IssueFilter/index.js @@ -0,0 +1 @@ +export { default } from './IssueFilter' \ No newline at end of file diff --git a/frontend/app/components/Funnels/IssueFilter/issueFilter.css b/frontend/app/components/Funnels/IssueFilter/issueFilter.css new file mode 100644 index 000000000..575c3d319 --- /dev/null +++ b/frontend/app/components/Funnels/IssueFilter/issueFilter.css @@ -0,0 +1,7 @@ +.filterBtn { + border: dashed 1px $teal !important; + color: $teal; + &:hover { + background-color: $active-blue; + } +} \ No newline at end of file diff --git a/frontend/app/components/Funnels/IssueItem/IssueGraph.js b/frontend/app/components/Funnels/IssueItem/IssueGraph.js new file mode 100644 index 000000000..9da602965 --- /dev/null +++ b/frontend/app/components/Funnels/IssueItem/IssueGraph.js @@ -0,0 +1,48 @@ +import React from 'react' +import { Popup } from 'UI' + +function IssueGraph({ issue }) { + return ( + <div className="flex rounded-sm" style={{ width: '600px' }}> + <Popup + trigger={ + <div style={{ width: issue.unaffectedSessionsPer + '%' }} className="relative"> + <div className="w-full relative rounded-tl-sm rounded-bl-sm" style={{ height: '18px', backgroundColor: 'rgba(217, 219, 238, 0.7)' }} /> + <div className="absolute ml-2 font-bold top-0 bottom-0 text-sm">{issue.unaffectedSessions}</div> + </div> + } + content={ `Unaffected sessions` } + size="tiny" + inverted + position="top center" + /> + <Popup + trigger={ + <div style={{ width: issue.affectedSessionsPer + '%'}} className="border-l relative"> + <div className="w-full relative" style={{ height: '18px', backgroundColor: 'rgba(238, 238, 238, 0.7)' }} /> + <div className="absolute ml-2 font-bold top-0 bottom-0 text-sm">{issue.affectedSessions}</div> + {/* <div className="absolute left-0 ml-1 text-xs">{issue.affectedSessionsPer}</div> */} + </div> + } + content={ `Affected sessions` } + size="tiny" + inverted + position="top center" + /> + <Popup + trigger={ + <div style={{ width: issue.lostConversionsPer + '%'}} className="border-l relative"> + <div className="w-full relative rounded-tr-sm rounded-br-sm" style={{ height: '18px', backgroundColor: 'rgba(204, 0, 0, 0.26)' }} /> + <div className="absolute ml-2 font-bold top-0 bottom-0 text-sm color-red">{issue.lostConversions}</div> + </div> + } + content={ `Conversion lost` } + size="tiny" + inverted + position="top center" + /> + </div> + ) +} + +export default IssueGraph diff --git a/frontend/app/components/Funnels/IssueItem/IssueItem.js b/frontend/app/components/Funnels/IssueItem/IssueItem.js new file mode 100644 index 000000000..ba5bdeef3 --- /dev/null +++ b/frontend/app/components/Funnels/IssueItem/IssueItem.js @@ -0,0 +1,79 @@ +import React from 'react' +import { BackLink, Icon, TextEllipsis } from 'UI' +import cn from 'classnames' +import IssueGraph from './IssueGraph' + +const Info = ({ label = '', color = 'red'}) => { + return ( + <div className="flex items-center ml-4"> + <div className="flex text-sm items-center color-gray-medium"> + <div className={ cn("w-2 h-2 rounded-full mr-2") } style={{ backgroundColor: color }} /> + <div>{ label }</div> + </div> + </div> + ) +} + +function IssueItem({ issue, inDetails = false, onClick = () => null, onBack = () => null }) { + return ( + <div className={cn('flex flex-col bg-white w-full rounded border relative', { 'cursor-pointer bg-hover' : !inDetails })} onClick={!inDetails ? onClick : () => null}> + {inDetails && ( + <BackLink onClick={onBack} className="absolute" style={{ left: '-50px', top: '8px' }} /> + )} + <div className="flex items-center px-6 py-4 relative"> + <div className="mr-3"> + <div + className="flex items-center justify-center flex-shrink-0 mr-3 relative" + > + <Icon name={issue.icon.icon} style={{ fill: issue.icon.color }} size="24" className="z-10 inset-0" /> + </div> + </div> + + {inDetails && ( + <div className="flex-1 overflow-hidden"> + <div className="text-lg font-medium mb-2 capitalize">{issue.title}</div> + <div className="text-xl whitespace-nowrap"> + <TextEllipsis text={issue.contextString} /> + </div> + </div> + )} + + {!inDetails && ( + <div className="flex-1 overflow-hidden"> + <div className="text-xl mb-2 capitalize">{issue.title}</div> + <div className="text-sm color-gray-medium whitespace-nowrap leading-none"> + <TextEllipsis text={issue.contextString} /> + </div> + </div> + )} + + <div className="text-center text-sm ml-10 flex-shrink-0"> + <div className="text-xl mb-2">{issue.affectedUsers}</div> + <div className="color-gray-medium leading-none">Affected Users</div> + </div> + + <div className="text-center text-sm ml-10 flex-shrink-0"> + <div className="text-xl mb-2 color-red">{issue.conversionImpact}<span className="text-sm ml-1">%</span></div> + <div className="color-gray-medium leading-none">Conversion Impact</div> + </div> + + <div className="text-center text-sm ml-10 flex-shrink-0"> + <div className="text-xl mb-2">{issue.lostConversions}</div> + <div className="color-gray-medium leading-none">Lost Conversions</div> + </div> + </div> + {inDetails && ( + <div className="flex items-center px-6 py-4 justify-between border-t"> + <IssueGraph issue={issue} /> + <div className="flex items-center"> + <Info label="Unaffected sessions" color="rgba(217, 219, 238, 0.7)" /> + <Info label="Affected sessions" color="rgba(238, 238, 238, 0.7)" /> + <Info label="Conversion Lost" color="rgba(204, 0, 0, 0.26)" /> + </div> + </div> + )} + </div> + ) +} + +export default IssueItem diff --git a/frontend/app/components/Funnels/IssueItem/index.js b/frontend/app/components/Funnels/IssueItem/index.js new file mode 100644 index 000000000..59c95e8f4 --- /dev/null +++ b/frontend/app/components/Funnels/IssueItem/index.js @@ -0,0 +1 @@ +export { default } from './IssueItem' \ No newline at end of file diff --git a/frontend/app/components/Funnels/IssuesEmptyMessage/IssuesEmptyMessage.js b/frontend/app/components/Funnels/IssuesEmptyMessage/IssuesEmptyMessage.js new file mode 100644 index 000000000..344aa3aed --- /dev/null +++ b/frontend/app/components/Funnels/IssuesEmptyMessage/IssuesEmptyMessage.js @@ -0,0 +1,26 @@ +import React from 'react' +import { Button } from 'UI' +import { addEvent } from 'Duck/funnelFilters' +import Event, { TYPES } from 'Types/filter/event'; +import { connect } from 'react-redux'; + +function IssuesEmptyMessage(props) { + const { children, show } = props; + const createHandler = () => { + props.addEvent(Event({ type: TYPES.LOCATION, key: TYPES.LOCATION } )) + props.onAddEvent(); + } + return (show ? ( + <div className="flex flex-col items-center"> + <div className="text-center my-6"> + <div className="text-3xl font-medium mb-4">See what's impacting conversions</div> + <div className="mb-4 text-xl">Add events to your funnel to identify potential issues that are causing conversion loss.</div> + <Button primary size="small" onClick={ createHandler }>+ ADD EVENTS</Button> + </div> + <img src="/img/funnel_intro.png" /> + </div> + ) : children + ) +} + +export default connect(null, { addEvent })(IssuesEmptyMessage) diff --git a/frontend/app/components/Funnels/IssuesEmptyMessage/index.js b/frontend/app/components/Funnels/IssuesEmptyMessage/index.js new file mode 100644 index 000000000..fccfd2545 --- /dev/null +++ b/frontend/app/components/Funnels/IssuesEmptyMessage/index.js @@ -0,0 +1 @@ +export { default } from './IssuesEmptyMessage' \ No newline at end of file diff --git a/frontend/app/components/Funnels/funnels.stories.js b/frontend/app/components/Funnels/funnels.stories.js new file mode 100644 index 000000000..67849e0fc --- /dev/null +++ b/frontend/app/components/Funnels/funnels.stories.js @@ -0,0 +1,56 @@ +import { storiesOf } from '@storybook/react'; +import { List } from 'immutable'; +import Funnel from 'Types/funnel' +import FunnelIssue from 'Types/funnelIssue' +import FunnelList from './FunnelList'; +import FunnelItem from './FunnelItem'; +import IssueItem from './IssueItem'; +import FunnelGraph from './FunnelGraph'; +import FunnelHeader from './FunnelHeader'; +import FunnelOverview from './FunnelOverview'; +import IssueFilter from './IssueFilter'; + +const funnel = Funnel({ + title: 'Sessions from france', + users: 308, + steps: 10, + sessionsCount: 200, + criticalIssues: 5, + missedConversions: 30 +}) + +const list = [funnel, funnel, funnel]; + +const funnelIssue = FunnelIssue({ + type: 'Error', + error: 'Unchecked runtime lasterror the message port closed before a response was received.', + affectedUsers: 132, + conversionImpact: 30, + lostConversions: 200, +}) + +storiesOf('Funnels', module) + .add('Funnel List', () => ( + <FunnelList list={list} /> + )) + .add('Funnel Item', () => ( + <FunnelItem funnel={funnel} /> + )) + .add('Funnel Header', () => ( + <FunnelHeader /> + )) + .add('Funnel Header', () => ( + <FunnelHeader funnel={funnel} /> + )) + .add('Issue Item', () => ( + <IssueItem issue={funnelIssue} /> + )) + .add('Funnel graph', () => ( + <FunnelGraph /> + )) + .add('Funnel Overview', () => ( + <FunnelOverview funnel={funnel} /> + )) + .add('Funnel IssueFilter', () => ( + <IssueFilter /> + )) diff --git a/frontend/app/components/Funnels/index.js b/frontend/app/components/Funnels/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/app/components/Header/AlertItem.js b/frontend/app/components/Header/AlertItem.js new file mode 100644 index 000000000..77702eeb2 --- /dev/null +++ b/frontend/app/components/Header/AlertItem.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { Icon } from 'UI'; +import styles from './alertItem.css'; + +const AlertItem = ({ alert, onDelete, onEdit }) => ( + <div className={ styles.alertItem }> + <div className={ styles.title }>{ alert.name }</div> + <div className={ styles.period }>{ alert.period }</div> + <div className={ styles.actions }> + <Icon name="edit" size="16" onClick={ () => onEdit(alert) } /> + <Icon name="trash" size="16" onClick={ () => onDelete(alert.id) } /> + </div> + </div> +); + +export default AlertItem; diff --git a/frontend/app/components/Header/Discover/Discover.js b/frontend/app/components/Header/Discover/Discover.js new file mode 100644 index 000000000..1f3cf8f80 --- /dev/null +++ b/frontend/app/components/Header/Discover/Discover.js @@ -0,0 +1,143 @@ +import { connect } from 'react-redux'; +import React from 'react'; +import withToggle from 'Components/hocs/withToggle'; +import stl from './discover.css'; +import FeatureItem from './FeatureItem'; +import { getOnboard } from 'Duck/dashboard'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; + +import { CircularProgressbar, buildStyles } from 'react-circular-progressbar'; +import { withRouter } from 'react-router'; + +const styles = { + // Rotation of path and trail, in number of turns (0-1) + rotation: 0, + // Whether to use rounded or flat corners on the ends - can use 'butt' or 'round' + strokeLinecap: 'butt', + + // Text size + textSize: '16px', + + // How long animation takes to go from one percentage to another, in seconds + pathTransitionDuration: 1, + + // Can specify path transition in more detail, or remove it entirely + // pathTransition: 'none', + + // Colors + pathColor: `#394EFF`, + // textColor: '#f88', + // trailColor: '#d6d6d6', + // backgroundColor: '#3e98c7', +}; + +@connect(state => ({ + boarding: state.getIn([ 'dashboard', 'boarding' ]), + boardingCompletion: state.getIn([ 'dashboard', 'boardingCompletion' ]), +}), { + getOnboard, +}) +@withToggle('display', 'toggleModal') +@withRouter +class Discover extends React.PureComponent { + componentWillMount() { + this.props.getOnboard(); + } + + componentDidMount() { + setTimeout(function() { + const { onComplete, boardingCompletion } = this.props; + if (typeof onComplete === 'function' && boardingCompletion >= 50) { + onComplete() + } + }.bind(this), 1000 * 60 * 2); + } + + onClickOutside = () => { + if (this.props.display) + this.props.toggleModal(); + } + + getHeaderText = (percentage) => { + if (percentage === 0 ) { + return 'Welcome!'; + } else if (percentage < 100) { + return 'Few more steps and you’re done!'; + } + return 'Good Job!'; + } + + onClick = task => { + if (task.URL) { + if (task.URL.includes(window.ENV.ORIGIN)) { + const { history } = this.props; + var path = new URL(task.URL).pathname + history.push(path) + } else { + window.open(task.URL, "_blank") + } + this.props.toggleModal(); + } + } + + render() { + const { display, toggleModal, boarding, boardingCompletion } = this.props; + + styles.pathColor = '#394EFF'; + if (boardingCompletion < 50) + styles.pathColor = '#FF0000'; + else if (boardingCompletion < 75) + styles.pathColor = '#FFA500'; + const _styles = buildStyles(styles); + + return ( + <OutsideClickDetectingDiv className={ stl.wrapper } onClickOutside={this.onClickOutside}> + <button className={ stl.button } onClick={ toggleModal }> + <div className={ stl.progressWrapper }> + <CircularProgressbar value={ boardingCompletion } styles={ _styles } strokeWidth={ 12 }/> + </div> + </button> + { display && + <div className={ stl.modal } > + <div className={ stl.tooltipArrow } /> + <div className={ stl.header }> + <div style={ { width: '50px', marginRight: '10px' }}> + <CircularProgressbar + strokeWidth={ 14 } + value={ boardingCompletion } + styles={ _styles } + /> + </div> + <div className={ stl.info }> + <div>{ this.getHeaderText(boardingCompletion) }</div> + <div> + { + boardingCompletion > 0 ? + `You have discovered ${ boardingCompletion }% of OpenReplay features!` : + 'Let us help you configure OpenReplay.' + } + </div> + </div> + </div> + + <div className={ stl.content }> + <h4>{ 'Discover more of OpenReplay' }</h4> + <div className={ stl.list }> + { boarding.map(task => ( + <FeatureItem + key={ task.task } + label={ task.task } + completed={ task.done } + onClick={task.URL && (() => this.onClick(task)) } + /> + ))} + </div> + </div> + </div> + } + </OutsideClickDetectingDiv> + ); + } +} + +export default Discover; diff --git a/frontend/app/components/Header/Discover/FeatureItem.js b/frontend/app/components/Header/Discover/FeatureItem.js new file mode 100644 index 000000000..a403fbeb9 --- /dev/null +++ b/frontend/app/components/Header/Discover/FeatureItem.js @@ -0,0 +1,26 @@ +import React from 'react'; +import { Checkbox } from 'UI'; +import cn from 'classnames'; +import stl from './featureItem.css'; + +const FeatureItem = ({ label, completed = false, subText, onClick }) => { + return ( + <div + className={ cn(stl.wrapper, { [stl.activeLink]: onClick, [stl.completed]: completed }) } + onClick={onClick && onClick} + > + <Checkbox + label={ label } + className={ cn(stl.checkbox, completed ? stl.active : '') } + name="strict" + checked={ completed } + readOnly={ true } + /> + { subText && + <div className={ stl.subText }>{ subText }</div> + } + </div> + ); +}; + +export default FeatureItem; diff --git a/frontend/app/components/Header/Discover/discover.css b/frontend/app/components/Header/Discover/discover.css new file mode 100644 index 000000000..1abc8c835 --- /dev/null +++ b/frontend/app/components/Header/Discover/discover.css @@ -0,0 +1,91 @@ +.wrapper { + position: relative; +} + +.button { + position: relative; + cursor: pointer; + display: flex; + align-items: center; + padding: 0 15px; + height: 50px; + transition: all 0.3s; + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + + &[data-active=true] { + background-color: $gray-lightest; + } +} + + +.modal { + min-width: 350px; + border-radius: 5px; + background-color: white; + box-shadow: 0 2px 10px 0 $gray-light; + position: absolute; + right: -40px; + top: 65px; + + & .tooltipArrow { + width: 50px; + height: 25px; + position: absolute; + bottom: 100%; + right: 16px; + transform: translateX(-50%); + overflow: hidden; + + &::after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + background: white; + transform: translateX(-50%) translateY(50%) rotate(45deg); + bottom: 0; + left: 50%; + box-shadow: 2px 2px 6px 0px rgba(0,0,0,0.6); + } + } + + & .header { + padding: 10px 15px; + font-weight: 500; + display: flex; + align-items: center; + + & .info { + & > div { + &:first-child { + font-style: italic; + font-weight: 400; + } + &:last-child { + font-size: 12px; + font-weight: 300; + } + } + } + } +} + +.content { + & h4 { + border-bottom: solid thin $gray-light; + padding: 10px 20px; + } + + & .list { + padding: 20px; + padding-top: 0; + } +} + +.progressWrapper { + width: 25px; +} \ No newline at end of file diff --git a/frontend/app/components/Header/Discover/featureItem.css b/frontend/app/components/Header/Discover/featureItem.css new file mode 100644 index 000000000..0c0d54b9c --- /dev/null +++ b/frontend/app/components/Header/Discover/featureItem.css @@ -0,0 +1,46 @@ +.wrapper { + padding: 10px 0; +} + +.checkbox { + font-weight: 500; + pointer-events: none; + & label { + &:before { + border-radius: 50% !important; + background-color: $gray-light !important; + } + } + &.active { + text-decoration: line-through !important; + font-weight: 300; + & label { + &:before { + display: none !important; + } + } + } +} + +.subText { + margin-left: 27px; + color: $gray-medium; + font-size: 12px; + font-weight: 300; +} + +.activeLink { + cursor: pointer; + pointer-events: default; + & label { + color: #000000 !important; + text-decoration: underline; + } +} + +.completed { + pointer-events: none; + & label { + text-decoration: none !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Header/Discover/index.js b/frontend/app/components/Header/Discover/index.js new file mode 100644 index 000000000..c75729235 --- /dev/null +++ b/frontend/app/components/Header/Discover/index.js @@ -0,0 +1 @@ +export { default } from './Discover'; \ No newline at end of file diff --git a/frontend/app/components/Header/Header.js b/frontend/app/components/Header/Header.js new file mode 100644 index 000000000..6e7a6601f --- /dev/null +++ b/frontend/app/components/Header/Header.js @@ -0,0 +1,157 @@ +import React, { useEffect, useState } from 'react'; +import { connect } from 'react-redux'; +import { NavLink, withRouter } from 'react-router-dom'; +import cn from 'classnames'; +import { + sessions, + client, + errors, + dashboard, + withSiteId, + CLIENT_DEFAULT_TAB, + isRoute, +} from 'App/routes'; +import { logout } from 'Duck/user'; +import { Icon, Popup } from 'UI'; +import SiteDropdown from './SiteDropdown'; +import styles from './header.css'; +import Discover from './Discover/Discover'; +import OnboardingExplore from './OnboardingExplore/OnboardingExplore' +import Announcements from '../Announcements'; +import Notifications from '../Alerts/Notifications'; +import { init as initSite, fetchList as fetchSiteList } from 'Duck/site'; + +import ErrorGenPanel from 'App/dev/components'; +import ErrorsBadge from 'Shared/ErrorsBadge'; +import Alerts from '../Alerts/Alerts'; +import EmailVerificationMessage from '../shared/EmailVerificationMessage/EmailVerificationMessage'; + +const DASHBOARD_PATH = dashboard(); +const SESSIONS_PATH = sessions(); +const ERRORS_PATH = errors(); +const CLIENT_PATH = client(CLIENT_DEFAULT_TAB); +const AUTOREFRESH_INTERVAL = 30 * 1000; + +let interval = null; + +const Header = (props) => { + const { + sites, location, account, + onLogoutClick, siteId, + boardingCompletion = 100, fetchSiteList, showAlerts = false + } = props; + + const name = account.get('name').split(" ")[0]; + const [hideDiscover, setHideDiscover] = useState(false) + let activeSite = null; + + useEffect(() => { + activeSite = sites.find(s => s.id == siteId); + props.initSite(activeSite); + }, [sites]) + + const showTrackingModal = ( + isRoute(SESSIONS_PATH, location.pathname) || + isRoute(ERRORS_PATH, location.pathname) + ) && activeSite && !activeSite.recorded; + + useEffect(() => { + if(showTrackingModal) { + interval = setInterval(() => { + fetchSiteList() + }, AUTOREFRESH_INTERVAL); + } else if (interval){ + clearInterval(interval); + } + }, [showTrackingModal]) + + useEffect(() => { + fetchSiteList() + }, []) + + return ( + <div className={ cn(styles.header, showTrackingModal ? styles.placeOnTop : '') }> + <NavLink to={ withSiteId(SESSIONS_PATH, siteId) }> + <div className="relative"> + <div className={ styles.logo } /> + <div className="absolute bottom-0" style={{ fontSize: '7px', right: '5px' }}>v{window.ENV.VERSION}</div> + </div> + </NavLink> + <SiteDropdown /> + <div className={ styles.divider } /> + + <NavLink + to={ withSiteId(SESSIONS_PATH, siteId) } + className={ styles.nav } + activeClassName={ styles.active } + > + { 'Sessions' } + </NavLink> + <NavLink + to={ withSiteId(ERRORS_PATH, siteId) } + className={ styles.nav } + activeClassName={ styles.active } + > + <ErrorsBadge /> + { 'Errors' } + </NavLink> + <NavLink + to={ withSiteId(DASHBOARD_PATH, siteId) } + className={ styles.nav } + activeClassName={ styles.active } + > + <span>{ 'Metrics' }</span> + </NavLink> + <div className={ styles.right }> + { !account.verifiedEmail && <EmailVerificationMessage email={account.email} /> } + <Announcements /> + <div className={ styles.divider } /> + + { (boardingCompletion < 100 && !hideDiscover) && ( + <React.Fragment> + <OnboardingExplore onComplete={() => setHideDiscover(true)} /> + <div className={ styles.divider } /> + </React.Fragment> + )} + + <Notifications /> + <div className={ styles.divider } /> + <Popup + trigger={ + <NavLink to={ CLIENT_PATH } className={ styles.headerIcon }><Icon name="cog" size="20" /></NavLink> + } + content={ `Preferences` } + size="tiny" + inverted + position="top center" + /> + + <div className={ styles.divider } /> + <div className={ styles.userDetails }> + <div className="flex items-center"> + <div className="mr-5">{ name }</div> + <Icon color="gray-medium" name="ellipsis-v" size="24" /> + </div> + + <ul> + <li><button onClick={ onLogoutClick }>{ 'Logout' }</button></li> + </ul> + </div> + </div> + { <ErrorGenPanel/> } + {showAlerts && <Alerts />} + </div> + ); +}; + +export default withRouter(connect( + state => ({ + account: state.getIn([ 'user', 'account' ]), + appearance: state.getIn([ 'user', 'account', 'appearance' ]), + siteId: state.getIn([ 'user', 'siteId' ]), + sites: state.getIn([ 'site', 'list' ]), + showAlerts: state.getIn([ 'dashboard', 'showAlerts' ]), + boardingCompletion: state.getIn([ 'dashboard', 'boardingCompletion' ]) + }), + { onLogoutClick: logout, initSite, fetchSiteList }, +)(Header)); diff --git a/frontend/app/components/Header/NotificationItem.js b/frontend/app/components/Header/NotificationItem.js new file mode 100644 index 000000000..54da02705 --- /dev/null +++ b/frontend/app/components/Header/NotificationItem.js @@ -0,0 +1,20 @@ +import { checkForRecent } from 'App/dateRange'; + +import styles from './notificationItem.css'; + +const NotificationItem = ({ + notification: { + notificationId, createdAt, name, text, viewed, + }, + onClick, +}) => ( + <div className={ styles.wrapper } data-viewed={ viewed } onClick={ () => (!viewed ? onClick(notificationId) : null) }> + <div className={ styles.time }>{ checkForRecent(createdAt, 'LLL dd, yyyy, hh:mm a') }</div> + <div className={ styles.title }>{ name }</div> + { text && <div className={ styles.details }>{ text }</div> } + </div> +); + +NotificationItem.displayName = 'NotificationItem'; + +export default NotificationItem; diff --git a/frontend/app/components/Header/OnboardingExplore/FeatureItem.js b/frontend/app/components/Header/OnboardingExplore/FeatureItem.js new file mode 100644 index 000000000..720014f55 --- /dev/null +++ b/frontend/app/components/Header/OnboardingExplore/FeatureItem.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { Checkbox, Icon } from 'UI'; +import cn from 'classnames'; +import stl from './featureItem.css'; + +const FeatureItem = ({ label, completed = false, subText, onClick }) => { + return ( + <div + className={ cn(stl.wrapper, { [stl.activeLink]: onClick, [stl.completed]: !completed }) } + onClick={onClick && onClick} + > + <div className={ cn("h-6 w-6 flex-shrink-0 rounded-full flex items-center justify-center", { 'bg-white' : !completed, 'bg-teal' : completed })}> + { completed && <Icon name="check" size="16" color="white" /> } + </div> + <div className="ml-3">{label}</div> + </div> + ); +}; + +export default FeatureItem; diff --git a/frontend/app/components/Header/OnboardingExplore/OnboardingExplore.js b/frontend/app/components/Header/OnboardingExplore/OnboardingExplore.js new file mode 100644 index 000000000..a6893fc17 --- /dev/null +++ b/frontend/app/components/Header/OnboardingExplore/OnboardingExplore.js @@ -0,0 +1,146 @@ +import { connect } from 'react-redux'; +import React from 'react'; +import withToggle from 'Components/hocs/withToggle'; +import stl from './onboardingExplore.css'; +import FeatureItem from './FeatureItem'; +import { getOnboard } from 'Duck/dashboard'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; + +import { OB_TABS, onboarding as onboardingRoute } from 'App/routes' +import * as routes from '../../../routes' + +const withSiteId = routes.withSiteId; + +import { CircularProgressbar, buildStyles } from 'react-circular-progressbar'; +import { withRouter } from 'react-router'; + +const styles = { + // Rotation of path and trail, in number of turns (0-1) + rotation: 0, + // Whether to use rounded or flat corners on the ends - can use 'butt' or 'round' + strokeLinecap: 'butt', + + // Text size + textSize: '16px', + + // How long animation takes to go from one percentage to another, in seconds + pathTransitionDuration: 1, + + // Can specify path transition in more detail, or remove it entirely + // pathTransition: 'none', + + // Colors + pathColor: `#394EFF`, + // textColor: '#f88', + // trailColor: '#d6d6d6', + // backgroundColor: '#3e98c7', +}; + +@connect(state => ({ + siteId: state.getIn([ 'user', 'siteId' ]), + boarding: state.getIn([ 'dashboard', 'boarding' ]), + boardingCompletion: state.getIn([ 'dashboard', 'boardingCompletion' ]), +}), { + getOnboard, +}) +@withToggle('display', 'toggleModal') +@withRouter +class OnboardingExplore extends React.PureComponent { + componentWillMount() { + this.props.getOnboard(); + } + + componentDidMount() { + setTimeout(function() { + const { onComplete, boardingCompletion } = this.props; + if (typeof onComplete === 'function' && boardingCompletion >= 50) { + onComplete() + } + }.bind(this), 1000 * 60 * 2); + } + + onClickOutside = () => { + if (this.props.display) + this.props.toggleModal(); + } + + getHeaderText = (percentage) => { + if (percentage === 0 ) { + return 'Welcome!'; + } else if (percentage < 100) { + return 'Few more steps and you’re done!'; + } + return 'Good Job!'; + } + + getOnboardingTab = (task) => { + if (task === 'Install OpenReplay') + return OB_TABS.INSTALLING; + if (task === 'Identify Users') + return OB_TABS.IDENTIFY_USERS; + if (task === 'Invite Team Members') + return OB_TABS.MANAGE_USERS; + if (task === 'Integrations') + return OB_TABS.INTEGRATIONS; + } + onClick = task => { + const { siteId, history } = this.props; + const tab = this.getOnboardingTab(task.task) + history.push(withSiteId(onboardingRoute(tab), siteId)); + + // if (task.URL) { + // if (task.URL.includes(window.ENV.ORIGIN)) { + // const { history } = props; + // var path = new URL(task.URL).pathname + // history.push(path) + // } else { + // window.open(task.URL, "_blank") + // } + // this.props.toggleModal(); + // } + } + + render() { + const { display, toggleModal, boarding, boardingCompletion } = this.props; + + styles.pathColor = '#394EFF'; + if (boardingCompletion < 50) + styles.pathColor = '#FF0000'; + else if (boardingCompletion < 75) + styles.pathColor = '#FFA500'; + const _styles = buildStyles(styles); + + return ( + <OutsideClickDetectingDiv className={ stl.wrapper } onClickOutside={this.onClickOutside}> + <button className={ stl.button } onClick={ toggleModal }> + <div className={ stl.progressWrapper }> + <CircularProgressbar value={ boardingCompletion } styles={ _styles } strokeWidth={ 12 }/> + </div> + </button> + { display && + <div className={ stl.modal } > + <div className={ stl.tooltipArrow } /> + <div className={ stl.header }> + Follow the steps below to complete this project setup and make the best out of OpenReplay. + </div> + + <div className={ stl.content }> + <div className={ stl.list }> + { boarding.map(task => ( + <FeatureItem + key={ task.task } + label={ task.task } + completed={ task.done } + onClick={task.URL && (() => this.onClick(task)) } + /> + ))} + </div> + </div> + </div> + } + </OutsideClickDetectingDiv> + ); + } +} + +export default OnboardingExplore; diff --git a/frontend/app/components/Header/OnboardingExplore/featureItem.css b/frontend/app/components/Header/OnboardingExplore/featureItem.css new file mode 100644 index 000000000..e0b005408 --- /dev/null +++ b/frontend/app/components/Header/OnboardingExplore/featureItem.css @@ -0,0 +1,48 @@ +.wrapper { + padding: 10px 0; + display: flex; + align-items: center; +} + +.checkbox { + font-weight: 500; + pointer-events: none; + & label { + &:before { + border-radius: 50% !important; + background-color: $gray-light !important; + } + } + &.active { + text-decoration: line-through !important; + font-weight: 300; + & label { + &:before { + display: none !important; + } + } + } +} + +.subText { + margin-left: 27px; + color: $gray-medium; + font-size: 12px; + font-weight: 300; +} + +.activeLink { + cursor: pointer; + pointer-events: default; + & label { + color: #000000 !important; + text-decoration: underline; + } +} + +.completed { + pointer-events: none; + & label { + text-decoration: none !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Header/OnboardingExplore/index.js b/frontend/app/components/Header/OnboardingExplore/index.js new file mode 100644 index 000000000..df2d8e791 --- /dev/null +++ b/frontend/app/components/Header/OnboardingExplore/index.js @@ -0,0 +1 @@ +export { default } from './OnboardingExplore'; \ No newline at end of file diff --git a/frontend/app/components/Header/OnboardingExplore/onboardingExplore.css b/frontend/app/components/Header/OnboardingExplore/onboardingExplore.css new file mode 100644 index 000000000..d246bd4a0 --- /dev/null +++ b/frontend/app/components/Header/OnboardingExplore/onboardingExplore.css @@ -0,0 +1,91 @@ +.wrapper { + position: relative; +} + +.button { + position: relative; + cursor: pointer; + display: flex; + align-items: center; + padding: 0 15px; + height: 50px; + transition: all 0.3s; + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + + &[data-active=true] { + background-color: $gray-lightest; + } +} + + +.modal { + min-width: 280px; + border-radius: 5px; + background-color: white; + box-shadow: 0 2px 10px 0 $gray-light; + position: absolute; + right: -40px; + top: 65px; + + & .tooltipArrow { + width: 50px; + height: 25px; + position: absolute; + bottom: 100%; + right: 16px; + transform: translateX(-50%); + overflow: hidden; + + &::after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + background: white; + transform: translateX(-50%) translateY(50%) rotate(45deg); + bottom: 0; + left: 50%; + box-shadow: 2px 2px 6px 0px rgba(0,0,0,0.6); + } + } + + & .header { + padding: 10px 15px; + font-weight: 500; + display: flex; + align-items: center; + + & .info { + & > div { + &:first-child { + font-style: italic; + font-weight: 400; + } + &:last-child { + font-size: 12px; + font-weight: 300; + } + } + } + } +} + +.content { + & h4 { + border-bottom: solid thin $gray-light; + padding: 10px 20px; + } + + & .list { + padding: 20px; + padding-top: 0; + } +} + +.progressWrapper { + width: 25px; +} \ No newline at end of file diff --git a/frontend/app/components/Header/SiteDropdown.js b/frontend/app/components/Header/SiteDropdown.js new file mode 100644 index 000000000..db66db530 --- /dev/null +++ b/frontend/app/components/Header/SiteDropdown.js @@ -0,0 +1,87 @@ +import { connect } from 'react-redux'; +import { setSiteId } from 'Duck/user'; +import { withRouter } from 'react-router-dom'; +import { hasSiteId, siteChangeAvaliable } from 'App/routes'; +import { STATUS_COLOR_MAP, GREEN } from 'Types/site'; +import { Icon, SlideModal } from 'UI'; +import { pushNewSite } from 'Duck/user' +import styles from './siteDropdown.css'; +import cn from 'classnames'; +import NewSiteForm from '../Client/Sites/NewSiteForm'; + +@withRouter +@connect(state => ({ + sites: state.getIn([ 'site', 'list' ]), + siteId: state.getIn([ 'user', 'siteId' ]), +}), { + setSiteId, + pushNewSite +}) +export default class SiteDropdown extends React.PureComponent { + state = { showProductModal: false } + + closeModal = (e, newSite) => { + this.setState({ showProductModal: false }) + if (newSite) { + this.props.pushNewSite(newSite) + this.props.setSiteId(newSite.id) + } + }; + + render() { + const { sites, siteId, location: { pathname } } = this.props; + const { showProductModal } = this.state; + const activeSite = sites.find(s => s.id == siteId); + const disabled = !siteChangeAvaliable(pathname); + const showCurrent = hasSiteId(pathname) || siteChangeAvaliable(pathname); + return ( + <div className={ styles.wrapper }> + { + showCurrent ? + <div className={ activeSite && activeSite.status === GREEN ? styles.statusGreenIcon : styles.statusRedIcon }></div> : + <Icon name="window-alt" size="14" marginRight="10" /> + } + <div className={ styles.currentSite }>{ showCurrent && activeSite ? activeSite.host : 'All Projects' }</div> + <Icon className={ styles.drodownIcon } color="gray-light" name="chevron-down" size="16" /> + <div className={styles.menu}> + <ul data-can-disable={ disabled }> + { !showCurrent && <li>{ 'Does not require domain selection.' }</li>} + { + sites.map(site => ( + <li key={ site.id } onClick={ () => this.props.setSiteId(site.id) }> + <Icon + name="circle" + size="8" + marginRight="10" + color={ STATUS_COLOR_MAP[ site.status ] } + /> + { site.host } + </li> + )) + } + </ul> + <div + className={cn(styles.btnNew, 'flex items-center justify-center py-3 cursor-pointer')} + onClick={() => this.setState({showProductModal: true})} + > + <Icon + name="plus" + size="12" + marginRight="5" + color="teal" + /> + <span className="color-teal">Add New Project</span> + </div> + </div> + + <SlideModal + title="New Project" + size="small" + isDisplayed={ showProductModal } + content={ <NewSiteForm onClose={ this.closeModal } /> } + onClose={ this.closeModal } + /> + </div> + ); + } +} diff --git a/frontend/app/components/Header/alertItem.css b/frontend/app/components/Header/alertItem.css new file mode 100644 index 000000000..eae7ad108 --- /dev/null +++ b/frontend/app/components/Header/alertItem.css @@ -0,0 +1,31 @@ +.alertItem { + padding: 10px 20px; + border-bottom: solid thin $gray-light; + position: relative; + + & .title { + font-size: 16px; + font-weight: 500; + margin-bottom: 5px; + } + + & .period { + color: $gray-medium; + font-size: 12px; + } + + & .actions { + position: absolute; + display: flex; + align-items: center; + right: 20px; + top: 0; + bottom: 0; + + & > span { + margin-left: 12px; + cursor: pointer; + fill: $gray-medium; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/Header/alertList.css b/frontend/app/components/Header/alertList.css new file mode 100644 index 000000000..7663e4749 --- /dev/null +++ b/frontend/app/components/Header/alertList.css @@ -0,0 +1,15 @@ +.detailContent { + width: 400px; + padding: 20px; + + background-color: rgba(242, 242, 242, 1); + position: absolute; + top: 0; + bottom: 0; + overflow-y: auto; + + & .title { + font-size: 20px; + margin-bottom: 25px; + } +} \ No newline at end of file diff --git a/frontend/app/components/Header/components/index.js b/frontend/app/components/Header/components/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/app/components/Header/header.css b/frontend/app/components/Header/header.css new file mode 100644 index 000000000..427f95e18 --- /dev/null +++ b/frontend/app/components/Header/header.css @@ -0,0 +1,164 @@ +@import "icons.css"; +@import "zindex.css"; + +$height: 50px; + +.header { + position: fixed; + width: 100%; + display: flex; + justify-content: space-between; + border-bottom: solid thin $gray-light; + padding: 0 15px; + background: $white; + z-index: $header; +} + +.nav { + position: relative; + margin: 0 15px; + padding: 0 10px; + height: $height; + line-height: $height; + font-size: 16px; + font-weight: 500; + color: $gray-darkest; + text-transform: uppercase; + white-space: nowrap; + &:hover, &.active { + color: $teal; + border-bottom: 2px solid $teal; + } + position: relative; +} + +.logo { + background-image: svg-load('logo-small.svg'); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + height: $height; + width: 30px; + margin-right: 15px; +} + +.right { + margin-left: auto; + position: relative; + cursor: default; + display: flex; + + & > .menuItem { + height: $height; + width: 50px; + + display: flex; + align-items: center; + justify-content: center; + border-left: solid thin $gray-light; + + position: relative; + + & .dropdown { + position: absolute; + right: 0; + top: $height; + } + } +} + +.userDetails { + display: flex; + align-items: center; + justify-content: flex-end; + position: relative; + padding: 0 5px 0 15px; + transition: all 0.2s; + min-width: 100px; + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + & ul { + display: block; + } + } + & ul { + display: none; + position: absolute; + list-style: none; + right: -15px; + top: 50px; + left: -1px; + background: $white; + z-index: 1; + } + & li { + border: 1px solid $gray-light; + border-top: none; + &:first-child { + border-top: 1px solid $gray-light; + } + } + & a, & button { + color: $gray-darkest; + display: block; + cursor: pointer; + width: 100%; + padding: 10px 15px; + text-align: left; + font-size: 14px; + &:hover { + background-color: $gray-lightest; + } + } +} + +.userIcon { + @mixin icon user-circle, $gray-dark; + width: 20px; + height: 20px; + margin-right: 10px; +} + +.headerIcon { + position: relative; + cursor: pointer; + display: flex; + align-items: center; + padding: 0 15px; + height: 50px; + transition: all 0.3s; + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + + &[data-active=true] { + background-color: $gray-lightest; + } +} + +.divider { + width: 1px; + background-color: $gray-light; +} + +.placeOnTop { + z-index: 9999; +} + +.newBadge { + position: absolute; + height: 14px; + width: 28px; + background-image: linear-gradient(40deg, #6051FF 0%, #FF693B 100%); + border-radius: 3px; + font-size: 9px; + line-height: 15px; + color: white; + text-align: center; + right: -22px; + top: 10px; +} \ No newline at end of file diff --git a/frontend/app/components/Header/notificationItem.css b/frontend/app/components/Header/notificationItem.css new file mode 100644 index 000000000..4c1a6aeb3 --- /dev/null +++ b/frontend/app/components/Header/notificationItem.css @@ -0,0 +1,18 @@ +.wrapper { + padding: 8px 15px; + border-bottom: solid thin $gray-light; + + &[data-viewed=false] { + background-color: $active-blue; + cursor: pointer; + } + + & .time { + color: $gray-medium; + font-size: 10px; + } + + & .title { + font-weight: 500; + } +} \ No newline at end of file diff --git a/frontend/app/components/Header/notifications.css b/frontend/app/components/Header/notifications.css new file mode 100644 index 000000000..e026229d9 --- /dev/null +++ b/frontend/app/components/Header/notifications.css @@ -0,0 +1,135 @@ +.wrapper { + position: relative; +} + +.button { + position: relative; + cursor: pointer; + display: flex; + align-items: center; + padding: 0 15px; + height: 50px; + transition: all 0.3s; + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + + &[data-active=true] { + background-color: $gray-lightest; + } +} + +.counter { + position: absolute; + top: 8px; + left: 24px; + background-color: red; + color: white; + font-size: 9px; + font-weight: 300; + min-width: 16px; + height: 16px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + padding: 3px; +} + +.list { + max-height: 500px; + overflow-y: auto; +} + +.dropdown { + min-width: 300px; + border-radius: 5px; + background-color: white; + box-shadow: 0 2px 10px 0 $gray-light; + position: absolute; + right: -40px; + top: 65px; + + & .tooltipArrow { + width: 50px; + height: 25px; + position: absolute; + bottom: 100%; + right: 15px; + transform: translateX(-50%); + overflow: hidden; + + &::after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + background: white; + transform: translateX(-50%) translateY(50%) rotate(45deg); + bottom: 0; + left: 50%; + box-shadow: 2px 2px 6px 0px rgba(0,0,0,0.6); + } + } + + & .header { + padding: 10px 15px; + border-bottom: solid thin $gray-light; + font-weight: 500; + box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.1); + + display: flex; + align-items: center; + justify-content: space-between; + + & > div:first-child { + font-size: 16px; + } + + & .closeButton { + cursor: pointer; + } + + & .right { + display: flex; + align-items: center; + } + } + + & .content { + max-height: 300px; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 4px; + margin-right: 10px; + } + + & .emptyBox { + min-height: 70px; + display: flex; + align-items: center; + justify-content: center; + color: $gray-medium; + } + } + + & .footer { + display: flex; + align-items: center; + justify-content: center; + background-color: white; + height: 40px; + + border-top: solid thin $gray-light; + box-shadow: 0 -1px 10px 0 rgba(0, 0, 0, 0.05); + color: $teal; + cursor: pointer; + + & span:last-child { + line-height: 1px; + } + } +} diff --git a/frontend/app/components/Header/siteDropdown.css b/frontend/app/components/Header/siteDropdown.css new file mode 100644 index 000000000..cfe43ff06 --- /dev/null +++ b/frontend/app/components/Header/siteDropdown.css @@ -0,0 +1,120 @@ +.wrapper { + display: flex; + align-items: center; + border-left: solid thin $gray-light !important; + padding: 10px 10px; + min-width: 180px; + justify-content: flex-start; + position: relative; + user-select: none; + + &:hover { + background-color: $gray-lightest; + & .drodownIcon { + transform: rotate(180deg); + transition: all 0.2s; + } + & .menu { + display: block; + } + } + + & .drodownIcon { + transition: all 0.4s; + margin: 0; + margin-left: auto; + } + + & [data-can-disable=true] { + & > li { + &:first-child { + pointer-events: none; + } + &:not(:first-child) { + opacity: 0.3; + pointer-events: none; + } + } + } + & .menu { + display: none; + position: absolute; + top: 50px; + left: -1px; + background-color: white; + min-width: 200px; + z-index: 2; + border: 1px solid $gray-light; + } + + & ul { + margin: 0; + max-height: 300px; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 2px; + } + + & li { + display: flex; + align-items: center; + cursor: pointer; + list-style-type: none; + border-bottom: 1px solid $gray-light; + border-top: none; + padding: 10px 15px; + transition: all 0.2s; + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + &:first-child { + border-top: 1px solid $gray-light; + } + } + } +} + +.headerSelect { + border: none !important; + display: flex !important; + align-items: center; + border-radius: 0 !important; +} + +.currentSite { + max-width: 130px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.statusGreenIcon { + display: block; + margin: 2px 10px 0 5px; + background-image: svg-load(signal-green.svg, fill=#CCC); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + width: 11px; + height: 22px; +} + +.statusRedIcon { + display: block; + margin: 2px 10px 0 5px; + background-image: svg-load(signal-red.svg, fill=#CCC); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + width: 11px; + height: 22px; +} + +.btnNew { + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } +} \ No newline at end of file diff --git a/frontend/app/components/InfoModal/InfoModal.js b/frontend/app/components/InfoModal/InfoModal.js new file mode 100644 index 000000000..cebfcb222 --- /dev/null +++ b/frontend/app/components/InfoModal/InfoModal.js @@ -0,0 +1,19 @@ +import { connect } from 'react-redux'; +import { Modal } from 'UI'; + +@connect(state => ({ + open: false, +})) +export default class InfoModal extends React.PureComponent { + render() { + return ( + <Modal + open={ this.props.open } + size="small" + > + <Modal.Content> + </Modal.Content> + </Modal> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Login/Login.js b/frontend/app/components/Login/Login.js new file mode 100644 index 000000000..81bc8109a --- /dev/null +++ b/frontend/app/components/Login/Login.js @@ -0,0 +1,133 @@ +import { connect } from 'react-redux'; +import withPageTitle from 'HOCs/withPageTitle'; +import { Icon, Loader, Button, Link } from 'UI'; +import { login } from 'Duck/user'; +import { forgotPassword, signup } from 'App/routes'; +import ReCAPTCHA from 'react-google-recaptcha'; +import stl from './login.css'; +import cn from 'classnames'; + +const FORGOT_PASSWORD = forgotPassword(); +const SIGNUP_ROUTE = signup(); +const recaptchaRef = React.createRef(); + +@connect( + state => ({ + errors: state.getIn([ 'user', 'loginRequest', 'errors' ]), + loading: state.getIn([ 'user', 'loginRequest', 'loading' ]), + }), + { login, }, +) +@withPageTitle('Login - OpenReplay') +export default class Login extends React.Component { + state = { + email: '', + password: '', + }; + + handleSubmit = (token) => { + const { email, password } = this.state; + this.props.login({ email: email.trim(), password, 'g-recaptcha-response': token }).then(() => { + const { errors } = this.props; + }) + } + + onSubmit = (e) => { + e.preventDefault(); + if (window.ENV.CAPTCHA_ENABLED && recaptchaRef.current) { + recaptchaRef.current.execute(); + } else if (!window.ENV.CAPTCHA_ENABLED) { + this.handleSubmit(); + } + } + + write = ({ target: { value, name } }) => this.setState({ [ name ]: value }) + + render() { + const { errors, loading } = this.props; + return ( + <div className="flex" style={{ height: '100vh'}}> + <div className={cn("w-6/12", stl.left)}> + <div className="px-6 pt-10"> + <img src="/logo-white.svg" /> + </div> + <div className="color-white text-lg flex items-center"> + <div className="flex items-center justify-center w-full" style={{ height: 'calc(100vh - 130px)'}}> + <div className="text-4xl">Welcome Back!</div> + </div> + </div> + </div> + <div className="w-6/12 flex items-center justify-center"> + <div className=""> + <form onSubmit={ this.onSubmit }> + <div className="mb-8"> + <h2 className="text-center text-3xl mb-6">Login to OpenReplay</h2> + <div className="text-center text-xl">Don't have an a Account? <span className="link"><Link to={ SIGNUP_ROUTE }>Sign up</Link></span></div> + </div> + <Loader loading={ loading }> + { window.ENV.CAPTCHA_ENABLED && ( + <ReCAPTCHA + ref={ recaptchaRef } + size="invisible" + sitekey={ window.ENV.CAPTCHA_SITE_KEY } + onChange={ token => this.handleSubmit(token) } + /> + )} + <div> + <div className="mb-6"> + <label>Email</label> + <div className={ stl.inputWithIcon }> + <i className={ stl.inputIconUser } /> + <input + autoFocus={true} + autoComplete="username" + type="text" + placeholder="Email" + name="email" + onChange={ this.write } + className={ stl.email } + required="true" + /> + </div> + </div> + <div className="mb-6"> + <label className="mb-2">Password</label> + <div className={ stl.inputWithIcon }> + <i className={ stl.inputIconPassword } /> + <input + autoComplete="current-password" + type="password" + placeholder="Password" + name="password" + onChange={ this.write } + className={ stl.password } + required="true" + /> + </div> + </div> + </div> + </Loader> + { errors && + <div className={ stl.errors }> + { errors.map(error => ( + <div className={stl.errorItem}> + <Icon name="info" color="red" size="20"/> + <span className="color-red ml-2">{ error }<br /></span> + </div> + )) } + </div> + } + <div className={ stl.formFooter }> + <Button type="submit" primary >{ 'Login' }</Button> + + <div className={ cn(stl.links, 'text-lg') }> + <Link to={ FORGOT_PASSWORD }>{'Forgot your password?'}</Link> + </div> + </div> + </form> + </div> + </div> + </div> + ); + } +} diff --git a/frontend/app/components/Login/login.css b/frontend/app/components/Login/login.css new file mode 100644 index 000000000..4ab843f18 --- /dev/null +++ b/frontend/app/components/Login/login.css @@ -0,0 +1,147 @@ +@import "icons.css"; +.form { + /* position: absolute; */ + /* top: 50%; */ + /* margin-top: -300px; */ + /* width: 520px; */ + /* left: 50%; */ + /* margin-left: -260px; */ + + & form { + padding: 10px 0; + border: solid 2px $gray-light; + border-radius: 2px; + background-color: white; + } + & h2 { + text-align: center; + font-size: 20px; + color: #555555; + margin: 35px 0; + font-weight: 500; + } +} + +.formFooter { + text-align: center; + padding: 15px 0; +} + +.links { + display: flex; + align-items: center; + justify-content: center; + padding: 10px 0; + margin-top: 20px; + + & .divider { + width: 1px; + height: 12px; + background-color: $gray-medium; + margin: 0 5px; + } +} + +.logo { + background-image: svg-load('logo.svg'); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + height: 40px; + margin-bottom: 20px; +} + + +.email, .password { + display: block; + margin: 10px auto; + width: 100%; + height: 45px; + line-height: 45px; + border: $gray-light solid 1px; + border-radius: 3px; + font-size: 14px; + padding: 0 10px; + transition: all 0.2s; + + &::placeholder { + color: #AAA; + } + + &:focus { + border-color: $teal; + transition: all 0.2s; + } +} + +.errors { + border-radius: 5px; + width: 400px; + margin: auto; + /* border: 1px solid $red; */ + padding: 15px; + background-color: rgba(204, 0, 0, 0.1); + & .errorItem { + display: flex; + align-items: center; + justify-content: center; + } +} + +.submit { + display: block; + border-radius: 5px; + background: $teal; + width: 135px; + height: 45px; + margin: 20px auto; + color: $white; + font-size: 16px; + cursor: pointer; +} + +.inputWithIcon { + position: relative; + width: 400px; + margin: 0 auto; + + & input { + padding-left: 45px; + } +} + +@define-mixin inputIcon $name { + position: absolute; + left: 15px; + top: calc(50% - 8px); + @mixin icon $name, $gray-medium, 15px; +} + +.inputIconUser { + @mixin inputIcon user-alt; +} + +.inputIconPassword { + @mixin inputIcon lock-alt; +} + + + +.left { + /* background: rgb(57,78,255); */ + background: linear-gradient(135deg, rgba(57,78,255,1) 0%, rgba(58,89,245,1) 21%, rgba(62,161,183,1) 69%, rgba(62,170,175,1) 100%); + background-image: svg-load(pattern-login.svg), linear-gradient(135deg, rgba(57,78,255,1) 0%, rgba(58,89,245,1) 21%, rgba(62,161,183,1) 69%, rgba(62,170,175,1) 100%); + background-size: cover; + background-position: center center; + position: relative; + & .bottom { + background-color: black; + } +} + +.formField { + margin-bottom: 20px; + > & label { + margin-bottom: 10px !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Modal/Modal.js b/frontend/app/components/Modal/Modal.js new file mode 100644 index 000000000..cb4738cd0 --- /dev/null +++ b/frontend/app/components/Modal/Modal.js @@ -0,0 +1,13 @@ +export default class Modal extends React.PureComponent { + constructor(props) { + super(props); + this.el = document.createElement('div'); + } + + render() { + return ReactDOM.createPortal( + this.props.children, + this.el, + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Modal/ModalContext.js b/frontend/app/components/Modal/ModalContext.js new file mode 100644 index 000000000..197358f97 --- /dev/null +++ b/frontend/app/components/Modal/ModalContext.js @@ -0,0 +1,38 @@ +const ModalContext = React.createContext({ + component: null, + props: {}, + content: null, + showModal: () => {}, + hideModal: () => {} +}); + +export class ModalProvider extends React.PureComponent { + showModal = (component, props = {}) => { + this.setState({ + component, + props + }); + }; + + hideModal = () => this.setState({ + component: null, + props: {}, + }); + + state = { + component: null, + props: {}, + showModal: this.showModal, + hideModal: this.hideModal + }; + + render() { + return ( + <ModalContext.Provider value={this.state}> + {this.props.children} + </ModalContext.Provider> + ); + } +} + +export const ModalConsumer = ModalContext.Consumer; diff --git a/frontend/app/components/Modal/ModalRoot.js b/frontend/app/components/Modal/ModalRoot.js new file mode 100644 index 000000000..226447af1 --- /dev/null +++ b/frontend/app/components/Modal/ModalRoot.js @@ -0,0 +1,9 @@ +const ModalRoot = () => ( + <ModalConsumer> + {({ component: Component, props, hideModal }) => + Component ? <Component {...props} onRequestClose={hideModal} /> : null + } + </ModalConsumer> +); + +export default ModalRoot \ No newline at end of file diff --git a/frontend/app/components/Modal/withModal.js b/frontend/app/components/Modal/withModal.js new file mode 100644 index 000000000..1ecc93ed2 --- /dev/null +++ b/frontend/app/components/Modal/withModal.js @@ -0,0 +1,8 @@ +import { ModalConsumer } from './ModalContext'; + + +export default BaseComponent => React.memo(props => ( + <ModalConsumer> + { value => <BaseComponent { ...value } { ...props } /> } + </ModalConsumer> +)); \ No newline at end of file diff --git a/frontend/app/components/Onboarding/Onboarding.js b/frontend/app/components/Onboarding/Onboarding.js new file mode 100644 index 000000000..64e09b19f --- /dev/null +++ b/frontend/app/components/Onboarding/Onboarding.js @@ -0,0 +1,59 @@ +import React from 'react' +import SideMenu from './components/SideMenu' +import { withRouter } from 'react-router-dom' +import { Switch, Route, Redirect } from 'react-router' +import { OB_TABS, onboarding as onboardingRoute } from 'App/routes' +import InstallOpenReplayTab from './components/InstallOpenReplayTab' +import IdentifyUsersTab from './components/IdentifyUsersTab' +import IntegrationsTab from './components/IntegrationsTab' +import ManageUsersTab from './components/ManageUsersTab' +import OnboardingNavButton from './components/OnboardingNavButton' +import * as routes from '../../routes' +import Crisp from 'Shared/Crisp' + +const withSiteId = routes.withSiteId; + +const Onboarding = (props) => { + const { match: { params: { activeTab } } } = props; + + const route = path => { + return withSiteId(onboardingRoute(path)); + } + + const renderActiveTab = () => ( + <Switch> + <Route exact strict path={ route(OB_TABS.INSTALLING) } component={ () => <InstallOpenReplayTab /> } /> + <Route exact strict path={ route(OB_TABS.IDENTIFY_USERS) } component={ () => <IdentifyUsersTab /> } /> + <Route exact strict path={ route(OB_TABS.MANAGE_USERS) } component={ () => <ManageUsersTab /> } /> + <Route exact strict path={ route(OB_TABS.INTEGRATIONS) } component={ () => <IntegrationsTab /> } /> + <Redirect to={ route(OB_TABS.INSTALLING) } /> + </Switch> + ) + + return ( + <div className="page flex relative h-full" style={{ minHeight: '100vh', paddingBottom: '75px' }}> + <div className="flex w-full"> + <div className="flex-1 flex bg-ray"> + <div className="pt-6 px-6" style={{ width: '250px'}}> + <SideMenu /> + </div> + <div className="bg-white flex-1 h-full px-6"> + { activeTab && renderActiveTab()} + </div> + </div> + </div> + <div className="py-6 px-4 w-full flex items-center fixed bottom-0 bg-white border-t z-10"> + <div className="crisp-chat" id="crisp-chat"> + <Crisp /> + </div> + <div className="ml-auto"> + {/* <Button primary size="small" plain>Done. See Recoded Sessions</Button> */} + <span className="mx-2"/> + <OnboardingNavButton /> + </div> + </div> + </div> + ) +} + +export default withRouter(Onboarding); \ No newline at end of file diff --git a/frontend/app/components/Onboarding/Onboarding.stories.js b/frontend/app/components/Onboarding/Onboarding.stories.js new file mode 100644 index 000000000..6f160f3e8 --- /dev/null +++ b/frontend/app/components/Onboarding/Onboarding.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Onboarding from '.'; + +storiesOf('Onboarding', module) + .add('Pure', () => ( + <Onboarding /> + )) + diff --git a/frontend/app/components/Onboarding/components/CircleNumber/CircleNumber.js b/frontend/app/components/Onboarding/components/CircleNumber/CircleNumber.js new file mode 100644 index 000000000..c51458176 --- /dev/null +++ b/frontend/app/components/Onboarding/components/CircleNumber/CircleNumber.js @@ -0,0 +1,8 @@ +import React from 'react' +import stl from './circleNumber.css' + +export default function CircleNumber({ text }) { + return ( + <span className={stl.number}>{text}</span> + ) +} diff --git a/frontend/app/components/Onboarding/components/CircleNumber/circleNumber.css b/frontend/app/components/Onboarding/components/CircleNumber/circleNumber.css new file mode 100644 index 000000000..aaea1eb41 --- /dev/null +++ b/frontend/app/components/Onboarding/components/CircleNumber/circleNumber.css @@ -0,0 +1,12 @@ +.number { + width: 24px; + height: 24px; + background-color: black; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + color: white; + font-size: 12px; + margin-right: 10px; +} \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/CircleNumber/index.js b/frontend/app/components/Onboarding/components/CircleNumber/index.js new file mode 100644 index 000000000..59b03145b --- /dev/null +++ b/frontend/app/components/Onboarding/components/CircleNumber/index.js @@ -0,0 +1 @@ +export { default } from './CircleNumber' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/IdentifyUsersTab/IdentifyUsersTab.js b/frontend/app/components/Onboarding/components/IdentifyUsersTab/IdentifyUsersTab.js new file mode 100644 index 000000000..2e6fd2ad6 --- /dev/null +++ b/frontend/app/components/Onboarding/components/IdentifyUsersTab/IdentifyUsersTab.js @@ -0,0 +1,70 @@ +import React from 'react' +import CircleNumber from '../CircleNumber' +import MetadataList from '../MetadataList/MetadataList' +import Snippet from '../Snippet/Snippet' +import Highlight from 'react-highlight' + +export default function IdentifyUsersTab() { + return ( + <div className="flex pt-8 -mx-4"> + <div className="w-8/12 px-4"> + <h1 className="text-3xl font-bold flex items-center mb-4"> + <span>🕵️‍♂️</span> + <div className="ml-3">Identify Users</div> + </h1> + <div> + <div className="font-bold mb-4 text-lg">By User ID</div> + <div className="mb-2"> + Call <span className="highlight-gray">userID</span> to identify your users when recording a session. The identity of the user can be changed, but OpenReplay will only keep the last communicated user ID. + </div> + <Highlight className="js"> + {`tracker.userID('john@doe.com');`} + </Highlight> + {/* <Snippet text="tracker.userID('john@doe.com');" /> */} + </div> + + <div className="my-8" /> + <div> + <div className="font-bold mb-4 text-lg">By adding metadata</div> + <div className="flex items-start"> + <CircleNumber text="1" /> + <div className="pt-1"> + <span className="font-bold">Explicitly specify the metadata</span> + <div className="my-2">You can add up to 10 keys.</div> + <div className="my-2" /> + + <MetadataList /> + </div> + </div> + + + <div className="my-6" /> + <div className="flex items-start"> + <CircleNumber text="2" /> + <div className="pt-1"> + <span className="font-bold">Inject metadata when recording sessions</span> + <div className="my-2">Use the <span className="highlight-gray">metadata</span> method in your code to inject custom user data in the form of a key/value pair (string).</div> + <Highlight className="js"> + {`tracker.metadata('plan', 'premium');`} + </Highlight> + </div> + </div> + {/* <Snippet text="tracker.metadata('plan', 'premium');" /> */} + </div> + </div> + + <div className="my-8" /> + <div className="w-4/12 py-6"> + <div className="p-5 bg-gray-lightest mb-4 rounded"> + <div className="font-bold mb-2">Why Identify Users?</div> + <div className="text-sm">Make it easy to search and filter replays by user id. OpenReplay allows you to associate your internal-user-id with the recording.</div> + </div> + + <div className="p-5 bg-gray-lightest mb-4 rounded"> + <div className="font-bold mb-2">What is Metadata?</div> + <div className="text-sm">Additional information about users can be provided with metadata (also known as traits or user variables). They take the form of key/value pairs, and are useful for filtering and searching for specific session replays.</div> + </div> + </div> + </div> + ) +} diff --git a/frontend/app/components/Onboarding/components/IdentifyUsersTab/index.js b/frontend/app/components/Onboarding/components/IdentifyUsersTab/index.js new file mode 100644 index 000000000..c56d7e9bb --- /dev/null +++ b/frontend/app/components/Onboarding/components/IdentifyUsersTab/index.js @@ -0,0 +1 @@ +export { default } from './IdentifyUsersTab' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/InstallOpenReplayTab/InstallOpenReplayTab.js b/frontend/app/components/Onboarding/components/InstallOpenReplayTab/InstallOpenReplayTab.js new file mode 100644 index 000000000..1d6288c4d --- /dev/null +++ b/frontend/app/components/Onboarding/components/InstallOpenReplayTab/InstallOpenReplayTab.js @@ -0,0 +1,19 @@ +import React from 'react' +import OnboardingTabs from '../OnboardingTabs' +import ProjectFormButton from '../ProjectFormButton' + +export default function InstallOpenReplayTab() { + return ( + <div className="pt-8"> + <h1 className="flex items-center mb-4"> + <span className="text-3xl">👋</span> + <div className="ml-3 flex items-end"> + <span className="text-3xl font-bold">Hey there! Setup</span> + <ProjectFormButton /> + </div> + </h1> + <div className="mb-6">OpenReplay can be installed via script or NPM package (recommended).</div> + <OnboardingTabs /> + </div> + ) +} diff --git a/frontend/app/components/Onboarding/components/InstallOpenReplayTab/index.js b/frontend/app/components/Onboarding/components/InstallOpenReplayTab/index.js new file mode 100644 index 000000000..d2dc736a3 --- /dev/null +++ b/frontend/app/components/Onboarding/components/InstallOpenReplayTab/index.js @@ -0,0 +1 @@ +export { default } from './InstallOpenReplayTab' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/IntegrationsTab/IntegrationsTab.js b/frontend/app/components/Onboarding/components/IntegrationsTab/IntegrationsTab.js new file mode 100644 index 000000000..df05ca807 --- /dev/null +++ b/frontend/app/components/Onboarding/components/IntegrationsTab/IntegrationsTab.js @@ -0,0 +1,84 @@ +import React from 'react' +import { Icon } from 'UI' +import Integrations from '../../../Client/Integrations' + +function IntegrationItem({ icon, title, onClick= () => null }) { + return ( + <div className="flex flex-col items-center mr-16"> + <Icon name={icon} size="40" /> + <div className="mt-1 text-sm">{title}</div> + </div> + ) +} + +function IntegrationsTab() { + return ( + <div className="flex pt-8 -mx-4"> + <div className="w-8/12 px-4"> + <h1 className="text-3xl font-bold flex items-center mb-4"> + <span>🔌</span> + <div className="ml-3">Plugins</div> + </h1> + <Integrations hideHeader plugins /> + + <div className="my-4"/> + <h1 className="text-3xl font-bold flex items-center mb-4"> + <span>🔌</span> + <div className="ml-3">Integrations</div> + </h1> + + <Integrations hideHeader /> + + {/* <div className="mt-6"> + <div className="font-bold mb-4">How are you handling store management?</div> + <div className="flex"> + <IntegrationItem icon="vendors/redux" title="Redux" /> + <IntegrationItem icon="vendors/vuex" title="VueX" /> + <IntegrationItem icon="vendors/graphql" title="GraphQL" /> + <IntegrationItem icon="vendors/ngrx" title="NgRx" /> + </div> + </div> + + <div className="divider" /> + + <div className="mt-6"> + <div className="font-bold mb-4">How are you monitoring errors and crash reporting?</div> + <div className="flex"> + <IntegrationItem icon="integrations/sentry" title="Sentry" /> + <IntegrationItem icon="integrations/bugsnag" title="Sentry" /> + <IntegrationItem icon="integrations/rollbar" title="Sentry" /> + <IntegrationItem icon="integrations/elasticsearch" title="Sentry" /> + </div> + </div> + + <div className="divider" /> + + <div className="mt-6"> + <div className="font-bold mb-4">How are you logging backend errors?</div> + <div className="flex"> + <IntegrationItem icon="integrations/datadog" title="Datadog" /> + <IntegrationItem icon="integrations/sumologic" title="Sumo Logic" /> + <IntegrationItem icon="integrations/stackdriver" title="Stackdriver" /> + <IntegrationItem icon="integrations/cloudwatch" title="CloudWatch" /> + <IntegrationItem icon="integrations/newrelic" title="New Relic" /> + </div> + </div> + + <div className="my-4" /> */} + </div> + <div className="py-6 w-4/12"> + <div className="p-5 bg-gray-lightest mb-4"> + <div className="font-bold mb-2">Why Use Plugins?</div> + <div className="text-sm">Reproduce issues as if they happened in your own browser. Plugins help capture your application’s store, HTTP requests, GraphQL queries and more.</div> + </div> + + <div className="p-5 bg-gray-lightest mb-4"> + <div className="font-bold mb-2">Why Use Integrations?</div> + <div className="text-sm">Sync your backend errors with sessions replays and see what happened front-to-back.</div> + </div> + </div> + </div> + ) +} + +export default IntegrationsTab diff --git a/frontend/app/components/Onboarding/components/IntegrationsTab/index.js b/frontend/app/components/Onboarding/components/IntegrationsTab/index.js new file mode 100644 index 000000000..785164388 --- /dev/null +++ b/frontend/app/components/Onboarding/components/IntegrationsTab/index.js @@ -0,0 +1 @@ +export { default } from './IntegrationsTab' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/ManageUsersTab/ManageUsersTab.js b/frontend/app/components/Onboarding/components/ManageUsersTab/ManageUsersTab.js new file mode 100644 index 000000000..c4d414395 --- /dev/null +++ b/frontend/app/components/Onboarding/components/ManageUsersTab/ManageUsersTab.js @@ -0,0 +1,24 @@ +import React from 'react' +import ManageUsers from '../../../Client/ManageUsers' + +export default function ManageUsersTab() { + return ( + <div className="flex pt-8 -mx-4"> + <div className="w-8/12 px-4"> + <h1 className="text-3xl font-bold flex items-center mb-4"> + <span>👨‍💻</span> + <div className="ml-3">Invite Collaborators</div> + </h1> + + <ManageUsers hideHeader /> + + </div> + <div className="w-4/12 py-6"> + <div className="p-5 bg-gray-lightest mb-4 rounded"> + <div className="font-bold mb-2">Why Invite Collaborators?</div> + <div className="text-sm">Session replay is useful for all team members, from developers, testers and product managers to design, support and marketing folks. Invite them all and start improving your app now.</div> + </div> + </div> + </div> + ) +} diff --git a/frontend/app/components/Onboarding/components/ManageUsersTab/index.js b/frontend/app/components/Onboarding/components/ManageUsersTab/index.js new file mode 100644 index 000000000..448dcf28e --- /dev/null +++ b/frontend/app/components/Onboarding/components/ManageUsersTab/index.js @@ -0,0 +1 @@ +export { default } from './ManageUsersTab' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/MetadataList/MetadataList.js b/frontend/app/components/Onboarding/components/MetadataList/MetadataList.js new file mode 100644 index 000000000..014fac088 --- /dev/null +++ b/frontend/app/components/Onboarding/components/MetadataList/MetadataList.js @@ -0,0 +1,69 @@ +import React, { useState, useEffect } from 'react' +import { Button, SlideModal, TagBadge } from 'UI' +import { connect } from 'react-redux' +import { init, fetchList, save, remove } from 'Duck/customField'; +import CustomFieldForm from '../../../Client/CustomFields/CustomFieldForm'; +import { confirm } from 'UI/Confirmation'; + +const MetadataList = (props) => { + const { site, fields } = props; + const [showModal, setShowModal] = useState(false) + + useEffect(() => { + props.fetchList(site.id); + }, []) + + const save = (field) => { + props.save(site.id, field).then(() => { + setShowModal(false) + }); + }; + + const openModal = () => { + setShowModal(!showModal); + } + + const removeMetadata = async (field) => { + if (await confirm({ + header: 'Metadata', + confirmation: `Are you sure you want to remove?` + })) { + this.props.remove(site.id, field.index); + } + } + + return ( + <div className="py-2 flex"> + <Button primary outline size="small" onClick={() => openModal(true)}>Add Metadata</Button> + <div className="flex ml-2"> + { fields.map((f, index) => ( + <TagBadge + key={index} + text={ f.key } + onRemove={ () => removeMetadata(f) } + outline + /> + // <div>{f.key}</div> + ))} + </div> + + <SlideModal + // title={ `${ (field.exists() ? 'Update' : 'Add') + ' Metadata Field' }` } + title={ `Metadata Field` } + size="small" + isDisplayed={ showModal } + content={ showModal && ( + <CustomFieldForm onClose={ () => setShowModal(false) } onSave={save} /> + )} + onClose={ () => setShowModal(false) } + /> + </div> + ) +} + +export default connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), + fields: state.getIn(['customFields', 'list']).sortBy(i => i.index), + field: state.getIn(['customFields', 'instance']), + loading: state.getIn(['customFields', 'fetchRequest', 'loading']), +}), { fetchList, save, remove })(MetadataList) \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/MetadataList/index.js b/frontend/app/components/Onboarding/components/MetadataList/index.js new file mode 100644 index 000000000..ae4eb73f6 --- /dev/null +++ b/frontend/app/components/Onboarding/components/MetadataList/index.js @@ -0,0 +1 @@ +export { default } from './MetadataList' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingMenu/OnboardingMenu.js b/frontend/app/components/Onboarding/components/OnboardingMenu/OnboardingMenu.js new file mode 100644 index 000000000..bd985b5ef --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingMenu/OnboardingMenu.js @@ -0,0 +1,73 @@ +import React from 'react' +import { Icon, SideMenuitem } from 'UI' +import cn from 'classnames' +import stl from './onboardingMenu.css' +import { OB_TABS, onboarding as onboardingRoute } from 'App/routes' +import { withRouter } from 'react-router-dom' +import * as routes from '../../../../routes' + +const withSiteId = routes.withSiteId; + +const MENU_ITEMS = [OB_TABS.INSTALLING, OB_TABS.IDENTIFY_USERS, OB_TABS.MANAGE_USERS, OB_TABS.INTEGRATIONS] + +const Item = ({ icon, text, completed, active, onClick }) => ( + <div className={ + cn( + 'cursor-pointer', + stl.stepWrapper, + { [stl.completed]: completed, [stl.active]: active } + )} + onClick={onClick} + > + <div className={stl.verticleLine }/> + <div className={cn('flex', stl.step)}> + <div className={ + cn( + "h-6 w-6 mr-3 bg-white rounded-full flex items-center justify-center", + stl.iconWrapper, + {'bg-gray-light' : !active || !completed } + )} + > + { completed && + <Icon + name={icon} + color={completed? 'white' : 'gray-medium' } + size="18" + /> + } + </div> + <div className="color-gray-dark">{text}</div> + </div> + </div> +) + +const OnboardingMenu = (props) => { + const { match: { params: { activeTab, siteId } }, history } = props; + const activeIndex = MENU_ITEMS.findIndex(i => i === activeTab); + + const setTab = (tab) => { + history.push(withSiteId(onboardingRoute(tab), siteId)); + } + + return ( + <div> + { activeIndex === 0 && ( + <SideMenuitem + title="Install OpenReplay" + iconName="tools" + active + /> + )} + { activeIndex > 0 && ( + <> + <Item icon="check" text="Install OpenReplay" completed={activeIndex >= 0} active={activeIndex === 0} onClick={() => setTab(MENU_ITEMS[0])} /> + <Item icon="check" text="Identify Users" completed={activeIndex >= 1} active={activeIndex === 1} onClick={() => setTab(MENU_ITEMS[1])} /> + <Item icon="check" text="Invite Collaborators" completed={activeIndex >= 2} active={activeIndex === 2} onClick={() => setTab(MENU_ITEMS[2])} /> + <Item icon="check" text="Integrations" completed={activeIndex >= 3} active={activeIndex === 3} onClick={() => setTab(MENU_ITEMS[3])} /> + </> + )} + </div> + ) +} + +export default withRouter(OnboardingMenu) diff --git a/frontend/app/components/Onboarding/components/OnboardingMenu/index.js b/frontend/app/components/Onboarding/components/OnboardingMenu/index.js new file mode 100644 index 000000000..1edf30267 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingMenu/index.js @@ -0,0 +1 @@ +export { default } from './OnboardingMenu' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingMenu/onboardingMenu.css b/frontend/app/components/Onboarding/components/OnboardingMenu/onboardingMenu.css new file mode 100644 index 000000000..cbf1a24a2 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingMenu/onboardingMenu.css @@ -0,0 +1,56 @@ +.stepWrapper { + overflow: hidden; + position: relative; + + & .step { + padding: 10px 0; + & .iconWrapper { + background-color: white; + border: solid thin $gray-light; + } + } + + &.completed { + & .step .iconWrapper { + background-color: $gray-medium; + } + } + + &.active { + & .step .iconWrapper { + background-color: $teal; + } + } +} + +.stepWrapper:first-child { + & .verticleLine:before { + display: none !important; + } +} + +.stepWrapper:last-child { + & .verticleLine:after { + display: none !important; + } +} + +.verticleLine { + &:before, &:after { + content: ""; + width: 1px; + position: absolute; + background-color: $gray-medium; + left: 10px; + } + + &:before { + top: 0; + bottom: 75%; + } + + &:after { + top: 75%; + bottom: 0; + } +} \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingNavButton/OnboardingNavButton.js b/frontend/app/components/Onboarding/components/OnboardingNavButton/OnboardingNavButton.js new file mode 100644 index 000000000..0a048e3cb --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingNavButton/OnboardingNavButton.js @@ -0,0 +1,56 @@ +import React from 'react' +import { connect } from 'react-redux' +import { withRouter } from 'react-router' +import { Button } from 'UI' +import { OB_TABS, onboarding as onboardingRoute } from 'App/routes' +import * as routes from '../../../../routes' +import { sessions } from 'App/routes'; + +const withSiteId = routes.withSiteId; +const MENU_ITEMS = [OB_TABS.INSTALLING, OB_TABS.IDENTIFY_USERS, OB_TABS.MANAGE_USERS, OB_TABS.INTEGRATIONS] +const BTN_MSGS = [ + 'Next: Identify Users', + 'Next: Invite Collaborators', + 'Next: Integrations', + 'See Recorded Sessions' +] + +const OnboardingNavButton = (props) => { + const { match: { params: { activeTab, siteId } }, history } = props; + const activeIndex = MENU_ITEMS.findIndex(i => i === activeTab); + const completed = activeIndex == MENU_ITEMS.length - 1; + + const setTab = () => { + if (!completed) { + const tab = MENU_ITEMS[activeIndex+1] + history.push(withSiteId(onboardingRoute(tab), siteId)); + } else { + history.push(sessions()); + } + } + + return ( + <> + <Button + primary + size="small" + plain + onClick={() => history.push(sessions())} + > + {activeIndex === 0 ? 'Done. See Recorded Sessions' : 'Skip Optional Steps and See Recorded Sessions'} + </Button> + <span className="mx-2"/> + { + <Button + primary + size="small" + onClick={setTab} + > + {BTN_MSGS[activeIndex]} + </Button> + } + </> + ) +} + +export default withRouter(OnboardingNavButton) \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingNavButton/index.js b/frontend/app/components/Onboarding/components/OnboardingNavButton/index.js new file mode 100644 index 000000000..28ab42bb7 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingNavButton/index.js @@ -0,0 +1 @@ +export { default } from './OnboardingNavButton' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/CopyButton/CopyButton.js b/frontend/app/components/Onboarding/components/OnboardingTabs/CopyButton/CopyButton.js new file mode 100644 index 000000000..d080b1a02 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/CopyButton/CopyButton.js @@ -0,0 +1,25 @@ +import React from 'react' +import { useState } from 'react'; +import copy from 'copy-to-clipboard'; + +function CopyButton({ content, className }) { + const [copied, setCopied] = useState(false) + + const copyHandler = () => { + setCopied(true); + copy(content); + setTimeout(() => { + setCopied(false); + }, 1000); + }; + return ( + <button + className={ className } + onClick={ copyHandler } + > + { copied ? 'copied' : 'copy' } + </button> + ) +} + +export default CopyButton diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/CopyButton/index.js b/frontend/app/components/Onboarding/components/OnboardingTabs/CopyButton/index.js new file mode 100644 index 000000000..a230b4ecc --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/CopyButton/index.js @@ -0,0 +1 @@ +export { default } from './CopyButton' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/InstallDocs.js b/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/InstallDocs.js new file mode 100644 index 000000000..4072b2018 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/InstallDocs.js @@ -0,0 +1,100 @@ +import React, { useState } from 'react' +import { connect } from 'react-redux' +import stl from './installDocs.css' +import cn from 'classnames' +import CopyButton from '../CopyButton' +import Highlight from 'react-highlight' +import CircleNumber from '../../CircleNumber' +import { Slider } from 'UI' + +const installationCommand = 'npm i @openreplay/tracker --save' +const usageCode = `import Tracker from '@openreplay/tracker'; +const tracker = new Tracker({ + projectID: PROJECT_ID +}); +tracker.start();` +const usageCodeSST = `import Tracker from '@openreplay/tracker/cjs'; +//... +const tracker = new Tracker({ + projectID: PROJECT_ID, + onStart: () => { tracker.userID('MY_USER_ID'); }, +}); +//... + useEffect(() => { // or componentDidMount + tracker.start(); + }, [])` + +function InstallDocs({ site }) { + const _usageCode = usageCode.replace('PROJECT_ID', site.projectKey) + const _usageCodeSST = usageCodeSST.replace('PROJECT_ID', site.projectKey) + const [isSpa, setIsSpa] = useState(true) + return ( + <div> + <div className="mb-8"> + <div className="font-semibold mb-2 flex items-center"> + <CircleNumber text="1" /> + Install the npm package. + </div> + <div className={ cn(stl.snippetWrapper, 'ml-10 mr-8') }> + <CopyButton content={installationCommand} className={cn(stl.codeCopy, 'mt-2 mr-2')} /> + <Highlight className="cli"> + {installationCommand} + </Highlight> + </div> + </div> + <div> + <div className="font-semibold mb-2 flex items-center"> + <CircleNumber text="2" /> + Continue with one of the following options. + </div> + + <div className="flex items-center ml-10 cursor-pointer"> + <div className="mr-2" onClick={() => setIsSpa(!isSpa)}>Server-Side-Rendered (SSR)?</div> + <Slider + name="sessionsLive" + onChange={ () => setIsSpa(!isSpa) } + checked={ !isSpa } + // className={stl.customSlider} + style={{ lineHeight: '23px' }} + // label="Server-Side-Rendered (SSR)?" + /> + </div> + + <div className="flex ml-10 mt-4"> + <div className="w-full"> + {isSpa && ( + <div className="w-6/12"> + <div className="mb-2 text-sm">If your website is a <strong>Single Page Application (SPA)</strong> use the below code:</div> + <div className={ cn(stl.snippetWrapper) }> + <CopyButton content={_usageCode} className={cn(stl.codeCopy, 'mt-2 mr-2')} /> + <Highlight className="js"> + {_usageCode} + </Highlight> + </div> + </div> + )} + + {!isSpa && ( + <div className="w-6/12"> + <div className="mb-2 text-sm">Otherwise, if your web app is <strong>Server-Side-Rendered (SSR)</strong> (i.e. NextJS, NuxtJS) use this snippet:</div> + <div className={ cn(stl.snippetWrapper) }> + <CopyButton content={_usageCodeSST} className={cn(stl.codeCopy, 'mt-2 mr-2')} /> + <Highlight className="js"> + {_usageCodeSST} + </Highlight> + </div> + </div> + )} + </div> + </div> + </div> + <div className="border-t pt-4 mt-8">See <a href="https://docs.openreplay.com/javascript-sdk" className="color-teal underline" target="_blank">Documentation</a> for the list of available options.</div> + </div> + ) +} + +// export default InstallDocs + +export default connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), +}))(InstallDocs) \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/index.js b/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/index.js new file mode 100644 index 000000000..854a075b6 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/index.js @@ -0,0 +1 @@ +export { default } from './InstallDocs'; \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/installDocs.css b/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/installDocs.css new file mode 100644 index 000000000..448b08f72 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/InstallDocs/installDocs.css @@ -0,0 +1,29 @@ +@import 'zindex.css'; + +.snippetWrapper { + position: relative; + & .codeCopy { + position: absolute; + right: 0px; + top: -3px; + z-index: $codeSnippet; + padding: 5px 10px; + color: $teal; + text-transform: uppercase; + cursor: pointer; + border-radius: 3px; + transition: all 0.4s; + user-select: none; + + &:hover { + background-color: $gray-light; + transition: all 0.2s; + } + } + & .snippet { + overflow: hidden; + line-height: 20px; + border-radius: 5px; + user-select: none; + } +} \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/OnboardingTabs.js b/frontend/app/components/Onboarding/components/OnboardingTabs/OnboardingTabs.js new file mode 100644 index 000000000..6ec2db234 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/OnboardingTabs.js @@ -0,0 +1,50 @@ +import React from 'react'; +import { Tabs } from 'UI'; +import ProjectCodeSnippet from './ProjectCodeSnippet'; +import InstallDocs from './InstallDocs'; + +const PROJECT = 'SCRIPT'; +const DOCUMENTATION = 'NPM'; +// const SEGMENT = 'SEGMENT'; +// const GOOGLE_TAG = 'GOOGLE TAG'; +const TABS = [ + { key: PROJECT, text: PROJECT }, + { key: DOCUMENTATION, text: DOCUMENTATION }, + // { key: SEGMENT, text: SEGMENT }, + // { key: GOOGLE_TAG, text: GOOGLE_TAG } +]; + +class TrackingCodeModal extends React.PureComponent { + state = { copied: false, changed: false, activeTab: PROJECT }; + + setActiveTab = (tab) => { + this.setState({ activeTab: tab }); + } + + renderActiveTab = () => { + console.log('rendering...') + switch (this.state.activeTab) { + case PROJECT: + return <ProjectCodeSnippet /> + case DOCUMENTATION: + return <InstallDocs /> + } + return null; + } + + render() { + const { activeTab } = this.state; + return ( + <> + <Tabs + tabs={ TABS } + active={ activeTab } onClick={ this.setActiveTab } /> + <div className="p-5 py-8"> + { this.renderActiveTab() } + </div> + </> + ); + } +} + +export default TrackingCodeModal; \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/ProjectCodeSnippet.js b/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/ProjectCodeSnippet.js new file mode 100644 index 000000000..d4989b5a4 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/ProjectCodeSnippet.js @@ -0,0 +1,159 @@ +import React, { useState } from 'react' +import { connect } from 'react-redux'; +import { editGDPR, saveGDPR } from 'Duck/site'; +import copy from 'copy-to-clipboard'; +import { Select, Checkbox } from 'UI'; +import GDPR from 'Types/site/gdpr'; +import cn from 'classnames' +import stl from './projectCodeSnippet.css' +import CircleNumber from '../../CircleNumber'; +import Highlight from 'react-highlight' + +const inputModeOptions = [ + { text: 'Record all inputs', value: 'plain' }, + { text: 'Ignore all inputs', value: 'obscured' }, + { text: 'Obscure all inputs', value: 'hidden' }, +]; + +const codeSnippet = `<!-- OpenReplay Tracking Code for HOST --> +<script> +(function(A,s,a,y,e,r){ + r=window.OpenReplay=[s,r,e,[y-1]]; + s=document.createElement('script');s.src=a;s.async=!A; + document.getElementsByTagName('head')[0].appendChild(s); + r.start=function(v){r.push([0])}; + r.stop=function(v){r.push([1])}; + r.setUserID=r.userID=function(id){r.push([2,id])}; + r.setUserAnonymousID=r.userAnonymousID=function(id){r.push([3,id])}; + r.setMetadata=r.metadata=function(k,v){r.push([4,k,v])}; + r.event=function(k,p,i){r.push([5,k,p,i])}; + r.issue=function(k,p){r.push([6,k,p])}; + r.isActive=r.active=function(){return false}; + r.getSessionToken=r.sessionID=function(){}; +})(0,PROJECT_HASH,"//${window.location.hostname}/static/openreplay.js",1,XXX); +<script>`; + +const ProjectCodeSnippet = props => { + const { site, gdpr } = props; + const [changed, setChanged] = useState(false) + const [copied, setCopied] = useState(false) + + const saveGDPR = (value) => { + setChanged(true) + props.saveGDPR(site.id, GDPR({...value})); + } + + const onChangeSelect = (event, { name, value }) => { + const { gdpr } = site; + const _gdpr = { ...gdpr.toData() }; + props.editGDPR({ [ name ]: value }); + _gdpr[name] = value; + props.editGDPR({ [ name ]: value }); + saveGDPR(_gdpr) + }; + + const onChangeOption = (event, { name, checked }) => { + const { gdpr } = props.site; + const _gdpr = { ...gdpr.toData() }; + _gdpr[name] = checked; + props.editGDPR({ [ name ]: checked }); + saveGDPR(_gdpr) + } + + const getOptionValues = () => { + const { gdpr } = props.site; + return (!!gdpr.maskEmails)|(!!gdpr.maskNumbers << 1)|(['plain' , 'obscured', 'hidden'].indexOf(gdpr.defaultInputMode) << 5)|28 + } + + + const getCodeSnippet = site => { + let snippet = codeSnippet; + if (site && site.id) { + snippet = snippet.replace('PROJECT_HASH', site.projectKey); + } + return snippet + .replace('XXX', getOptionValues()) + .replace('HOST', site && site.host); + } + + const copyHandler = (code) => { + setCopied(true); + copy(code); + setTimeout(() => { + setCopied(false); + }, 1000); + }; + + const _snippet = getCodeSnippet(site); + + return ( + <div> + <div className="mb-4"> + <div className="font-semibold mb-2 flex items-center"> + <CircleNumber text="1" /> Choose data recording options: + </div> + <div className="flex items-center ml-10"> + <Select + name="defaultInputMode" + options={ inputModeOptions } + onChange={ onChangeSelect } + placeholder="Default Input Mode" + value={ gdpr.defaultInputMode } + /> + <div className="mx-4" /> + + <Checkbox + name="maskNumbers" + type="checkbox" + checked={ gdpr.maskNumbers } + onClick={ onChangeOption } + className="mr-2" + label="Do not record any numeric text" + /> + + <div className="mx-4" /> + + <Checkbox + name="maskEmails" + type="checkbox" + checked={ gdpr.maskEmails } + onClick={ onChangeOption } + className="mr-2" + label="Do not record email addresses" + /> + </div> + </div> + <div className={ cn(stl.info,'rounded bg-gray mt-2 mb-4', { 'hidden': !changed })}> + Below code snippet changes depending on the data recording options chosen. + </div> + + <div className={ cn(stl.instructions, 'mt-8') }> + <div className="font-semibold flex items-center"> + <CircleNumber text="2" /> + <span>Install SDK</span> + </div> + <div className={ stl.siteId }>{ 'Project ID: ' } <span>{ site.projectKey }</span></div> + </div> + + <div className="ml-10 mb-2 text-sm"> + Paste this snippet <span>{ 'before the ' }</span> + <span className={ stl.highLight }> { '</head>' } </span> + <span>{ ' tag of your page.' }</span> + </div> + <div className={ cn(stl.snippetsWrapper, 'ml-10') }> + <button className={ stl.codeCopy } onClick={ () => copyHandler(_snippet) }>{ copied ? 'copied' : 'copy' }</button> + <Highlight className="html"> + {_snippet} + </Highlight> + </div> + {/* TODO Extract for SaaS */} + <div className="my-4">You can also setup OpenReplay using <a className="link" href="https://docs.openreplay.com/integrations/google-tag-manager" target="_blank">Google Tag Manager (GTM)</a> or <a className="link" href="https://docs.openreplay.com/integrations/segment" target="_blank">Segment</a>. </div> + </div> + ) +} + +export default connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), + gdpr: state.getIn([ 'site', 'instance', 'gdpr' ]), + saving: state.getIn([ 'site', 'saveGDPR', 'loading' ]) +}), { editGDPR, saveGDPR })(ProjectCodeSnippet) diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/index.js b/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/index.js new file mode 100644 index 000000000..d665d3825 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/index.js @@ -0,0 +1 @@ +export { default } from './ProjectCodeSnippet'; \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/projectCodeSnippet.css b/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/projectCodeSnippet.css new file mode 100644 index 000000000..610a3a4d7 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/projectCodeSnippet.css @@ -0,0 +1,101 @@ + +@import 'zindex.css'; + +.modalHeader { + display: flex !important; + align-items: center; +} + +.content { + background-color: white !important; +} + +.highLight { + background-color: rgba(204, 0, 0, 0.05); + color: $red; + padding: 2px 5px; + border-radius: 3px; +} + +.snippetsWrapper { + position: relative; + & .codeCopy { + position: absolute; + right: 10px; + top: 10px; + z-index: $codeSnippet; + padding: 5px 10px; + color: $teal; + text-transform: uppercase; + cursor: pointer; + border-radius: 3px; + transition: all 0.4s; + user-select: none; + + &:hover { + background-color: $gray-light; + transition: all 0.2s; + } + } + & .snippet { + overflow: hidden; + line-height: 18px; + border-radius: 5px; + user-select: none; + & > div { + background-color: $gray-lightest !important; + } + } +} + +.siteInfo { + display: flex; + align-items: center; + margin-bottom: 10px; + + & span { + color: $teal; + } +} +.instructions { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 10px; +} + +.closeButton { + margin-left: auto; + cursor: pointer; + padding: 5px; +} + +.siteId { + font-weight: 500; + & span { + background: #f6f6f6; + border-radius: 3px; + padding: 2px 7px; + font-weight: normal; + margin-left: 4px; + border: solid thin #eee; + } +} + +.info { + padding: 5px 10px; + background-color: #ffedd1; +} + +.number { + width: 24px; + height: 24px; + background-color: black; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + color: white; + font-size: 12px; + margin-right: 10px; +} \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/SegmentTab/SegmentTab.js b/frontend/app/components/Onboarding/components/OnboardingTabs/SegmentTab/SegmentTab.js new file mode 100644 index 000000000..8168bbc0f --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/SegmentTab/SegmentTab.js @@ -0,0 +1,12 @@ +import React from 'react' + +export default function SegmentTab() { + return ( + <div> + <p><b>Note:</b> This integration is only available to OpenReplay Cloud customers.</p> + <p>Segment allows you to collect your user data from every source into a single exportable API. You can then send that information to all your favorite tools instantly.</p> + <p>With this integration, you don’t have to add any code to your site. If you have a Segment account, all you need to do is to set your OpenReplay ProjectID then enable the integration as specified in the instructions below.</p> + <div className="mt-6">See <a href="https://docs.openreplay.com/api" className="color-teal underline" target="_blank">API</a> for more options.</div> + </div> + ) +} diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/SegmentTab/index.js b/frontend/app/components/Onboarding/components/OnboardingTabs/SegmentTab/index.js new file mode 100644 index 000000000..29ca44602 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/SegmentTab/index.js @@ -0,0 +1 @@ +export { default } from './SegmentTab' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/index.js b/frontend/app/components/Onboarding/components/OnboardingTabs/index.js new file mode 100644 index 000000000..4744de7c7 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/index.js @@ -0,0 +1 @@ +export { default } from './OnboardingTabs'; \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/onboardingTabs.css b/frontend/app/components/Onboarding/components/OnboardingTabs/onboardingTabs.css new file mode 100644 index 000000000..805329b16 --- /dev/null +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/onboardingTabs.css @@ -0,0 +1,20 @@ + +@import 'zindex.css'; + +.modalHeader { + display: flex !important; + align-items: center; +} + +.content { + background-color: white !important; + padding: 0 !important; +} + + +.closeButton { + margin-left: auto; + cursor: pointer; + padding: 5px; +} + diff --git a/frontend/app/components/Onboarding/components/ProjectFormButton/ProjectFormButton.js b/frontend/app/components/Onboarding/components/ProjectFormButton/ProjectFormButton.js new file mode 100644 index 000000000..c7386fe7b --- /dev/null +++ b/frontend/app/components/Onboarding/components/ProjectFormButton/ProjectFormButton.js @@ -0,0 +1,31 @@ +import React, { useState } from 'react' +import { connect } from 'react-redux' +import { SlideModal } from 'UI' +import NewSiteForm from '../../../Client/Sites/NewSiteForm' + +const ProjectFormButton = ({ children, site }) => { + const [showModal, setShowModal] = useState(false) + + const closeModal = () => setShowModal(!showModal); + + return ( + <> + <span + className="text-3xl font-bold ml-2 color-teal underline-dashed cursor-pointer" + onClick={ () => setShowModal(true)} + >{site && site.name}</span> + {/* { React.cloneElement( children, { onClick: () => setShowModal(true) } ) } */} + <SlideModal + title={ 'Project' } + size="small" + isDisplayed={ showModal } + content={ <NewSiteForm onClose={ closeModal } /> } + onClose={ closeModal } + /> + </> + ) +} + +export default connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), +}))(ProjectFormButton) \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/ProjectFormButton/index.js b/frontend/app/components/Onboarding/components/ProjectFormButton/index.js new file mode 100644 index 000000000..e5013b005 --- /dev/null +++ b/frontend/app/components/Onboarding/components/ProjectFormButton/index.js @@ -0,0 +1 @@ +export { default } from './ProjectFormButton' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/SideMenu.js b/frontend/app/components/Onboarding/components/SideMenu.js new file mode 100644 index 000000000..e828fd856 --- /dev/null +++ b/frontend/app/components/Onboarding/components/SideMenu.js @@ -0,0 +1,48 @@ +import React from 'react' +import stl from './sideMenu.css' +import cn from 'classnames' +import { SideMenuitem, Icon } from 'UI' +import OnboardingMenu from './OnboardingMenu/OnboardingMenu' + +export default function SideMenu() { + return ( + <div className={stl.wrapper}> + <div className={ cn(stl.header, 'flex items-center') }> + <div className={ stl.label }> + <span>Setup Project</span> + </div> + </div> + + <OnboardingMenu /> + + <div className={cn(stl.divider, 'my-4')} /> + + <div className={ cn(stl.header, 'flex items-center') }> + <div className={ stl.label }> + <span>Help</span> + </div> + </div> + + <SideMenuitem + // active={activeTab.type === 'all'} + title="Documentation" + iconName="journal-code" + onClick={() => window.open('https://docs.openreplay.com/api', '_blank')} + /> + + <SideMenuitem + // active={activeTab.type === 'all'} + title="Report Issue" + iconName="github" + onClick={() => window.open('https://github.com/openreplay/openreplay/issues/new', '_blank')} + /> + + <SideMenuitem + // active={activeTab.type === 'all'} + title="Chat with us" + iconName="chat-dots" + onClick={() => $crisp.push(['do', 'chat:open']) } + /> + </div> + ) +} diff --git a/frontend/app/components/Onboarding/components/Snippet/Snippet.js b/frontend/app/components/Onboarding/components/Snippet/Snippet.js new file mode 100644 index 000000000..cd2a7bb33 --- /dev/null +++ b/frontend/app/components/Onboarding/components/Snippet/Snippet.js @@ -0,0 +1,36 @@ +import React, { useState } from 'react' +import { Controlled as CodeMirror } from 'react-codemirror2' +import cn from 'classnames' +import stl from './snippet.css' + +export default function Snippet({ text }) { + const [copied, setCopied] = useState(false) + + + const copyHandler = (code) => { + setCopied(true); + copy(code); + setTimeout(() => { + setCopied(false); + }, 1000); + }; + + return ( + <div className={ cn(stl.snippetsWrapper, 'bg-gray-light-shade rounded p-3') }> + <button className={ stl.codeCopy } onClick={ () => copyHandler(_snippet) }>{ copied ? 'copied' : 'copy' }</button> + <CodeMirror + value={ text } + className={ stl.snippet } + options={{ + autoCursor: false, + height: 50, + // mode: 'javascript', + theme: 'docs', + readOnly: true, + showCursorWhenSelecting: false, + scroll: false + }} + /> + </div> + ) +} diff --git a/frontend/app/components/Onboarding/components/Snippet/index.js b/frontend/app/components/Onboarding/components/Snippet/index.js new file mode 100644 index 000000000..fc24f4209 --- /dev/null +++ b/frontend/app/components/Onboarding/components/Snippet/index.js @@ -0,0 +1 @@ +export { default } from './Snippet' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/Snippet/snippet.css b/frontend/app/components/Onboarding/components/Snippet/snippet.css new file mode 100644 index 000000000..e64e0f2cd --- /dev/null +++ b/frontend/app/components/Onboarding/components/Snippet/snippet.css @@ -0,0 +1,29 @@ +@import 'zindex.css'; + +.snippetsWrapper { + position: relative; + & .codeCopy { + position: absolute; + right: 18px; + top: 19px; + z-index: $codeSnippet; + padding: 5px 10px; + color: $teal; + text-transform: uppercase; + cursor: pointer; + border-radius: 3px; + transition: all 0.4s; + user-select: none; + + &:hover { + background-color: $gray-light; + transition: all 0.2s; + } + } + & .snippet { + overflow: hidden; + line-height: 20px; + border-radius: 5px; + user-select: none; + } +} \ No newline at end of file diff --git a/frontend/app/components/Onboarding/components/sideMenu.css b/frontend/app/components/Onboarding/components/sideMenu.css new file mode 100644 index 000000000..71404279d --- /dev/null +++ b/frontend/app/components/Onboarding/components/sideMenu.css @@ -0,0 +1,33 @@ +.wrapper { + padding-right: 20px; +} + +.header { + margin-bottom: 10px; + & .label { + text-transform: uppercase; + color: gray; + letter-spacing: 0.2em; + } + + & .manageButton { + margin-left: 5px; + font-size: 12px; + color: $teal; + cursor: pointer; + padding: 2px 5px; + border: solid thin transparent; + border-radius: 3px; + margin-bottom: -3px; + &:hover { + background-color: $gray-light; + color: $gray-darkest; + } + } +} + +.divider { + height: 1px; + width: 100%; + background-color: $gray-light; +} \ No newline at end of file diff --git a/frontend/app/components/Onboarding/index.js b/frontend/app/components/Onboarding/index.js new file mode 100644 index 000000000..c26d51492 --- /dev/null +++ b/frontend/app/components/Onboarding/index.js @@ -0,0 +1 @@ +export { default } from './Onboarding' \ No newline at end of file diff --git a/frontend/app/components/Onboarding/onboarding.css b/frontend/app/components/Onboarding/onboarding.css new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/app/components/Session/IOSPlayer.js b/frontend/app/components/Session/IOSPlayer.js new file mode 100644 index 000000000..a8d7ca5f3 --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer.js @@ -0,0 +1,66 @@ +import { useState, useEffect } from 'react'; +import ImagePlayer from 'Player/ios/ImagePlayer'; +import { CRASHES, NETWORK, LOGS, PERFORMANCE, CUSTOM } from 'Player/ios/state'; +import Network from './IOSPlayer/Network'; +import Logs from './IOSPlayer/Logs'; +import IMGScreen from './IOSPlayer/IMGScreen'; +import Crashes from './IOSPlayer/Crashes'; +import Performance from './IOSPlayer/Performance'; +import StackEvents from './IOSPlayer/StackEvents'; +import Layout from './Layout/Layout'; + +const TOOLBAR = [ + { + Component: Network, + key: NETWORK, + label: "Network", + icon: "wifi", + }, + { + Component: Logs, + key: LOGS, + label: "Logs", + icon: "console", + }, + { + Component: Crashes, + key: CRASHES, + label: "Crashes", + icon: "console/error", + }, + { + Component: StackEvents, + key: CUSTOM, + label: "Events", + icon: "puzzle-piece", + }, + { + Component: Performance, + key: PERFORMANCE, + label: "Performance", + icon: "tachometer-slow", + showCount: false, + } +]; + + +export default function IOSPlayer({ session }) { + const [player] = useState(() => new ImagePlayer(session)); + useEffect(() => { + player.attach({ wrapperId: "IOSWrapper", screenId: "IOSscreen" }); + return () => { + player.clean(); + } + }, []) + + return ( + <Layout player={ player } toolbar={TOOLBAR} > + <IMGScreen + screenId="IOSscreen" + wrapperId="IOSWrapper" + device={ session.userDevice } + player={ player } + /> + </Layout> + ); +} \ No newline at end of file diff --git a/frontend/app/components/Session/IOSPlayer/Crashes.js b/frontend/app/components/Session/IOSPlayer/Crashes.js new file mode 100644 index 000000000..9fe3d9ad0 --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/Crashes.js @@ -0,0 +1,51 @@ +import { useState } from 'react'; +import { observer } from "mobx-react-lite"; +import { Input, NoContent } from 'UI'; +import { getRE } from 'App/utils'; +import { CRASHES } from 'Player/ios/state'; + +import * as PanelLayout from '../Layout/ToolPanel/PanelLayout'; + +import Autoscroll from 'Components/Session_/Autoscroll'; + + +function Crashes({ player }) { + + const [ filter, setFilter ] = useState(""); + const filterRE = getRE(filter, 'i'); + const filtered = player.lists[CRASHES].listNow.filter(({ name, reason, stacktrace }) => + filterRE.test(name) || filterRE.test(reason) || filterRE.test(stacktrace) + ); + return ( + <> + <PanelLayout.Header> + <Input + className="input-small" + placeholder="Filter" + icon="search" + iconPosition="left" + name="filter" + onChange={ setFilter } + /> + </PanelLayout.Header> + <PanelLayout.Body> + <NoContent + size="small" + show={ filtered.length === 0} + > + <Autoscroll> + { filtered.map(c => ( + <div className="border-b border-gray-light-shade error p-2"> + <h4>{ c.name }</h4> + <h5><i>{`Reason: "${c.reason}"`}</i></h5> + <div className="whitespace-pre pl-5">{ c.stacktrace }</div> + </div> + ))} + </Autoscroll> + </NoContent> + </PanelLayout.Body> + </> + ); +} + +export default observer(Crashes); \ No newline at end of file diff --git a/frontend/app/components/Session/IOSPlayer/HTMLScreen.css b/frontend/app/components/Session/IOSPlayer/HTMLScreen.css new file mode 100644 index 000000000..fc0c9fd73 --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/HTMLScreen.css @@ -0,0 +1,95 @@ + +.iphone { + position: absolute; + /*margin: 10px auto;*/ + width: 360px; + /*height: calc(100% - 20px);*/ + height: 780px; + /*background-color: #7371ee;*/ + background-image: linear-gradient(60deg, #7371ee 1%,#a1d9d6 100%); + border-radius: 40px; + box-shadow: 0px 0px 0px 11px #1f1f1f, 0px 0px 0px 13px #191919, 0px 0px 0px 20px #111; + + &:before, + &:after{ + content: ''; + position: absolute; + left: 50%; + transform: translateX(-50%); + } + + &:after { + bottom: 7px; + width: 140px; + height: 4px; + background-color: #f2f2f2; + border-radius: 10px; + } + + &:before { + top: 0px; + width: 56%; + height: 30px; + background-color: #1f1f1f; + border-radius: 0px 0px 40px 40px; + } + + i, + b, + span { + position: absolute; + display: block; + color: transparent; + } + + i { + top: 0px; + left: 50%; + transform: translate(-50%, 6px); + height: 8px; + width: 15%; + background-color: #101010; + border-radius: 8px; + box-shadow: inset 0px -3px 3px 0px rgba(256, 256, 256, 0.2); + } + + b { + left: 10%; + top: 0px; + transform: translate(180px, 4px); + width: 12px; + height: 12px; + background-color: #101010; + border-radius: 12px; + box-shadow: inset 0px -3px 2px 0px rgba(256, 256, 256, 0.2); + + &:after { + content: ''; + position: absolute; + background-color: #2d4d76; + width: 6px; + height: 6px; + top: 2px; + left: 2px; + top: 3px; + left: 3px; + display: block; + border-radius: 4px; + box-shadow: inset 0px -2px 2px rgba(0, 0, 0, 0.5); + } + } + + span { + bottom: 50px; + width: 40px; + height: 40px; + background-color: rgba(0, 0, 0, 0.3); + border-radius: 50%; + left: 30px; + + & + span { + left: auto; + right: 30px; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/Session/IOSPlayer/HTMLScreen.js b/frontend/app/components/Session/IOSPlayer/HTMLScreen.js new file mode 100644 index 000000000..d17030d2d --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/HTMLScreen.js @@ -0,0 +1,185 @@ +import { observer } from 'mobx-react-lite'; +import cn from 'classnames'; +import Screen from './ScreenWithLoaders'; +//import cls from './HTMLScreen.css'; + + +const DEVICE_MAP = { + "iPhone 4s": "iphone4s", + "iPhone 5s": "iphone5s", + "iPhone 5c": "iphone5c", + "iPhone 8": "iphone8", + "iPhone 8 Plus": "iphone8plus", + "iPhone X": "iphone-x", +} + +function mapDevice(device) { + if (!!DEVICE_MAP[ device ]) { + return DEVICE_MAP[ device ]; + } + if (device.includes("iPhone")) { + return "iphone8"; // ?? + } + if (device.includes("iPad")) { + return "iPad"; + } + return "macbook"; +} + +function getDefaultColor(type) { + if (type === "iphone5c") { + return "white"; + } + if (type === "iphone-x" || type === "macbook") { + return ""; + } + return "black"; +} + + +function BeforeScreen({ type }) { + if (type === "ipad") { + return <div className="camera"></div> + } + if (type === "iphone-x") { + return ( + <> + <div className="notch"> + <div className="camera"></div> + <div className="speaker"></div> + </div> + <div className="top-bar"></div> + <div className="sleep"></div> + <div className="bottom-bar"></div> + <div className="volume"></div> + <div className="overflow"> + <div className="shadow shadow--tr"></div> + <div className="shadow shadow--tl"></div> + <div className="shadow shadow--br"></div> + <div className="shadow shadow--bl"></div> + </div> + <div className="inner-shadow"></div> + </> + ); + } + if (type === "macbook") { + return ( + <> + <div className="top-bar"></div> + <div className="camera"></div> + </> + ); + } + return ( + <> + <div className="top-bar"></div> + <div className="sleep"></div> + <div className="volume"></div> + <div className="camera"></div> + <div className="sensor"></div> + <div className="speaker"></div> + </> + ); +} + +function AfterScreen({ type }) { + if (type === "ipad") { + return <div className="home"></div>; + } + if (type === "macbook") { + return <div className="bottom-bar"></div>; + } + if (type === "iphone-x") { + return null; + } + return ( + <> + <div className="home"></div> + <div className="bottom-bar"></div> + </> + ); +} + + +function HTMLScreen({ wrapperId, screenId, device, player }) { + const type = mapDevice(device); + const color = getDefaultColor(type); + + return ( + <> + <link rel="stylesheet" type="text/css" href="/marvel-device.css" /> + <div + className={ cn("marvel-device iphone5c", type, color, { "landscape": player.state.orientationLandscape }) } + id={wrapperId} + > + <BeforeScreen type={ type } /> + <Screen className="screen" screenId={screenId} player={player}/> + <AfterScreen type={ type } /> + </div> + {/* <div className={cls.iphone} id={ id }> */} + {/* <i></i> */} + {/* <b></b> */} + {/* <span></span> */} + {/* <span></span> */} + {/* </div> */} + </> + ); +} +export default observer(HTMLScreen); + +// iphone8 iphone8plus iphone5s iphone5c(white) iphone4s +// <div className="marvel-device iphone8 black"> +// <div className="top-bar"></div> +// <div className="sleep"></div> +// <div className="volume"></div> +// <div className="camera"></div> +// <div className="sensor"></div> +// <div className="speaker"></div> +// <div className="screen"> +// <!-- Content goes here --> +// </div> +// <div className="home"></div> +// <div className="bottom-bar"></div> +// </div> +// +// +// <div className="marvel-device iphone-x"> +// <div className="notch"> +// <div className="camera"></div> +// <div className="speaker"></div> +// </div> +// <div className="top-bar"></div> +// <div className="sleep"></div> +// <div className="bottom-bar"></div> +// <div className="volume"></div> +// <div className="overflow"> +// <div className="shadow shadow--tr"></div> +// <div className="shadow shadow--tl"></div> +// <div className="shadow shadow--br"></div> +// <div className="shadow shadow--bl"></div> +// </div> +// <div className="inner-shadow"></div> +// <div className="screen"> +// <!-- Content goes here --> +// </div> +// </div> +// +// <div className="marvel-device ipad silver"> +// <div className="camera"></div> +// <div className="screen"> +// <!-- Content goes here --> +// </div> +// <div className="home"></div> +// </div> +// +// +// <div className="marvel-device macbook"> +// <div className="top-bar"></div> +// <div className="camera"></div> +// <div className="screen"> +// <!-- Content goes here --> +// </div> +// <div className="bottom-bar"></div> +// </div> +// +// diff --git a/frontend/app/components/Session/IOSPlayer/IMGScreen.js b/frontend/app/components/Session/IOSPlayer/IMGScreen.js new file mode 100644 index 000000000..afd75d19a --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/IMGScreen.js @@ -0,0 +1,122 @@ +import { observer } from 'mobx-react-lite'; +import Screen from './ScreenWithLoaders'; +import HTMLScreen from './HTMLScreen'; + +const MODEL_IMG_MAP = { + "iPhone 12" : { + img: "iPhone-12", // 723 × 1396 + screenY: 57, + screenX: 60, + //width: 723, + screenWidth: 588, + foreground: true, + }, + "iPhone 11" : { + img: "iPhone-11", + screenY: 47, + screenX: 45, + screenWidth: 420, + foreground: true, + }, + "iPhone X" : { + img: "iPhone-X", + screenY: 41, + screenX: 42, + screenWidth: 380, + foreground: true, + }, + "iPhone 8" : { + img: "iPhone-8", + screenY: 113, + screenX: 27, + screenWidth: 382, + }, + "iPhone 7" : { + img: "iPhone-7", // 476 × 923 + screenY: 117, + screenX: 43, + screenWidth: 380, + }, + "iPhone 6" : { + img: "iPhone-6", // 540 × 980 + screenY: 149, + screenX: 81, + screenWidth: 376, + }, + "iPad (7th generation)" : { + img: "iPad-7th", // 965 × 1347 + screenY: 122, + screenX: 66, + screenWidth: 812, + foreground: true, + }, + "iPad Pro (12.9-inch)" : { + img: "iPad-pro-12.9-2020", // 1194 × 1536 + screenY: 78, + screenX: 78, + screenWidth: 1025, + foreground: true, + }, + "iPad Pro (11-inch)" : { + img: "iPad-pro-11-2020", // 996 × 1353 + screenY: 73, + screenX: 72, + screenWidth: 836, + foreground: true, + }, + "iPad Air" : { + img: "iPad-Air", + screenY: 162, + screenX: 123, + screenWidth: 768, + }, + "iPad Air 2": { + img: "iPad-Air-2", + screenY: 165, + screenX: 118, + screenWidth: 776, + }, +} + + +function getImgInfo(type) { + let imgInfo; + Object.keys(MODEL_IMG_MAP).map(key => { + if (type.startsWith(key)) { + imgInfo = MODEL_IMG_MAP[key]; + } + }); + return imgInfo; +} + + +function IMGScreen(props) { + const imgInfo = getImgInfo(props.device); + if (!imgInfo) { + return <HTMLScreen {...props } />; + } + const { wrapperId, player, screenId } = props; + + const curScreenWidth = player.state.orientationLandscape ? player.state.height : player.state.width; + return ( + <div id={wrapperId} className="relative"> + <Screen className="absolute inset-0" screenId={ screenId } player={player} /> + <img + className="absolute" + style={{ + maxWidth: 'none', + zIndex: imgInfo.foreground ? 0 : -1, + transformOrigin: `${imgInfo.screenX}px ${imgInfo.screenY}px`, + transform: ` + translate(-${imgInfo.screenX}px, -${imgInfo.screenY}px) + scale(${ curScreenWidth/imgInfo.screenWidth }) + ${player.state.orientationLandscape ? console.log('wtdf') || `rotate(-90deg) translateX(-${imgInfo.screenWidth}px)` : ''} + `, + }} + src={`/img/ios/${imgInfo.img}.png`} + /> + </div> + ); +} + +export default observer(IMGScreen); diff --git a/frontend/app/components/Session/IOSPlayer/Logs.js b/frontend/app/components/Session/IOSPlayer/Logs.js new file mode 100644 index 000000000..2469a7e1a --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/Logs.js @@ -0,0 +1,60 @@ +import { useState, useCallback } from 'react'; +import { observer } from 'mobx-react-lite'; +import { LOGS } from 'Player/ios/state'; +import { getRE } from 'App/utils'; +import { Tabs, Input, NoContent } from 'UI'; +import * as PanelLayout from '../Layout/ToolPanel/PanelLayout'; +import Log from '../Layout/ToolPanel/Log'; + +import Autoscroll from 'Components/Session_/Autoscroll'; + + +const ALL = 'ALL'; +const INFO = 'info'; +const ERROR = 'error'; + +const TABS = [ ALL, INFO, ERROR ].map(tab => ({ text: tab.toUpperCase(), key: tab })); + +function Logs({ player }) { + const [ filter, setFilter ] = useState(""); + const [ activeTab, setTab ] = useState(ALL); + const onInputChange = useCallback(({ target }) => setFilter(target.value)); + const filterRE = getRE(filter, 'i'); + const filtered = player.lists[LOGS].listNow.filter(({ severity, content }) => + (activeTab === ALL || activeTab === severity) && filterRE.test(content) + ); + return ( + <> + <PanelLayout.Header> + <Tabs + tabs={ TABS } + active={ activeTab } + onClick={ setTab } + border={ false } + /> + <Input + className="input-small" + placeholder="Filter" + icon="search" + iconPosition="left" + name="filter" + onChange={ onInputChange } + /> + </PanelLayout.Header> + <PanelLayout.Body> + <NoContent + size="small" + show={ filtered.length === 0 } + > + <Autoscroll> + { filtered.map(log => + <Log text={log.content} level={log.severity}/> + )} + </Autoscroll> + </NoContent> + </PanelLayout.Body> + </> + ); +} + +export default observer(Logs); \ No newline at end of file diff --git a/frontend/app/components/Session/IOSPlayer/Network.css b/frontend/app/components/Session/IOSPlayer/Network.css new file mode 100644 index 000000000..ce8cb5988 --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/Network.css @@ -0,0 +1,11 @@ +.popupNameTrigger { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + max-width: 100%; + width: fit-content; +} +.popupNameContent { + max-width: 600px; + overflow-wrap: break-word; +} diff --git a/frontend/app/components/Session/IOSPlayer/Network.js b/frontend/app/components/Session/IOSPlayer/Network.js new file mode 100644 index 000000000..cf8140740 --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/Network.js @@ -0,0 +1,90 @@ +import { observer } from 'mobx-react-lite'; +import { useState, useCallback } from 'react'; +import { Popup, SlideModal } from 'UI'; + +import { NETWORK } from 'Player/ios/state'; + +import cls from './Network.css'; + +import TimeTable from 'Components/Session_/TimeTable'; +import FetchDetails from 'Components/Session_/Fetch/FetchDetails'; + +const COLUMNS = [ + { + label: "Status", + dataKey: 'status', + width: 70, + }, { + label: "Method", + dataKey: 'method', + width: 60, + }, { + label: "url", + width: 130, + render: (r) => + <Popup + trigger={ <div className={ cls.popupNameTrigger }>{ r.url }</div> } + content={ <div className={ cls.popupNameContent }>{ r.url }</div> } + size="mini" + position="right center" + />, + }, + { + label: "Size", + width: 60, + render: (r) => `${r.body.length}`, + }, + { + label: "Time", + width: 80, + render: (r) => `${r.duration}ms`, + } +]; + + + +function Network({ player }) { + const [ current, setCurrent ] = useState(null); + const [ currentIndex, setCurrentIndex ] = useState(0); + const onRowClick = useCallback((raw, index) => { + setCurrent(raw); + setCurrentIndex(index); + }); + const onNextClick = useCallback(() => { + onRowClick(player.lists[NETWORK].list[currentIndex+1], currentIndex+1) + }); + const onPrevClick = useCallback(() => { + onRowClick(player.lists[NETWORK].list[currentIndex-1], currentIndex-1) + }); + const closeModal = useCallback(() => setCurrent(null)); // TODO: handle in modal + + return ( + <> + <SlideModal + size="middle" + title="Network Request" + isDisplayed={ current != null } + content={ current && + <FetchDetails + resource={ current } + nextClick={ onNextClick } + prevClick={ onPrevClick } + first={ currentIndex === 0 } + last={ currentIndex === player.lists[NETWORK].countNow - 1 } + /> + } + onClose={ closeModal } + /> + <TimeTable + rows={ player.lists[NETWORK].listNow } + hoverable + tableHeight={270} + onRowClick={ onRowClick } + > + { COLUMNS } + </TimeTable> + </> + ); +} + +export default observer(Network); \ No newline at end of file diff --git a/frontend/app/components/Session/IOSPlayer/Performance.js b/frontend/app/components/Session/IOSPlayer/Performance.js new file mode 100644 index 000000000..42d19888f --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/Performance.js @@ -0,0 +1,54 @@ +import cn from 'classnames'; +import { observer } from 'mobx-react-lite'; +import { PERFORMANCE } from 'Player/ios/state'; + +import * as PanelLayout from '../Layout/ToolPanel/PanelLayout'; +import Performance from '../Layout/ToolPanel/Performance'; + + +function Info({ name='', value='', show, className }) { + if (!show) return null; + return ( + <div className={cn("mr-3", className)}> + <span>{name}</span> + <b >{value}</b> + </div> + ); +} + + +export default observer(({ player }) => { + const current = player.lists[PERFORMANCE].current; + return ( + <> + <PanelLayout.Header> + <Info + name="Thermal State" + value={current && current.thermalState} + show={current && ["serious", "critical"].includes(current.thermalState)} + className={current && current.thermalState==="critical" ? "color-red" : "color-orange"} + /> + <Info + name={current && current.activeProcessorCount} + value="Active Processors" + show={current && current.activeProcessorCount != null} + /> + <Info + value="LOW POWER MODE" + show={current && current.isLowPowerModeEnabled} + className="color-red" + /> + + </PanelLayout.Header> + <PanelLayout.Body> + <Performance + performanceChartTime={ current ? current.tmie : 0 } + performanceChartData={ player.lists[PERFORMANCE].list } + avaliability={ player.lists[PERFORMANCE].availability } + hiddenScreenMarker={ false } + player={ player } + /> + </PanelLayout.Body> + </> + ); +}) \ No newline at end of file diff --git a/frontend/app/components/Session/IOSPlayer/ScreenWithLoaders.js b/frontend/app/components/Session/IOSPlayer/ScreenWithLoaders.js new file mode 100644 index 000000000..696eecc7d --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/ScreenWithLoaders.js @@ -0,0 +1,25 @@ +import { observer } from 'mobx-react-lite'; +import cn from 'classnames'; + +import { Loader, CircularLoader } from 'UI'; + + +function ScreenWithLoaders({ player, screenId, className }) { + return ( + <div className={ className } id={screenId}> + <div className={ + cn("absolute inset-0", { + "opacity-75 bg-gray-light": player.loading || player.buffering, + "bg-transparent": !(player.loading || player.buffering), + })} + > + <Loader loading={ player.loading }> + <CircularLoader loading={ player.buffering } inline={false} size="large"/> + </Loader> + </div> + </div> + ); +} + + +export default observer(ScreenWithLoaders); diff --git a/frontend/app/components/Session/IOSPlayer/StackEvents.js b/frontend/app/components/Session/IOSPlayer/StackEvents.js new file mode 100644 index 000000000..92470b358 --- /dev/null +++ b/frontend/app/components/Session/IOSPlayer/StackEvents.js @@ -0,0 +1,11 @@ +import { observer } from 'mobx-react-lite'; +import { CUSTOM } from 'Player/ios/state'; + +import StackEvents from '../Layout/ToolPanel/StackEvents'; + + +export default observer(({ player }) => + <StackEvents + stackEvents={ player.lists[CUSTOM].listNow } + /> +); \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Events.js b/frontend/app/components/Session/Layout/Events.js new file mode 100644 index 000000000..8f1e2c80d --- /dev/null +++ b/frontend/app/components/Session/Layout/Events.js @@ -0,0 +1,20 @@ +import { observer } from 'mobx-react-lite'; +import { EVENTS } from 'Player/ios/state'; + +import EventsBlock from 'Components/Session_/EventsBlock'; + + + +function Events({ style, player }) { + return ( + <EventsBlock + style={style} + playing={ player.playing } + player={ player } + currentTimeEventIndex={ player.lists[EVENTS].countNow - 1 } + /> + ); +} + + +export default observer(Events); \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Header.js b/frontend/app/components/Session/Layout/Header.js new file mode 100644 index 000000000..e3cf2592e --- /dev/null +++ b/frontend/app/components/Session/Layout/Header.js @@ -0,0 +1,98 @@ +import cn from 'classnames'; +import { useEffect } from 'react'; +import { connect } from 'react-redux'; +import { browserIcon, osIcon, deviceTypeIcon } from 'App/iconNames'; +import { formatTimeOrDate } from 'App/date'; +import { sessions as sessionsRoute } from 'App/routes'; +import { CountryFlag, IconButton, BackLink } from 'UI'; +import { toggleFavorite } from 'Duck/sessions'; +import { fetchList as fetchListIntegration } from 'Duck/integrations/actions'; +import SharePopup from 'Shared/SharePopup/SharePopup'; + +import Section from './Header/Section'; +import Resolution from './Header/Resolution'; +import Issues from 'Components/Session_/Issues/Issues'; //TODO replace folder +import cls from './header.css'; + + +const SESSIONS_ROUTE = sessionsRoute(); + +function capitalise(str) { + return str[0].toUpperCase() + str.slice(1); +} + + +function Header({ + player, + session, + loading, + isLocalUTC, + toggleFavorite, + favoriteLoading, + fetchListIntegration, + enableIssues, +}) { + useEffect(() => { + fetchListIntegration('issues'); + }, []); + + return ( + <div className={ cn(cls.header, "flex") }> + <BackLink to={ SESSIONS_ROUTE } label="Back" /> + + <div className={ cls.divider } /> + + <div className="mx-4 flex items-center"> + <CountryFlag country={ session.userCountry } /> + <div className="ml-2 font-normal color-gray-dark mt-1 text-sm"> + { formatTimeOrDate(session.startedAt) } <span>{ isLocalUTC ? 'UTC' : ''}</span> + </div> + </div> + + { !session.isIOS && + <Section icon={ browserIcon(session.userBrowser) } label={ `v${ session.userBrowserVersion }` } /> + } + <Section icon={ deviceTypeIcon(session.userDeviceType) } label={ capitalise(session.userDevice) } /> + { !session.isIOS && + <Section icon="expand-wide" label={ <Resolution player={player} /> } /> + } + <Section icon={ osIcon(session.userOs) } label={ session.isIOS ? session.userOsVersion : session.userOs } /> + + <div className='ml-auto flex items-center'> + <IconButton + className="mr-2" + tooltip="Bookmark" + onClick={ toggleFavorite } + loading={ favoriteLoading } + icon={ session.favorite ? 'star-solid' : 'star' } + plain + /> + <SharePopup + entity="sessions" + id={ session.sessionId } + trigger={ + <IconButton + className="mr-2" + tooltip="Share Session" + disabled={ loading } + icon={ 'share-alt' } + plain + /> + } + /> + { enableIssues && <Issues sessionId={ sessionId } /> } + </div> + </div> + ); +} + + +export default connect((state, props) => ({ + session: state.getIn([ 'sessions', 'current' ]), + favoriteLoading: state.getIn([ 'sessions', 'toggleFavoriteRequest', 'loading' ]), + loading: state.getIn([ 'sessions', 'loading' ]), + enableIssues: !!state.getIn([ 'issues', 'list', 'token' ]), //?? + isLocalUTC: state.getIn(['sessions', 'timezone']) === 'UTC', +}), { + toggleFavorite, fetchListIntegration +})(Header) \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Header/Resolution.js b/frontend/app/components/Session/Layout/Header/Resolution.js new file mode 100644 index 000000000..334c2dfdf --- /dev/null +++ b/frontend/app/components/Session/Layout/Header/Resolution.js @@ -0,0 +1,14 @@ +import { observer } from 'mobx-react-lite'; +import { Icon } from 'UI'; + + +function Resolution ({ player }) { + return ( + <div className="flex items-center"> + { player.state.width || 'x' } <Icon name="close" size="12" className="mx-1" /> { player.state.height || 'x' } + </div> + ); +} + + +export default observer(Resolution); \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Header/Section.js b/frontend/app/components/Session/Layout/Header/Section.js new file mode 100644 index 000000000..1be822c5f --- /dev/null +++ b/frontend/app/components/Session/Layout/Header/Section.js @@ -0,0 +1,11 @@ +import { Icon } from 'UI'; +import styles from './section.css'; + +export default function Section({ icon, label }) { + return ( + <div className="flex items-center mx-4"> + <Icon name={ icon } size="18" color="color-dark" /> + <div className="ml-2 mt-1 font-sm font-normal color-gray-darkest text-sm">{ label }</div> + </div> + ); +}; diff --git a/frontend/app/components/Session/Layout/Header/section.css b/frontend/app/components/Session/Layout/Header/section.css new file mode 100644 index 000000000..b9c3b106c --- /dev/null +++ b/frontend/app/components/Session/Layout/Header/section.css @@ -0,0 +1,8 @@ +.wrapper { + display: flex; + flex-flow: column; + height: 40px; + justify-content: space-between; + font-size: 12px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Layout.js b/frontend/app/components/Session/Layout/Layout.js new file mode 100644 index 000000000..4d7758b82 --- /dev/null +++ b/frontend/app/components/Session/Layout/Layout.js @@ -0,0 +1,45 @@ +import { observer } from 'mobx-react-lite'; +import { useCallback } from 'react'; +import { EscapeButton, Loader } from 'UI'; + +import Header from './Header'; +import ToolPanel from'./ToolPanel'; +import Events from './Events'; +import PlayOverlay from './PlayOverlay'; +import Controls from './Player/Controls'; + + +function Layout({ children, player, toolbar }) { + return ( + <div className="flex flex-col h-screen"> + { !player.fullscreen.enabled && <Header player={player} /> } + <div className="flex-1 flex"> + <div className="flex flex-col" style={{ width: player.fullscreen.enabled ? "100vw" : "calc(100vw - 270px)" }}> + <div + className="flex-1 flex flex-col relative bg-white border-gray-light" + > + { player.fullscreen.enabled && + <EscapeButton onClose={ player.toggleFullscreen } /> + } + <div className="flex-1 relative overflow-hidden" > + {/* <Loader loading={ player.loading }> */} + { children } + {/* </Loader> */} + <PlayOverlay player={player} /> + </div> + <Controls player={ player } toolbar={ toolbar } /> + </div> + { !player.fullscreen.enabled && <ToolPanel player={ player } toolbar={ toolbar }/> } + </div> + { !player.fullscreen.enabled && + <Events + style={{ width: "270px" }} + player={ player } + /> + } + </div> + </div> + ); +} + +export default observer(Layout); \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/PlayOverlay.css b/frontend/app/components/Session/Layout/PlayOverlay.css new file mode 100644 index 000000000..4986ad239 --- /dev/null +++ b/frontend/app/components/Session/Layout/PlayOverlay.css @@ -0,0 +1,14 @@ +.iconWrapper { + background-color: rgba(0, 0, 0, 0.1); + width: 50px; + height: 50px; + border-radius: 50%; + opacity: 0; + transition: all .2s; /* Animation */ +} + +.zoomWrapper { + opacity: 1; + transform: scale(1.8); + transition: all .8s; +} \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/PlayOverlay.js b/frontend/app/components/Session/Layout/PlayOverlay.js new file mode 100644 index 000000000..537460c26 --- /dev/null +++ b/frontend/app/components/Session/Layout/PlayOverlay.js @@ -0,0 +1,30 @@ +import cn from 'classnames'; +import { useCallback, useState } from 'react'; + +import { Icon } from 'UI'; + +import cls from './PlayOverlay.css'; + +export default function PlayOverlay({ player }) { + const [ iconVisible, setIconVisible ] = useState(false); + + const togglePlay = useCallback(() => { + player.togglePlay(); + setIconVisible(true); + setTimeout( + () => setIconVisible(false), + 800, + ); + }); + + return ( + <div + className="absolute inset-0 flex items-center justify-center" + onClick={ togglePlay } + > + <div className={ cn("flex items-center justify-center", cls.iconWrapper, { [ cls.zoomWrapper ]: iconVisible }) } > + <Icon name={ player.state.playing ? "play" : "pause"} size="30" color="gray-medium"/> + </div> + </div> + ); +} diff --git a/frontend/app/components/Session/Layout/Player/ControlButton.js b/frontend/app/components/Session/Layout/Player/ControlButton.js new file mode 100644 index 000000000..feb3cacb1 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/ControlButton.js @@ -0,0 +1,19 @@ +import cn from 'classnames'; +import { Icon } from 'UI'; +import stl from './controlButton.css'; + +export default function ControlButton({ label, icon, onClick, disabled=false, count = 0, hasErrors=false, active=false }) { + return ( + <button + className={ cn(stl.controlButton, { [stl.disabled]: disabled, [stl.active]: active }) } + onClick={ onClick } + > + <div className="relative"> + { count > 0 && <div className={ stl.countLabel }>{ count }</div>} + { hasErrors && <div className={ stl.errorSymbol } /> } + <Icon name={ icon } size="20" color="gray-dark"/> + </div> + <span className={ stl.label }>{ label }</span> + </button> + ); +} diff --git a/frontend/app/components/Session/Layout/Player/Controls.css b/frontend/app/components/Session/Layout/Player/Controls.css new file mode 100644 index 000000000..ec00e8766 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/Controls.css @@ -0,0 +1,41 @@ +@keyframes fade { + 0% { opacity: 1} + 50% { opacity: 0} + 100% { opacity: 1} +} + +.controls { + border-top: solid thin $gray-light; + padding-top: 10px; + padding-bottom: 10px; +} + +.buttons { + margin-top: 7px; + padding: 0 30px; +} + + +.speedButton { + font-size: 14px; + padding: 0 10px; + height: 30px; + border-radius: 3px; + transition: all 0.2s; +} + + +.skipIntervalButton { + transition: all 0.2s; + font-size: 12px; + padding: 0 10px; + height: 30px; + border-radius: 3px; +} + +.divider { + height: 30px; + width: 1px; + margin: 0 5px; + background-color: $gray-light-shade; +} diff --git a/frontend/app/components/Session/Layout/Player/Controls.js b/frontend/app/components/Session/Layout/Player/Controls.js new file mode 100644 index 000000000..9268774d5 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/Controls.js @@ -0,0 +1,136 @@ +import { observer } from 'mobx-react-lite'; +import { useEffect, useCallback } from 'react'; +import { connect } from 'react-redux'; +import cn from 'classnames'; + +import { Popup, Icon } from 'UI'; + +import Timeline from './Timeline'; +import ControlButton from './ControlButton'; + +import cls from './Controls.css'; + + + +function getPlayButtonProps(player) { + let label; + let icon; + if (player.state.completed) { + label = 'Replay'; + icon = 'redo'; + } else if (player.state.playing) { + label = 'Pause'; + icon = 'pause'; + } else { + label = 'Play'; + icon = 'play'; + } + return { + label, + icon, + }; + } + +function Controls({ + player, + toolbar, +}) { + useEffect(() => { + function onKeyDown(e) { + if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) { + return; + } + if (e.key === 'Esc' || e.key === 'Escape') { + player.fullscreen.disable(); + } + if (player.controlsDisabled) { + return; + } + if (e.key === ' ') { + document.activeElement.blur(); + player.togglePlay(); + } + if (e.key === "ArrowRight") { + player.forthTenSeconds(); + } + if (e.key === "ArrowLeft") { + player.backTenSeconds(); + } + if (e.key === "ArrowDown") { + player.speedDown(); + } + if (e.key === "ArrowUp") { + player.speedUp(); + } + } + document.addEventListener('keydown', onKeyDown); + return () => { + document.removeEventListener('keydown', onKeyDown); + } + }, []); + + const disabled = player.controlsDisabled; + return ( + <div className={ cls.controls }> + <Timeline player={ player } /> + { !player.isFullscreen && + <div className={ cn("flex justify-between items-center", cls.buttons) } > + <div className="flex items-center"> + <ControlButton + disabled={ disabled } + onClick={ player.togglePlay } + { ...getPlayButtonProps(player) } + /> + <ControlButton + onClick={ player.backTenSeconds } + disabled={ disabled } + label="Back" + icon="replay-10" + /> + </div> + <div className="flex items-center"> + <button + className={ cn("text-gray-darkest hover:bg-gray-lightest", cls.speedButton) } + onClick={ player.toggleSpeed } + data-disabled={ disabled } + > + <div>{ player.state.speed + 'x' }</div> + </button> + {/* <div className={ cls.divider } /> */} + {/* <button */} + {/* className={ cn("flex items-center text-gray-darkest hover:bg-gray-lightest", cls.skipIntervalButton) } */} + {/* onClick={ player.toggleSkip } */} + {/* data-disabled={ disabled } */} + {/* > */} + {/* { player.isSkippingInactivity && <Icon name="check" color="gray-dark" /> } */} + {/* { 'Skip Inactivity' } */} + {/* </button> */} + <div className={ cls.divider } /> + { toolbar.map(({ key, label, icon, hasErrors=false, showCount = true }) => + <ControlButton + key={ key } + disabled={ disabled || player.lists[key].count === 0 } + onClick={ () => player.togglePanel(key) } + active={ player.toolPanel.key === key } + label={ label } + icon={ icon } + count={ showCount && player.lists[key].countNow } + hasErrors={ hasErrors } + /> + )} + + <ControlButton + disabled={ disabled } + onClick={ player.toggleFullscreen } + active={ player.fullscreen.enabled } + label="Full Screen" + icon="fullscreen" + /> + </div> + </div> + } + </div> + ); +} + +export default observer(Controls); \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Player/PlayerTime.js b/frontend/app/components/Session/Layout/Player/PlayerTime.js new file mode 100644 index 000000000..7833bbce9 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/PlayerTime.js @@ -0,0 +1,14 @@ +import { observer } from 'mobx-react-lite'; +import { Duration } from 'luxon'; +import styles from './playerTime.css'; + +function PlayerTime({ player, timeKey }) { + return ( + <div className={ styles.time }> + { Duration.fromMillis(player.state[timeKey]).toFormat('m:ss') } + </div> + ); +} + +export default observer(PlayerTime); + diff --git a/frontend/app/components/Session/Layout/Player/TimeTracker.js b/frontend/app/components/Session/Layout/Player/TimeTracker.js new file mode 100644 index 000000000..eae547250 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/TimeTracker.js @@ -0,0 +1,21 @@ +import { observer } from 'mobx-react-lite'; +import { connectPlayer } from 'Player'; +import cls from './timeTracker.css'; + + +function TimeTracker({ player, scale }) { + return ( + <> + <div + className={ cls.positionTracker } + style={ { left: `${ player.state.time * scale }%` } } + /> + <div + className={ cls.playedTimeline } + style={ { width: `${ player.state.time * scale }%` } } + /> + </> + ); +} + +export default observer(TimeTracker); \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Player/Timeline.js b/frontend/app/components/Session/Layout/Player/Timeline.js new file mode 100644 index 000000000..5f05834ee --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/Timeline.js @@ -0,0 +1,63 @@ +import { useCallback } from 'react'; +import cn from 'classnames'; +import { Popup } from 'UI'; + +import { CRASHES, EVENTS } from 'Player/ios/state'; + +import TimeTracker from './TimeTracker'; +import PlayerTime from './PlayerTime'; + +import cls from './timeline.css'; + +export default function Timeline({ player }) { + + const seekProgress = useCallback((e) => { + if (player.controlsDisabled) { + return; + } + const p = e.nativeEvent.offsetX / e.target.offsetWidth; + const time = Math.max(Math.round(p * player.state.endTime), 0); + player.jump(time); + }); + const scale = 100 / player.state.endTime; + return ( + <div className="flex items-center" > + <PlayerTime player={player} timeKey="time"/> + <div className={ cn(cls.progress, "relative flex items-center") } onClick={ seekProgress }> + <TimeTracker player={ player } scale={ scale } /> + <div className={ cn("flex items-center", cls.timeline) }/> + { player.lists[EVENTS].list.map(e => ( + <div + key={ e.key } + className={ cls.event } + style={ { left: `${ e.time * scale }%` } } + /> + ))} + { player.lists[CRASHES].list.map(e => ( + <Popup + key={ e.key } + offset="-19" + pinned + className="error" + trigger={ + <div + key={ e.key } + className={ cn(cls.markup, cls.error) } + style={ { left: `${ e.time * scale }%` } } + // onClick={ } + /> + } + content={ + <div className={ cls.popup } > + <b>{ `Crash ${e.name}:` }</b> + <br/> + <span>{ e.reason }</span> + </div> + } + /> + ))} + </div> + <PlayerTime player={player} timeKey="endTime"/> + </div> + ); +} \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Player/controlButton.css b/frontend/app/components/Session/Layout/Player/controlButton.css new file mode 100644 index 000000000..90d85a359 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/controlButton.css @@ -0,0 +1,55 @@ + +.controlButton { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 5px 10px; + cursor: pointer; + min-width: 60px; + position: relative; + border-radius: 3px; + &.active, &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + + & .errorSymbol { + width: 6px; + height: 6px; + border-radius: 3px; + background-color: red; + top: 12px; + left: 23px; + position: absolute; + } + + & .countLabel { + position: absolute; + top: -6px; + left: 12px; + background-color: $gray-dark; + color: white; + font-size: 9px; + font-weight: 300; + min-width: 20px; + height: 16px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + padding: 3px; + } + + & .label { + /* padding-top: 5px; */ + font-size: 10px; + color: $gray-darkest; + height: 16px; + } + + &.disabled { + pointer-events: none; + opacity: 0.5; + } +} \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Player/playerTime.css b/frontend/app/components/Session/Layout/Player/playerTime.css new file mode 100644 index 000000000..e72993bf8 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/playerTime.css @@ -0,0 +1,4 @@ +.time { + padding: 0 12px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Player/timeTracker.css b/frontend/app/components/Session/Layout/Player/timeTracker.css new file mode 100644 index 000000000..2e2137da3 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/timeTracker.css @@ -0,0 +1,23 @@ +@import 'zindex.css'; + +.positionTracker { + width: 15px; + height: 15px; + border: solid 1px $teal; + margin-left: -7px; + border-radius: 50%; + background-color: $active-blue; + position: absolute; + left: 0; + z-index: $positionTracker; + pointer-events: none; /* temporary. DnD should be */ +} + +.playedTimeline { + height: 100%; + border-radius: 4px; + background-color: $teal; + pointer-events: none; + height: 2px; + z-index: 1; +} \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/Player/timeline.css b/frontend/app/components/Session/Layout/Player/timeline.css new file mode 100644 index 000000000..b9e153e96 --- /dev/null +++ b/frontend/app/components/Session/Layout/Player/timeline.css @@ -0,0 +1,66 @@ +.progress { + height: 10px; + border-radius: 1px; + background: transparent; + cursor: pointer; + width: 100%; +} + +.timeline { + border-radius: 5px; + overflow: hidden; + position: absolute; + left: 0; + right: 0; + height: 2px; + background-color: $gray-light; +} + + +.event { + position: absolute; + width: 8px; + height: 8px; + border: solid 1px white; + margin-left: -4px; + border-radius: 50%; + background: rgba(136, 136, 136, 0.8); + pointer-events: none; +} + +.popup { + max-width: 300px !important; + overflow: hidden; + text-overflow: ellipsis; + & span { + display: block; + max-height: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.markup { + position: absolute; + width: 2px; + height: 8px; + border-radius: 2px; + margin-left: -1px; +} + +.markup.log { + background: $blue; +} + +.markup.error { + background: $red; +} + +.markup.warning { + background: $orange; +} + +.markup.info { + background: $blue2; +} \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/ToolPanel.js b/frontend/app/components/Session/Layout/ToolPanel.js new file mode 100644 index 000000000..7e13fba02 --- /dev/null +++ b/frontend/app/components/Session/Layout/ToolPanel.js @@ -0,0 +1,23 @@ +import { useCallback } from 'react'; +import { observer } from 'mobx-react-lite'; +import { CloseButton } from 'UI'; + + +function ToolPanel({ toolbar, player }) { + const currentKey = player.toolPanel.key; + const tool = toolbar.find(p => p.key === currentKey); + if (!tool) { + return null; + } + return ( + <div + className="relative bg-white mb-2 border-gray-light" + style={{ height: '300px' }} // Using style is ok for the unique-on-page elements + > + <CloseButton onClick={ player.closePanel } size="18" className="absolute top-0 right-0 z-10 p-2 bg-white rounded-full border opacity-25 hover:opacity-100" /> + <tool.Component player={ player } /> + </div> + ); +} + +export default observer(ToolPanel); \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/ToolPanel/Log.css b/frontend/app/components/Session/Layout/ToolPanel/Log.css new file mode 100644 index 000000000..5b5b2db7a --- /dev/null +++ b/frontend/app/components/Session/Layout/ToolPanel/Log.css @@ -0,0 +1,10 @@ +.line { + padding: 7px 0 7px 15px; +} + +.message { + font-size: 13px; + &::-webkit-scrollbar { + height: 2px; + } +} diff --git a/frontend/app/components/Session/Layout/ToolPanel/Log.js b/frontend/app/components/Session/Layout/ToolPanel/Log.js new file mode 100644 index 000000000..3aec11331 --- /dev/null +++ b/frontend/app/components/Session/Layout/ToolPanel/Log.js @@ -0,0 +1,49 @@ +import cn from 'classnames'; +import { Icon } from 'UI'; + +import cls from './Log.css'; + + +function getIconProps(level) { + switch (level) { + case "info": + return { + name: 'console/info', + color: 'blue2', + }; + case "warn": + return { + name: 'console/warning', + color: 'red2', + }; + case "error": + return { + name: 'console/error', + color: 'red', + }; + } + return null; +}; + + +function renderWithNL(s = '') { + if (typeof s !== 'string') return ''; + return s.split('\n').map((line, i) => <div className={ cn({ "ml-20": i !== 0 }) }>{ line }</div>) +} + + +/* + level is "info"/"warn"/"error" +*/ +export default function Log({ text, level, onClick }) { + return ( + <div + className={ cn("flex items-start font-mono cursor-pointer border-b border-gray-light-shade", cls.line, level) } + data-scroll-item={ level === "error" } + onClick={ onClick } + > + <Icon size="14" className="pt-1" { ...getIconProps(level) } /> + <div className={ cn("overflow-y-auto ml-20", cls.message)}>{ renderWithNL(text) }</div> + </div> + ); +} \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/ToolPanel/PanelLayout.js b/frontend/app/components/Session/Layout/ToolPanel/PanelLayout.js new file mode 100644 index 000000000..69737b97f --- /dev/null +++ b/frontend/app/components/Session/Layout/ToolPanel/PanelLayout.js @@ -0,0 +1,25 @@ +import cn from 'classnames'; + +export function Header({ + children, + className, +}) { + return ( + <div + className={ cn("flex items-center justify-between border-bottom-gray-light pr-10 pl-2", className) } + style={{ height: "14%" }} + > + { children } + </div> + ); +} + + +export function Body({ children }) { + return ( + <div style={{ height: "86%" }}> + { children } + </div> + ); +} + diff --git a/frontend/app/components/Session/Layout/ToolPanel/Performance.js b/frontend/app/components/Session/Layout/ToolPanel/Performance.js new file mode 100644 index 000000000..295085e46 --- /dev/null +++ b/frontend/app/components/Session/Layout/ToolPanel/Performance.js @@ -0,0 +1,634 @@ +import { connect } from 'react-redux'; +import { + AreaChart, + Area, + ComposedChart, + Line, + XAxis, + YAxis, + Tooltip, + ResponsiveContainer, + ReferenceLine, + CartesianGrid, + Label, +} from 'recharts'; +import { Checkbox } from 'UI'; +import { durationFromMsFormatted } from 'App/date'; +import { formatBytes } from 'App/utils'; + + +const tooltipWrapperClass = "bg-white rounded border px-2 py-1"; + +const CPU_VISUAL_OFFSET = 10; + +const FPS_COLOR = '#C5E5E7'; +const FPS_STROKE_COLOR = "#92C7CA"; +const FPS_LOW_COLOR = "pink"; +const FPS_VERY_LOW_COLOR = "red"; +const CPU_COLOR = "#A8D1DE"; +const CPU_STROKE_COLOR = "#69A5B8"; +const BATTERY_COLOR = "orange"; +const BATTERY_STROKE_COLOR = "orange"; +const USED_HEAP_COLOR = '#A9ABDC'; +const USED_HEAP_STROKE_COLOR = "#8588CF"; +const TOTAL_HEAP_STROKE_COLOR = '#4A4EB7'; +const NODES_COUNT_COLOR = "#C6A9DC"; +const NODES_COUNT_STROKE_COLOR = "#7360AC"; +const HIDDEN_SCREEN_COLOR = "#CCC"; + + +const CURSOR_COLOR = "#394EFF"; + +const Gradient = ({ color, id }) => ( + <linearGradient id={ id } x1="-1" y1="0" x2="0" y2="1"> + <stop offset="5%" stopColor={ color } stopOpacity={ 0.7 } /> + <stop offset="95%" stopColor={ color } stopOpacity={ 0.2 } /> + </linearGradient> +); + + +const TOTAL_HEAP = "Allocated Heap"; +const USED_HEAP = "JS Heap"; +const FPS = "Framerate"; +const CPU = "CPU Load"; +const MEMORY = "Memory Usage"; +const BATTERY = "Battery Charge"; +const NODES_COUNT = "Nodes Сount"; + + +const FPSTooltip = ({ active, payload }) => { + if (!active || payload.length < 3) { + return null; + } + if (payload[0].value === null) { + return ( + <div className={ tooltipWrapperClass } style={{ color: HIDDEN_SCREEN_COLOR }}> + {"Page is not active. User switched the tab or hid the window."} + </div> + ); + } + + let style; + if (payload[1].value != null && payload[1].value > 0) { + style = { color: FPS_LOW_COLOR }; + } + if (payload[2].value != null && payload[2].value > 0) { + style = { color: FPS_VERY_LOW_COLOR }; + } + + return ( + <div className={ tooltipWrapperClass } style={ style }> + <span className="font-medium">{`${ FPS }: `}</span> + { Math.trunc(payload[0].value) } + </div> + ); +}; + +const CPUTooltip = ({ active, payload }) => { + if (!active || payload.length < 1 || payload[0].value === null) { + return null; + } + return ( + <div className={ tooltipWrapperClass } > + <span className="font-medium">{`${ CPU }: `}</span> + { payload[0].value - CPU_VISUAL_OFFSET } + {"%"} + </div> + ); +}; + +const HeapTooltip = ({ active, payload }) => { + if (!active || payload.length < 2) return null; + return ( + <div className={ tooltipWrapperClass } > + <p> + <span className="font-medium">{`${ TOTAL_HEAP }: `}</span> + { formatBytes(payload[0].value)} + </p> + <p> + <span className="font-medium">{`${ USED_HEAP }: `}</span> + { formatBytes(payload[1].value)} + </p> + </div> + ); +} + +const MemoryTooltip = ({ active, payload}) => { + if (!active || payload.length < 1) return null; + return ( + <div className={ tooltipWrapperClass } > + <span className="font-medium">{`${ MEMORY }: `}</span> + { formatBytes(payload[0].value)} + </div> + ); +} + +const BatteryTooltip = ({ active, payload}) => { + if (!active || payload.length < 1 || payload[0].value === null) { + return null; + } + return ( + <div className={ tooltipWrapperClass } > + <span className="font-medium">{`${ BATTERY }: `}</span> + { payload[0].value } + {"%"} + </div> + ); +} + +const NodesCountTooltip = ({ active, payload } ) => { + if (!active || payload.length === 0) return null; + return ( + <div className={ tooltipWrapperClass } > + <p> + <span className="font-medium">{`${ NODES_COUNT }: `}</span> + { payload[0].value } + </p> + </div> + ); +} + +const TICKS_COUNT = 10; +function generateTicks(data: Array<Timed>): Array<number> { + if (data.length === 0) return []; + console.log(data, data[0]) + const minTime = data[0].time; + const maxTime = data[data.length-1].time; + + const ticks = []; + const tickGap = (maxTime - minTime) / (TICKS_COUNT + 1); + for (let i = 0; i < TICKS_COUNT; i++) { + const tick = tickGap * (i + 1) + minTime; + ticks.push(tick); + } + return ticks; +} + +const LOW_FPS = 30; +const VERY_LOW_FPS = 20; +const LOW_FPS_MARKER_VALUE = 5; +const HIDDEN_SCREEN_MARKER_VALUE = 20; +function adaptForGraphics(data) { + return data.map((point, i) => { + let fpsVeryLowMarker = null; + let fpsLowMarker = null; + let hiddenScreenMarker = 0; + if (point.fps != null) { + fpsVeryLowMarker = 0; + fpsLowMarker = 0; + if (point.fps < VERY_LOW_FPS) { + fpsVeryLowMarker = LOW_FPS_MARKER_VALUE; + } else if (point.fps < LOW_FPS) { + fpsLowMarker = LOW_FPS_MARKER_VALUE; + } + } + if (point.fps == null || + (i > 0 && data[i - 1].fps == null) //|| + //(i < data.length-1 && data[i + 1].fps == null) + ) { + hiddenScreenMarker = HIDDEN_SCREEN_MARKER_VALUE; + } + if (point.cpu != null) { + point.cpu += CPU_VISUAL_OFFSET; + } + return { + ...point, + fpsLowMarker, + fpsVeryLowMarker, + hiddenScreenMarker, + } + }); +} + +export default class Performance extends React.PureComponent { + _timeTicks = generateTicks(this.props.performanceChartData) + _data = adaptForGraphics(this.props.performanceChartData) + + onDotClick = ({ index }) => { + const point = this._data[index]; + if (!!point) { + this.props.player.jump(point.time); + } + } + + onChartClick = (e) => { + if (e === null) return; + const { activeTooltipIndex } = e; + const point = this._data[activeTooltipIndex]; + if (!!point) { + this.props.player.jump(point.time); + } + } + + render() { + const { + performanceChartTime, + avaliability = {}, + hiddenScreenMarker = true, + } = this.props; + const { fps, cpu, heap, nodes, memory, battery } = avaliability; + const avaliableCount = [ fps, cpu, heap, nodes, memory, battery ].reduce((c, av) => av ? c + 1 : c, 0); + const height = avaliableCount === 0 ? "0" : `${100 / avaliableCount}%`; + + return ( + <> + { fps && + <ResponsiveContainer height={ height }> + <AreaChart + onClick={ this.onChartClick } + data={this._data} + syncId="s" + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + > + <defs> + <Gradient id="fpsGradient" color={ FPS_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="1 1" stroke="#ddd" horizontal={ false } /> */} + {/* <CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={ false } + tickFormatter={ durationFromMsFormatted } + tick={{ fontSize: "12px" }} + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="FPS" position="insideRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={ false } + tick={ false } + mirror + domain={[0, 85]} + /> + {/* <YAxis */} + {/* yAxisId="r" */} + {/* axisLine={ false } */} + {/* tick={ false } */} + {/* mirror */} + {/* domain={[0, 120]} */} + {/* orientation="right" */} + {/* /> */} + <Area + dataKey="fps" + type="stepBefore" + stroke={FPS_STROKE_COLOR} + fill="url(#fpsGradient)" + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <Area + dataKey="fpsLowMarker" + type="stepBefore" + stroke="none" + fill={ FPS_LOW_COLOR } + activeDot={false} + isAnimationActive={ false } + /> + <Area + dataKey="fpsVeryLowMarker" + type="stepBefore" + stroke="none" + fill={ FPS_VERY_LOW_COLOR } + activeDot={false} + isAnimationActive={ false } + /> + { hiddenScreenMarker && + <Area + dataKey="hiddenScreenMarker" + type="stepBefore" + stroke="none" + fill={ HIDDEN_SCREEN_COLOR } + activeDot={false} + isAnimationActive={ false } + /> + } + {/* <Area */} + {/* yAxisId="r" */} + {/* dataKey="cpu" */} + {/* type="monotone" */} + {/* stroke={CPU_COLOR} */} + {/* fill="none" */} + {/* // fill="url(#fpsGradient)" */} + {/* dot={false} */} + {/* activeDot={{ */} + {/* onClick: this.onDotClick, */} + {/* style: { cursor: "pointer" }, */} + {/* }} */} + {/* isAnimationActive={ false } */} + {/* /> */} + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={FPSTooltip} + filterNull={ false } + /> + </AreaChart> + </ResponsiveContainer> + } + { cpu && + <ResponsiveContainer height={ height }> + <AreaChart + onClick={ this.onChartClick } + data={this._data} + syncId="s" + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + > + <defs> + <Gradient id="cpuGradient" color={ CPU_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={false} + tickFormatter={()=> ""} + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="CPU" position="insideRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={ false } + tick={ false } + mirror + domain={[ 0, 120]} + orientation="right" + /> + <Area + dataKey="cpu" + type="monotone" + stroke={CPU_STROKE_COLOR} + // fill="none" + fill="url(#cpuGradient)" + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + { hiddenScreenMarker && + <Area + dataKey="hiddenScreenMarker" + type="stepBefore" + stroke="none" + fill={ HIDDEN_SCREEN_COLOR } + activeDot={false} + isAnimationActive={ false } + /> + } + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={CPUTooltip} + filterNull={ false } + /> + </AreaChart> + </ResponsiveContainer> + } + { battery && + <ResponsiveContainer height={ height }> + <AreaChart + onClick={ this.onChartClick } + data={this._data} + syncId="s" + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + > + <defs> + <Gradient id="batteryGrad" color={ BATTERY_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={false} + tickFormatter={()=> ""} + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="BATTERY" position="insideTopRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={ false } + tick={ false } + mirror + domain={[ 0, 120]} + orientation="right" + /> + <Area + dataKey="battery" + type="monotone" + stroke={BATTERY_STROKE_COLOR} + // fill="none" + fill="url(#batteryGrad)" + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={BatteryTooltip} + filterNull={ false } + /> + </AreaChart> + </ResponsiveContainer> + } + { memory && + <ResponsiveContainer height={ height }> + <AreaChart + onClick={ this.onChartClick } + data={this._data} + syncId="s" + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + > + <defs> + <Gradient id="usedHeapGradient" color={ USED_HEAP_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={false} + tickFormatter={()=> ""} + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="MEMORY" position="insideTopRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={false} + tickFormatter={formatBytes} + mirror + // Hack to keep only end tick + minTickGap={Number.MAX_SAFE_INTEGER} + domain={[0, max => max*1.2]} + /> + <Area + dataKey="memory" + type="monotone" + stroke={USED_HEAP_STROKE_COLOR} + // fill="none" + fill="url(#usedHeapGradient)" + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={MemoryTooltip} + filterNull={ false } + /> + </AreaChart> + </ResponsiveContainer> + } + + { heap && + <ResponsiveContainer height={ height }> + <ComposedChart + onClick={ this.onChartClick } + data={this._data} + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + syncId="s" + > + <defs> + <Gradient id="usedHeapGradient" color={ USED_HEAP_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="1 1" stroke="#ddd" horizontal={ false } /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={false} + tickFormatter={()=> ""} // tick={false} + this._timeTicks to cartesian array + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="HEAP" position="insideRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={false} + tickFormatter={formatBytes} + mirror + // Hack to keep only end tick + minTickGap={Number.MAX_SAFE_INTEGER} + domain={[0, max => max*1.2]} + /> + <Line + type="monotone" + dataKey="totalHeap" + // fill="url(#totalHeapGradient)" + stroke={TOTAL_HEAP_STROKE_COLOR} + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <Area + dataKey="usedHeap" + type="monotone" + fill="url(#usedHeapGradient)" + stroke={USED_HEAP_STROKE_COLOR} + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={HeapTooltip} + filterNull={ false } + /> + </ComposedChart> + </ResponsiveContainer> + } + { nodes && + <ResponsiveContainer height={ height }> + <AreaChart + onClick={ this.onChartClick } + data={this._data} + syncId="s" + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + > + <defs> + <Gradient id="nodesGradient" color={ NODES_COUNT_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="1 1" stroke="#ddd" horizontal={ false } /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={false} + tickFormatter={()=> ""} + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="NODES" position="insideRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={ false } + tick={ false } + mirror + orientation="right" + domain={[0, max => max*1.2]} + /> + <Area + dataKey="nodesCount" + type="monotone" + stroke={NODES_COUNT_STROKE_COLOR} + // fill="none" + fill="url(#nodesGradient)" + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={NodesCountTooltip} + filterNull={ false } + /> + </AreaChart> + </ResponsiveContainer> + } + </> + ); + } +} diff --git a/frontend/app/components/Session/Layout/ToolPanel/StackEvents.js b/frontend/app/components/Session/Layout/ToolPanel/StackEvents.js new file mode 100644 index 000000000..0c10a38d1 --- /dev/null +++ b/frontend/app/components/Session/Layout/ToolPanel/StackEvents.js @@ -0,0 +1,72 @@ +import { connect } from 'react-redux'; +import { useState } from 'react'; +import { NoContent, Tabs } from 'UI'; +import withEnumToggle from 'HOCs/withEnumToggle'; +import { hideHint } from 'Duck/components/player'; +import { typeList } from 'Types/session/stackEvent'; +import * as PanelLayout from './PanelLayout'; + +import UserEvent from 'Components/Session_/StackEvents/UserEvent'; +import Autoscroll from 'Components/Session_/Autoscroll'; + +const ALL = 'ALL'; + +const TABS = [ ALL, ...typeList ].map(tab =>({ text: tab, key: tab })); + +function StackEvents({ + stackEvents, + hintIsHidden, + hideHint, +}) { + const [ activeTab, setTab ] = useState(ALL); + const tabs = TABS.filter(({ key }) => key === ALL || stackEvents.some(({ source }) => key === source)); // Do it once for all when we show them all + + const filteredStackEvents = stackEvents + .filter(({ source }) => activeTab === ALL || activeTab === source); + + return ( + <> + <PanelLayout.Header> + <Tabs + className="uppercase" + tabs={ tabs } + active={ activeTab } + onClick={ setTab } + border={ false } + /> + </PanelLayout.Header> + <PanelLayout.Body> + <NoContent + title="Nothing to display yet." + subtext={ !hintIsHidden + ? + <> + <a className="underline color-teal" href="https://docs.openreplay.com/integrations" target="_blank">Integrations</a> + {' and '} + <a className="underline color-teal" href="https://docs.openreplay.com/api#event" target="_blank">Events</a> + { ' make debugging easier. Sync your backend logs and custom events with session replay.' } + <br/><br/> + <button className="color-teal" onClick={() => hideHint("stack")}>Got It!</button> + </> + : null + } + size="small" + show={ filteredStackEvents.length === 0 } + > + <Autoscroll> + { filteredStackEvents.map(userEvent => ( + <UserEvent key={ userEvent.key } userEvent={ userEvent }/> + ))} + </Autoscroll> + </NoContent> + </PanelLayout.Body> + </> + ); +} + +export default connect(state => ({ + hintIsHidden: state.getIn(['components', 'player', 'hiddenHints', 'stack']) || + !state.getIn([ 'user', 'client', 'sites' ]).some(s => s.stackIntegrations), +}), { + hideHint +})(StackEvents); \ No newline at end of file diff --git a/frontend/app/components/Session/Layout/header.css b/frontend/app/components/Session/Layout/header.css new file mode 100644 index 000000000..325e34256 --- /dev/null +++ b/frontend/app/components/Session/Layout/header.css @@ -0,0 +1,14 @@ +.header { + height: 50px; + border-bottom: solid thin $gray-light; + padding: 10px 15px; + background-color: white; +} + +.divider { + width: 1px; + height: 100%; + margin: 0 15px; + background-color: $gray-light; +} + diff --git a/frontend/app/components/Session/Session.js b/frontend/app/components/Session/Session.js new file mode 100644 index 000000000..27c87875c --- /dev/null +++ b/frontend/app/components/Session/Session.js @@ -0,0 +1,69 @@ +import { useEffect } from 'react'; +import { connect } from 'react-redux'; +import usePageTitle from 'App/hooks/usePageTitle'; +import { fetch as fetchSession } from 'Duck/sessions'; +import { fetchList as fetchSlackList } from 'Duck/integrations/slack'; +import { Link, NoContent, Loader } from 'UI'; +import { sessions as sessionsRoute } from 'App/routes'; + +import WebPlayer from './WebPlayer'; +import IOSPlayer from './IOSPlayer'; + +const SESSIONS_ROUTE = sessionsRoute(); + +function Session({ + sessionId, + loading, + hasErrors, + session, + fetchSession, + fetchSlackList, + }) { + usePageTitle("OpenReplay Session Player"); + useEffect(() => { + fetchSlackList() + }, []); + useEffect(() => { + if (sessionId != null) { + fetchSession(sessionId) + } else { + console.error("No sessionID in route.") + } + return () => { + if (!session.exists()) return; + } + },[ sessionId ]); + + return ( + <NoContent + show={ hasErrors } + title="Session not found." + subtext={ + <span> + {'Please check your data retention plan, or try '} + <Link to={ SESSIONS_ROUTE }>{'another one'}</Link> + </span> + } + > + <Loader className="flex-1" loading={ loading || sessionId !== session.sessionId }> + { session.isIOS + ? <IOSPlayer session={session} /> + : <WebPlayer /> + } + </Loader> + </NoContent> + ); +} + +export default connect((state, props) => { + const { match: { params: { sessionId } } } = props; + return { + sessionId, + loading: state.getIn([ 'sessions', 'loading' ]), + hasErrors: !!state.getIn([ 'sessions', 'errors' ]), + session: state.getIn([ 'sessions', 'current' ]), + }; +}, { + fetchSession, + fetchSlackList, +})(Session); \ No newline at end of file diff --git a/frontend/app/components/Session/WebPlayer.js b/frontend/app/components/Session/WebPlayer.js new file mode 100644 index 000000000..9cfa607a0 --- /dev/null +++ b/frontend/app/components/Session/WebPlayer.js @@ -0,0 +1,65 @@ +import { useEffect } from 'react'; +import { connect } from 'react-redux'; +import { Loader } from 'UI'; +import { toggleFullscreen, closeBottomBlock } from 'Duck/components/player'; +import { + PlayerProvider, + connectPlayer, + init as initPlayer, + clean as cleanPlayer, +} from 'Player'; +import { Controls as PlayerControls } from 'Player'; + + +import PlayerBlockHeader from '../Session_/PlayerBlockHeader'; +import EventsBlock from '../Session_/EventsBlock'; +import PlayerBlock from '../Session_/PlayerBlock'; +import styles from '../Session_/session.css'; + + + +const EventsBlockConnected = connectPlayer(state => ({ + currentTimeEventIndex: state.eventListNow.length > 0 ? state.eventListNow.length - 1 : 0, + playing: state.playing, +}))(EventsBlock) + + +const InitLoader = connectPlayer(state => ({ + loading: !state.initialized +}))(Loader); + + +function WebPlayer ({ session, toggleFullscreen, closeBottomBlock, live, fullscreen, jwt }) { + useEffect(() => { + initPlayer(session, jwt); + return () => cleanPlayer() + }, [ session.sessionId ]); + + // LAYOUT (TODO: local layout state - useContext or something..) + useEffect(() => () => { + toggleFullscreen(false); + closeBottomBlock(); + }, []) + return ( + <PlayerProvider> + <InitLoader className="flex-1"> + <PlayerBlockHeader fullscreen={fullscreen}/> + <div className={ styles.session } data-fullscreen={fullscreen}> + <PlayerBlock /> + { !live && !fullscreen && <EventsBlockConnected player={PlayerControls}/> } + </div> + </InitLoader> + </PlayerProvider> + ); +} + + +export default connect(state => ({ + session: state.getIn([ 'sessions', 'current' ]), + jwt: state.get('jwt'), + fullscreen: state.getIn([ 'components', 'player', 'fullscreen' ]), +}), { + toggleFullscreen, + closeBottomBlock, +})(WebPlayer) + diff --git a/frontend/app/components/Session_/Autoscroll.js b/frontend/app/components/Session_/Autoscroll.js new file mode 100644 index 000000000..c7a9e60cf --- /dev/null +++ b/frontend/app/components/Session_/Autoscroll.js @@ -0,0 +1,87 @@ +import { IconButton } from 'UI'; +import cn from 'classnames'; +import stl from './autoscroll.css'; + +export default class Autoscroll extends React.PureComponent { + static defaultProps = { + bottomOffset: 10, + } + state = { + autoScroll: true, + } + + componentDidMount() { + if (!this.scrollableElement) return; // is necessary ? + this.scrollableElement.addEventListener('scroll', this.scrollHandler); + this.scrollableElement.scrollTop = this.scrollableElement.scrollHeight; + } + + componentDidUpdate() { + if (!this.scrollableElement) return; // is necessary ? + if (this.state.autoScroll) { + this.scrollableElement.scrollTop = this.scrollableElement.scrollHeight; + } + } + + scrollHandler = (e) => { + if (!this.scrollableElement) return; + this.setState({ + autoScroll: this.scrollableElement.scrollHeight + - this.scrollableElement.clientHeight + - this.scrollableElement.scrollTop < this.props.bottomOffset, + }); + } + + onPrevClick = () => { + if (!this.scrollableElement) return; + const scEl = this.scrollableElement; + let prevItem; + for (let i = scEl.children.length - 1; i >= 0; i--) { + const child = scEl.children[ i ]; + const isScrollable = child.getAttribute("data-scroll-item") === "true"; + if (isScrollable && child.offsetTop < scEl.scrollTop) { + prevItem = child; + break; + } + } + if (!prevItem) return; + scEl.scrollTop = prevItem.offsetTop; + } + + onNextClick = () => { + if (!this.scrollableElement) return; + const scEl = this.scrollableElement; + let nextItem; + for (let i = 0; i < scEl.children.length; i++) { + const child = scEl.children[ i ]; + const isScrollable = child.getAttribute("data-scroll-item") === "true"; + if (isScrollable && child.offsetTop > scEl.scrollTop + 20) { // ? + nextItem = child; + break; + } + } + if (!nextItem) return; + scEl.scrollTop = nextItem.offsetTop; + } + + render() { + const { className, navigation=false, children, ...props } = this.props; + return ( + <div className={ cn("relative w-full h-full", stl.wrapper) } > + <div + { ...props } + className={ cn("relative scroll-y h-full", className) } + ref={ ref => this.scrollableElement = ref } + > + { children } + </div> + { navigation && + <div className={ stl.navButtons } > + <IconButton size="small" icon="chevron-up" onClick={this.onPrevClick} /> + <IconButton size="small" icon="chevron-down" onClick={this.onNextClick} className="mt-5" /> + </div> + } + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/BottomBlock/BottomBlock.js b/frontend/app/components/Session_/BottomBlock/BottomBlock.js new file mode 100644 index 000000000..a541e6095 --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/BottomBlock.js @@ -0,0 +1,17 @@ +import cn from 'classnames'; +import stl from './bottomBlock.css'; + +const BottomBlock = ({ + children, + className, + additionalHeight, + ...props +}) => ( + <div className={ cn(stl.wrapper, "flex flex-col mb-2") } { ...props } > + { children } + </div> +); + +BottomBlock.displayName = 'BottomBlock'; + +export default BottomBlock; diff --git a/frontend/app/components/Session_/BottomBlock/Content.js b/frontend/app/components/Session_/BottomBlock/Content.js new file mode 100644 index 000000000..fc465768b --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/Content.js @@ -0,0 +1,16 @@ +import cn from 'classnames'; +import stl from './content.css'; + +const Content = ({ + children, + className, + ...props +}) => ( + <div className={ cn(className, stl.content) } { ...props } > + { children } + </div> +); + +Content.displayName = 'Content'; + +export default Content; diff --git a/frontend/app/components/Session_/BottomBlock/Header.js b/frontend/app/components/Session_/BottomBlock/Header.js new file mode 100644 index 000000000..addc59c40 --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/Header.js @@ -0,0 +1,25 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { closeBottomBlock } from 'Duck/components/player'; +import { Input, CloseButton } from 'UI'; +import stl from './header.css'; + +const Header = ({ + children, + className, + closeBottomBlock, + onFilterChange, + showClose = true, + ...props +}) => ( + <div className={ cn("relative border-r border-l", stl.header) } > + <div className={ cn("w-full h-full flex justify-between items-center", className) } > + <div className="w-full flex items-center justify-between">{ children }</div> + { showClose && <CloseButton onClick={ closeBottomBlock } size="18" className="ml-2" /> } + </div> + </div> +); + +Header.displayName = 'Header'; + +export default connect(null, { closeBottomBlock })(Header); diff --git a/frontend/app/components/Session_/BottomBlock/InfoLine.js b/frontend/app/components/Session_/BottomBlock/InfoLine.js new file mode 100644 index 000000000..671b3b4aa --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/InfoLine.js @@ -0,0 +1,19 @@ +import cn from 'classnames'; +import cls from './infoLine.css'; + +const InfoLine = ({ children }) => ( + <div className={ cls.info }> + { children } + </div> +) + +const Point = ({ label, value, display=true, color, dotColor }) => display + ? <div className={ cls.infoPoint } style={{ color }}> + { dotColor != null && <div className={ cn(cls.dot, `bg-${dotColor}`) } /> } + <span className={cls.label}>{ `${label}:` }</span> { value } + </div> + : null; + +InfoLine.Point = Point; + +export default InfoLine; diff --git a/frontend/app/components/Session_/BottomBlock/bottomBlock.css b/frontend/app/components/Session_/BottomBlock/bottomBlock.css new file mode 100644 index 000000000..b9ea933e0 --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/bottomBlock.css @@ -0,0 +1,8 @@ + +.wrapper { + background: $white; + /* padding-right: 10px; */ + /* border: solid thin $gray-light; */ + height: 300px; + padding-top: 2px; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/BottomBlock/content.css b/frontend/app/components/Session_/BottomBlock/content.css new file mode 100644 index 000000000..fe8303013 --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/content.css @@ -0,0 +1,3 @@ +.content { + height: 86%; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/BottomBlock/header.css b/frontend/app/components/Session_/BottomBlock/header.css new file mode 100644 index 000000000..99faa61c7 --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/header.css @@ -0,0 +1,6 @@ + +.header { + padding: 0 10px; + height: 40px; + border-bottom: 1px solid $gray-light; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/BottomBlock/index.js b/frontend/app/components/Session_/BottomBlock/index.js new file mode 100644 index 000000000..846d7ec6f --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/index.js @@ -0,0 +1,8 @@ +import BottomBlock from './BottomBlock'; +import Header from './Header'; +import Content from './Content'; + +BottomBlock.Header = Header; +BottomBlock.Content = Content; + +export default BottomBlock; \ No newline at end of file diff --git a/frontend/app/components/Session_/BottomBlock/infoLine.css b/frontend/app/components/Session_/BottomBlock/infoLine.css new file mode 100644 index 000000000..d03a53439 --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/infoLine.css @@ -0,0 +1,31 @@ + + +.info { + padding-left: 10px; + height: 36px; + display: flex; + align-items: center; + & >.infoPoint { + font-size: 12px; + display: flex; + align-items: center; + &:not(:last-child):after { + content: ''; + margin: 0 10px; + height: 30px; + border-right: 1px solid $gray-light-shade; + } + & .label { + font-weight: 500; + margin-right: 3px; + } + } +} + +.dot { + width: 10px; + height: 10px; + border-radius: 5px; + margin-right: 5px; +} + diff --git a/frontend/app/components/Session_/BottomBlock/tabs.js b/frontend/app/components/Session_/BottomBlock/tabs.js new file mode 100644 index 000000000..6addd161e --- /dev/null +++ b/frontend/app/components/Session_/BottomBlock/tabs.js @@ -0,0 +1,9 @@ +// import { NONE, CONSOLE, NETWORK, STACKEVENTS, REDUX_STATE, PROFILER, PERFORMANCE, GRAPHQL } from 'Duck/components/player'; +// +// +// export default { +// [NONE]: { +// Component: null, +// +// } +// } \ No newline at end of file diff --git a/frontend/app/components/Session_/Console/Console.js b/frontend/app/components/Session_/Console/Console.js new file mode 100644 index 000000000..ac58c36c2 --- /dev/null +++ b/frontend/app/components/Session_/Console/Console.js @@ -0,0 +1,123 @@ +// import cn from 'classnames'; +// import { getRE } from 'App/utils'; +// import { Icon, NoContent, Tabs, Input } from 'UI'; +import { connectPlayer, jump } from 'Player'; +// import { LEVEL } from 'Types/session/log'; +// import Autoscroll from '../Autoscroll'; +// import BottomBlock from '../BottomBlock'; +// import stl from './console.css'; +import ConsoleContent from './ConsoleContent'; + + +// const ALL = 'ALL'; +// const INFO = 'INFO'; +// const WARNINGS = 'WARNINGS'; +// const ERRORS = 'ERRORS'; + +// const LEVEL_TAB = { +// [ LEVEL.INFO ]: INFO, +// [ LEVEL.LOG ]: INFO, +// [ LEVEL.WARNING ]: WARNINGS, +// [ LEVEL.ERROR ]: ERRORS, +// [ LEVEL.EXCEPTION ]: ERRORS, +// }; + +// const TABS = [ ALL, INFO, WARNINGS, ERRORS ].map(tab => ({ text: tab, key: tab })); + +// // eslint-disable-next-line complexity +// const getIconProps = (level) => { +// switch (level) { +// case LEVEL.INFO: +// case LEVEL.LOG: +// return { +// name: 'console/info', +// color: 'blue2', +// }; +// case LEVEL.WARNING: +// return { +// name: 'console/warning', +// color: 'red2', +// }; +// case LEVEL.ERROR: +// return { +// name: 'console/error', +// color: 'red', +// }; +// } +// return null; +// }; + +// function renderWithNL(s = '') { +// if (typeof s !== 'string') return ''; +// return s.split('\n').map((line, i) => <div className={ cn({ "ml-20": i !== 0 }) }>{ line }</div>) +// } + +@connectPlayer(state => ({ + logs: state.logList, + time: state.time, +})) +export default class Console extends React.PureComponent { + // state = { + // filter: '', + // activeTab: ALL, + // } + // onTabClick = activeTab => this.setState({ activeTab }) + // onFilterChange = (e, { value }) => this.setState({ filter: value }) + + render() { + const { logs, time } = this.props; + // const { filter, activeTab, currentError } = this.state; + // const filterRE = getRE(filter, 'i'); + // const filtered = logs.filter(({ level, value }) => activeTab === ALL + // ? filterRE.test(value) + // : (filterRE.test(value) && LEVEL_TAB[ level ] === activeTab) + // ); + return ( + <> + <ConsoleContent jump={jump} logs={logs} time={time} /> + {/* <BottomBlock> + <BottomBlock.Header> + <Tabs + tabs={ TABS } + active={ activeTab } + onClick={ this.onTabClick } + border={ false } + /> + <Input + className="input-small" + placeholder="Filter" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + </BottomBlock.Header> + <BottomBlock.Content> + <NoContent + size="small" + show={ filtered.length === 0 } + > + <Autoscroll> + { filtered.map(l => ( + <div + key={ l.key } + className={ cn(stl.line, { + "info": !l.isYellow() && !l.isRed(), + "warn": l.isYellow(), + "error": l.isRed(), + }) } + data-scroll-item={ l.isRed() } + onClick={ () => jump(l.time) } + > + <Icon size="14" className={ stl.icon } { ...getIconProps(l.level) } /> + <div className={ stl.message }>{ renderWithNL(l.value) }</div> + </div> + ))} + </Autoscroll> + </NoContent> + </BottomBlock.Content> + </BottomBlock> */} + </> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Console/ConsoleContent.js b/frontend/app/components/Session_/Console/ConsoleContent.js new file mode 100644 index 000000000..32448dfc3 --- /dev/null +++ b/frontend/app/components/Session_/Console/ConsoleContent.js @@ -0,0 +1,124 @@ +import cn from 'classnames'; +import { getRE } from 'App/utils'; +import { Icon, NoContent, Tabs, Input } from 'UI'; +import { jump } from 'Player'; +import { LEVEL } from 'Types/session/log'; +import Autoscroll from '../Autoscroll'; +import BottomBlock from '../BottomBlock'; +import stl from './console.css'; + + +const ALL = 'ALL'; +const INFO = 'INFO'; +const WARNINGS = 'WARNINGS'; +const ERRORS = 'ERRORS'; + +const LEVEL_TAB = { + [ LEVEL.INFO ]: INFO, + [ LEVEL.LOG ]: INFO, + [ LEVEL.WARNING ]: WARNINGS, + [ LEVEL.ERROR ]: ERRORS, + [ LEVEL.EXCEPTION ]: ERRORS, +}; + +const TABS = [ ALL, INFO, WARNINGS, ERRORS ].map(tab => ({ text: tab, key: tab })); + +// eslint-disable-next-line complexity +const getIconProps = (level) => { + switch (level) { + case LEVEL.INFO: + case LEVEL.LOG: + return { + name: 'console/info', + color: 'blue2', + }; + case LEVEL.WARN: + case LEVEL.WARNING: + return { + name: 'console/warning', + color: 'red2', + }; + case LEVEL.ERROR: + return { + name: 'console/error', + color: 'red', + }; + + } + return null; +}; + +function renderWithNL(s = '') { + if (typeof s !== 'string') return ''; + return s.split('\n').map((line, i) => <div className={ cn({ "ml-20": i !== 0 }) }>{ line }</div>) +} + +export default class ConsoleContent extends React.PureComponent { + state = { + filter: '', + activeTab: ALL, + } + onTabClick = activeTab => this.setState({ activeTab }) + onFilterChange = (e, { value }) => this.setState({ filter: value }) + + render() { + const { logs, isResult, additionalHeight, time } = this.props; + const { filter, activeTab, currentError } = this.state; + const filterRE = getRE(filter, 'i'); + const filtered = logs.filter(({ level, value }) => activeTab === ALL + ? filterRE.test(value) + : (filterRE.test(value) && LEVEL_TAB[ level ] === activeTab) + ); + + const lastIndex = filtered.filter(item => item.time <= time).length - 1; + + return ( + <> + <BottomBlock style={{ height: 300 + additionalHeight + 'px' }}> + <BottomBlock.Header showClose={!isResult}> + <Tabs + tabs={ TABS } + active={ activeTab } + onClick={ this.onTabClick } + border={ false } + /> + <Input + className="input-small" + placeholder="Filter" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + </BottomBlock.Header> + <BottomBlock.Content> + <NoContent + size="small" + show={ filtered.length === 0 } + > + <Autoscroll> + { filtered.map((l, index) => ( + <div + key={ l.key } + className={ cn(stl.line, { + "info": !l.isYellow() && !l.isRed(), + "warn": l.isYellow(), + "error": l.isRed(), + "cursor-pointer": !isResult, + [stl.activeRow] : lastIndex === index + }) } + data-scroll-item={ l.isRed() } + onClick={ () => !isResult && jump(l.time) } + > + <Icon size="14" className={ stl.icon } { ...getIconProps(l.level) } /> + <div className={ stl.message }>{ renderWithNL(l.value) }</div> + </div> + ))} + </Autoscroll> + </NoContent> + </BottomBlock.Content> + </BottomBlock> + </> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Console/console.css b/frontend/app/components/Session_/Console/console.css new file mode 100644 index 000000000..55d19c7bd --- /dev/null +++ b/frontend/app/components/Session_/Console/console.css @@ -0,0 +1,28 @@ + +.message { + overflow-x: auto; + margin-left: 10px; + font-size: 13px; + overflow-x: auto; + &::-webkit-scrollbar { + height: 2px; + } +} + +.line { + font-family: 'Menlo', 'monaco', 'consolas', monospace; + padding: 7px 0 7px 15px; + /* margin-top: -1px; ??? */ + display: flex; + align-items: flex-start; + border-bottom: solid thin $gray-light-shade; +} + +.activeRow { + background-color: $teal !important; + color: white !important; +} + +.icon { + padding-top: 4px; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/AutomateButton.js b/frontend/app/components/Session_/EventsBlock/AutomateButton.js new file mode 100644 index 000000000..19d2eaf92 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/AutomateButton.js @@ -0,0 +1,55 @@ +import { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom'; +import { Loader } from 'semantic-ui-react'; +import { connectPlayer } from 'Player'; +import { testBuilderNew as testBuilderNewRoute } from 'App/routes'; +import { generateTest } from 'Duck/tests'; +import { FRAMEWORKS } from 'App/constants'; +import styles from './automateButton.css'; + +@withRouter +@connectPlayer(state => ({ + playing: state.playing, +})) +@connect((state, props) => ({ + genTestId: state.getIn([ 'tests', 'instance', 'id' ]), + loading: state.getIn([ 'tests', 'genTestRequest', 'loading' ]), + disabled: props.playing || + state.getIn([ 'events', 'selected' ]).size < 2, + selectedEvents: state.getIn([ 'events', 'selected' ]), + sessionId: state.getIn([ 'sessions', 'current', 'sessionId' ]), +}), { + generateTest, +}) +export default class AutomateButton extends React.PureComponent { + generateTest = (framework) => { + const steps = this.props.selectedEvents + .toList() + .sort((e1, e2) => e1.timestamp - e2.timestamp) + .toJS(); + + this.props.generateTest(this.props.sessionId, { + steps, + // framework, + }) + .then(() => this.props.history.push(testBuilderNewRoute())); + } + + generateSeleniumTest = () => this.generateTest(FRAMEWORKS.SELENIUM) + // generateCypressTest = () => this.generateTest(FRAMEWORKS.CYPRESS) + + render() { + const { loading, disabled } = this.props; + return ( + <div className={ styles.automateBtnWrapper } data-disabled={ disabled }> + <div className={ styles.automateButton }> + <a onClick={ this.generateSeleniumTest }> + <Loader active={ loading } inline /> + <div className={ styles.mainText }>{ 'Automate' }</div> + <div className={ styles.subText }>{'Select at Least 2 Events'}</div> + </a> + </div> + </div> + ); + } +} diff --git a/frontend/app/components/Session_/EventsBlock/Event.js b/frontend/app/components/Session_/EventsBlock/Event.js new file mode 100644 index 000000000..512cda6ba --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Event.js @@ -0,0 +1,181 @@ +import copy from 'copy-to-clipboard'; +// import { Checkbox } from 'semantic-ui-react'; +import cn from 'classnames'; +import { Icon, TextEllipsis } from 'UI'; +import { TYPES } from 'Types/session/event'; +import { prorata } from 'App/utils'; +// import { TYPES } from 'Types/session/event'; +import withOverlay from 'Components/hocs/withOverlay'; +import LoadInfo from './LoadInfo'; +import cls from './event.css'; +import { numberWithCommas } from 'App/utils'; + +@withOverlay() +export default class Event extends React.PureComponent { + state = { + menuOpen: false, + } + + componentDidMount() { + this.wrapper.addEventListener('contextmenu', this.onContextMenu); + } + + onContextMenu = (e) => { + e.preventDefault(); + this.setState({ menuOpen: true }); + } + onMouseLeave = () => this.setState({ menuOpen: false }) + + copyHandler = (e) => { + e.stopPropagation(); + //const ctrlOrCommandPressed = e.ctrlKey || e.metaKey; + //if (ctrlOrCommandPressed && e.keyCode === 67) { + const { event } = this.props; + copy(event.getIn([ 'target', 'path' ]) || event.url || ''); + this.setState({ menuOpen: false }); + } + + toggleInfo = (e) => { + e.stopPropagation(); + this.props.toggleInfo(); + } + + // eslint-disable-next-line complexity + renderBody = () => { + const { event } = this.props; + let title = event.type; + let body; + switch (event.type) { + case TYPES.LOCATION: + title = 'Visited'; + body = event.url; + break; + case TYPES.CLICK: + title = 'Clicked'; + body = event.label; + break; + case TYPES.INPUT: + title = 'Input'; + body = event.value; + break; + case TYPES.CLICKRAGE: + title = `${ event.count } Clicks`; + body = event.label; + break; + case TYPES.IOS_VIEW: + title = 'View'; + body = event.name; + break; + } + const isLocation = event.type === TYPES.LOCATION; + const isClickrage = event.type === TYPES.CLICKRAGE; + + return ( + <div className={ cn(cls.main, 'flex flex-col w-full') } > + <div className="flex items-center w-full"> + { event.type && <Icon name={`event/${event.type.toLowerCase()}`} size="16" color={isClickrage? 'red' : 'gray-dark' } /> } + <div className="ml-3 w-full"> + <div className="flex w-full items-first justify-between"> + <div className="flex items-center w-full" style={{ minWidth: '0'}}> + <span className={cls.title}>{ title }</span> + {/* { body && !isLocation && <div className={ cls.data }>{ body }</div> } */} + { body && !isLocation && + <TextEllipsis maxWidth="60%" className="w-full ml-2 text-sm color-gray-medium" text={body} /> + } + </div> + { isLocation && event.speedIndex != null && + <div className="color-gray-medium flex font-medium items-center leading-none justify-end"> + <div className="font-size-10 pr-2">{"Speed Index"}</div> + <div>{ numberWithCommas(event.speedIndex || 0) }</div> + </div> + } + </div> + { event.target && event.target.label && + <div className={ cls.badge } >{ event.target.label }</div> + } + </div> + </div> + { isLocation && + <div className="mt-1"> + <span className="text-sm font-normal color-gray-medium">{ body }</span> + </div> + } + </div> + ); + }; + + render() { + const { + event, + selected, + isCurrent, + onClick, + onEditClick, + showSelection, + onCheckboxClick, + showLoadInfo, + toggleLoadInfo, + isRed, + extended, + highlight = false, + presentInSearch=false + } = this.props; + const { menuOpen } = this.state; + return ( + <div + ref={ ref => { this.wrapper = ref } } + onMouseLeave={ this.onMouseLeave } + data-openreplay-label="Event" + data-type={event.type} + className={ cn(cls.event, { + [ cls.menuClosed ]: !menuOpen, + [ cls.highlighted ]: showSelection ? selected : isCurrent, + [ cls.selected ]: selected, + [ cls.showSelection ]: showSelection, + [ cls.red ]: isRed, + [ cls.clickType ]: event.type === TYPES.CLICK, + [ cls.inputType ]: event.type === TYPES.INPUT, + [ cls.clickrageType ]: event.type === TYPES.CLICKRAGE, + [cls.highlight] : presentInSearch + }) } + onClick={ onClick } + > + { menuOpen && + <button onClick={ this.copyHandler } className={ cls.contextMenu }> + { event.target ? 'Copy CSS' : 'Copy URL' } + </button> + } + <div className={ cls.topBlock }> + {/* <div className={ cls.checkbox }> + <Checkbox + className="customCheckbox" + name={ event.key } + checked={ selected } + onClick={ onCheckboxClick } + /> + </div> */} + <div className={ cls.firstLine }> + { this.renderBody() } + </div> + {/* { event.type === TYPES.LOCATION && + <div className="text-sm font-normal color-gray-medium">{event.url}</div> + } */} + </div> + { event.type === TYPES.LOCATION && (event.fcpTime || event.visuallyComplete || event.timeToInteractive) && + <LoadInfo + showInfo={ showLoadInfo } + onClick={ toggleLoadInfo } + event={ event } + prorata={ prorata({ + parts: 100, + elements: { a: event.fcpTime, b: event.visuallyComplete, c: event.timeToInteractive }, + startDivisorFn: elements => elements / 1.2, + // eslint-disable-next-line no-mixed-operators + divisorFn: (elements, parts) => elements / (2 * parts + 1), + }) } + /> + } + </div> + ); + } +} diff --git a/frontend/app/components/Session_/EventsBlock/EventGroupWrapper.js b/frontend/app/components/Session_/EventsBlock/EventGroupWrapper.js new file mode 100644 index 000000000..b84caea13 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/EventGroupWrapper.js @@ -0,0 +1,98 @@ +import React from 'react' +import cn from 'classnames'; + +import { TextEllipsis } from 'UI'; +import withToggle from 'HOCs/withToggle'; +import { TYPES } from 'Types/session/event'; +import Event from './Event' +import stl from './eventGroupWrapper.css'; + +// TODO: incapsulate toggler in LocationEvent +@withToggle("showLoadInfo", "toggleLoadInfo") +class EventGroupWrapper extends React.PureComponent { + + toggleLoadInfo = (e) => { + e.stopPropagation(); + this.props.toggleLoadInfo(); + } + + componentDidUpdate(prevProps) { + if (prevProps.showLoadInfo !== this.props.showLoadInfo) { + this.props.mesureHeight(); + } + } + componentDidMount() { + this.props.toggleLoadInfo(this.props.isFirst) + this.props.mesureHeight(); + } + + onEventClick = (e) => this.props.onEventClick(e, this.props.event); + + onCheckboxClick = e => this.props.onCheckboxClick(e, this.props.event); + + onEditClick = e => this.props.onEditClick(e, this.props.event); + + render() { + const { + event, + isLastEvent, + isLastInGroup, + isSelected, + isCurrent, + isEditing, + showSelection, + showLoadInfo, + isFirst, + presentInSearch + } = this.props; + const isLocation = event.type === TYPES.LOCATION; + + return ( + <div + className={ + cn(stl.container, { + [stl.last]: isLastInGroup, + [stl.first]: event.type === TYPES.LOCATION, + [stl.dashAfter]: isLastInGroup && !isLastEvent, + }) + } + > + { isFirst && isLocation && event.referrer && + <div className={ stl.referrer }> + {/* Referrer: <span className={stl.url}>{ event.referrer }</span> */} + <TextEllipsis> + Referrer: <span className={stl.url}>{ event.referrer }</span> + </TextEllipsis> + </div> + } + { isLocation + ? <Event + extended={isFirst} + key={ event.key } + event={ event } + onClick={ this.onEventClick } + selected={ isSelected } + showLoadInfo={ showLoadInfo } + toggleLoadInfo={ this.toggleLoadInfo } + isCurrent={ isCurrent } + presentInSearch={presentInSearch} + /> + : <Event + key={ event.key } + event={ event } + onClick={ this.onEventClick } + onCheckboxClick={ this.onCheckboxClick } + selected={ isSelected } + isCurrent={ isCurrent } + onEditClick={ this.onEditClick } + showSelection={ showSelection } + overlayed={ isEditing } + presentInSearch={presentInSearch} + /> + } + </div> + ) + } +} + +export default EventGroupWrapper diff --git a/frontend/app/components/Session_/EventsBlock/EventSearch/EventSearch.js b/frontend/app/components/Session_/EventsBlock/EventSearch/EventSearch.js new file mode 100644 index 000000000..af08ad24a --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/EventSearch/EventSearch.js @@ -0,0 +1,45 @@ +import React, { useState } from 'react' +import { Input, Icon } from 'UI' + +export default function EventSearch(props) { + const { onChange, clearSearch, value, header } = props; + const [showSearch, setShowSearch] = useState(false) + return ( + <div className="flex items-center w-full"> + <div className="flex-1 relative"> + { showSearch ? + <div className="flex items-center"> + <Input + autoFocus + type="text" + placeholder="Filter Events" + className="absolute inset-0 w-full" + name="query" + value={value} + onChange={onChange} + style={{ height: '32px' }} + /> + <div + onClick={() => { setShowSearch(!showSearch); clearSearch() }} + className="flex items-center justify-center cursor-pointer absolute right-0" + style={{ height: '30px', width: '32px' }} + > + <Icon name={'close'} size="18" color="teal" /> + </div> + </div> + : + header + } + </div> + { !showSearch && + <div + onClick={() => setShowSearch(!showSearch)} + className="border rounded flex items-center justify-center bg-white cursor-pointer" + style={{ height: '32px', width: '32px' }} + > + <Icon name={ showSearch ? 'close' : 'search'} size="12" color="teal" /> + </div> + } + </div> + ) +} diff --git a/frontend/app/components/Session_/EventsBlock/EventSearch/index.js b/frontend/app/components/Session_/EventsBlock/EventSearch/index.js new file mode 100644 index 000000000..8be1f4ddc --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/EventSearch/index.js @@ -0,0 +1 @@ +export { default } from './EventSearch' \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/EventsBlock.js b/frontend/app/components/Session_/EventsBlock/EventsBlock.js new file mode 100644 index 000000000..5605ebcd4 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/EventsBlock.js @@ -0,0 +1,281 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { List, AutoSizer, CellMeasurer, CellMeasurerCache } from "react-virtualized"; +import { Avatar, Input, Dropdown, Icon } from 'UI'; +import { TYPES } from 'Types/session/event'; +import { setSelected } from 'Duck/events'; +import { setEventFilter } from 'Duck/sessions'; +import { show as showTargetDefiner } from 'Duck/components/targetDefiner'; +import AutomateButton from './AutomateButton'; +import UserCard from './UserCard'; +import EventGroupWrapper from './EventGroupWrapper'; +import styles from './eventsBlock.css'; +import EventSearch from './EventSearch/EventSearch'; + +@connect(state => ({ + session: state.getIn([ 'sessions', 'current' ]), + filteredEvents: state.getIn([ 'sessions', 'filteredEvents' ]), + eventsIndex: state.getIn([ 'sessions', 'eventsIndex' ]), + selectedEvents: state.getIn([ 'events', 'selected' ]), + targetDefinerDisplayed: state.getIn([ 'components', 'targetDefiner', 'isDisplayed' ]), + testsAvaliable: false, + //state.getIn([ 'user', 'account', 'appearance', 'tests' ]), +}), { + showTargetDefiner, + setSelected, + setEventFilter +}) +export default class EventsBlock extends React.PureComponent { + state = { + editingEvent: null, + mouseOver: false, + query: '' + } + + scroller = React.createRef(); + cache = new CellMeasurerCache({ + fixedWidth: true, + defaultHeight: 300 + }); + + write = ({ target: { value, name } }) => { + const { filter } = this.state; + this.setState({ query: value }) + this.props.setEventFilter({ query: value, filter }) + + setTimeout(() => { + this.scroller.current.scrollToRow(0); + this.scroller.current.recomputeGridSize(); + this.scroller.current.recomputeRowHeights(); + this.scroller.current.forceUpdateGrid(); + }, 200) + } + + clearSearch = () => { + const { filter } = this.state; + this.setState({ query: '' }) + this.props.setEventFilter({ query: '', filter }) + + this.scroller.current.forceUpdateGrid(); + + setTimeout(() => { + this.scroller.current.scrollToRow(0); + }, 100) + } + + onSetEventFilter = (e, { name, value }) => { + const { query } = this.state; + this.setState({ filter: value }) + this.props.setEventFilter({ filter: value, query }); + } + + componentDidUpdate(prevProps) { + if (prevProps.targetDefinerDisplayed && !this.props.targetDefinerDisplayed) { + this.setState({ editingEvent: null }); + } + if (prevProps.session !== this.props.session) { // Doesn't happen + // this.setState({ + // groups: groupEvents(this.props.session.events), + // }); + this.cache = new CellMeasurerCache({ + fixedWidth: true, + defaultHeight: 300 + }); + } + if (prevProps.currentTimeEventIndex !== this.props.currentTimeEventIndex && + this.scroller.current !== null) { + this.scroller.current.forceUpdateGrid(); + if (!this.state.mouseOver) { + this.scroller.current.scrollToRow(this.props.currentTimeEventIndex); + } + } + } + + // TODO: move to Event componenet + onEditClick = (e, event) => { + e.stopPropagation(); + this.props.player.pause(); + this.props.player.jump(event.time); + this.props.player.markBelowMouse(); + this.props.showTargetDefiner(event.target); + this.setState({ editingEvent: event }) + // this.props.setSelected([ event ]); + } + + onCheckboxClick(e, event) { + e.stopPropagation(); + const { + session: { events }, + selectedEvents, + } = this.props; + + this.props.player.pause(); + + let newSelectedSet; + const wasSelected = selectedEvents.contains(event); + if (wasSelected) { + newSelectedSet = selectedEvents.remove(event); + } else { + newSelectedSet = selectedEvents.add(event); + } + + let selectNextLoad = false; + events.reverse().forEach((sessEvent) => { + if (sessEvent.type === TYPES.LOCATION) { + if (selectNextLoad) { + newSelectedSet = newSelectedSet.add(sessEvent); + } + selectNextLoad = false; + } else if (newSelectedSet.contains(sessEvent)) { + selectNextLoad = true; + } + }); + this.props.setSelected(newSelectedSet); + } + + onEventClick = (e, event) => this.props.player.jump(event.time) + + onMouseOver = () => this.setState({ mouseOver: true }) + onMouseLeave = () => this.setState({ mouseOver: false }) + + renderGroup = ({ index, key, style, parent }) => { + const { + session: { events }, + selectedEvents, + currentTimeEventIndex, + testsAvaliable, + playing, + eventsIndex, + filteredEvents + } = this.props; + const _events = filteredEvents || events; + const isLastEvent = index === _events.size - 1; + const isLastInGroup = isLastEvent || _events.get(index + 1).type === TYPES.LOCATION; + const event = _events.get(index); + const isSelected = selectedEvents.includes(event); + const isCurrent = index === currentTimeEventIndex; + const isEditing = this.state.editingEvent === event; + return ( + <CellMeasurer + key={key} + cache={this.cache} + parent={parent} + //columnIndex={0} + rowIndex={index} + > + {({measure, registerChild}) => ( + <div style={style} ref={registerChild}> + <EventGroupWrapper + presentInSearch={eventsIndex.includes(index)} + isFirst={index==0} + mesureHeight={measure} + onEventClick={ this.onEventClick } + onCheckboxClick={ this.onCheckboxClick } + onEditClick={this.onEditClick} + event={ event } + isLastEvent={ isLastEvent } + isLastInGroup={ isLastInGroup } + isSelected={ isSelected } + isCurrent={ isCurrent } + isEditing={ isEditing } + showSelection={ testsAvaliable && !playing } + /> + </div> + )} + </CellMeasurer> + ); + } + + render() { + const { query } = this.state; + const { + playing, + testsAvaliable, + session: { + events, + userNumericHash, + userDisplayName, + userUuid, + userId, + userAnonymousId + }, + filteredEvents + } = this.props; + + const _events = filteredEvents || events; + + return ( + <div className={ cn("flex flex-col", styles.eventsBlock) }> + <div className={ cn(styles.header, 'p-3') }> + <UserCard + className="" + userNumericHash={userNumericHash} + userDisplayName={userDisplayName} + userId={userId} + userAnonymousId={userAnonymousId} + /> + + <div className={ cn(styles.hAndProgress, 'mt-3') }> + {/* <div className="text-lg">{ `User Events (${ events.size })` }</div> */} + <EventSearch + onChange={this.write} + clearSearch={this.clearSearch} + value={query} + header={ + <div className="text-lg">{ `User Events (${ events.size })` }</div> + } + /> + </div> + <div className="flex mt-3"> + {/* <Dropdown + trigger={ + <div className={cn("py-3 px-3 bg-white flex items-center text-sm mb-2 border rounded ml-2")} style={{ height: '32px' }}> + <Icon name="filter" size="12" color="teal" /> + </div> + } + options={ [ + // { text: 'Visited', value: TYPES.LOCATION }, + { text: 'Clicked', value: TYPES.CLICK }, + { text: 'Input', value: TYPES.INPUT }, + ] } + name="filter" + icon={null} + onChange={this.onSetEventFilter} + basic + direction="left" + scrolling + selectOnBlur={true} + closeOnChange={true} + /> */} + </div> + </div> + <div + className={ cn("flex-1 px-3 pb-3", styles.eventsList) } + id="eventList" + data-openreplay-masked + onMouseOver={ this.onMouseOver } + onMouseLeave={ this.onMouseLeave } + > + <AutoSizer disableWidth> + {({ height }) => ( + <List + ref={this.scroller} + className={ styles.eventsList } + height={height} + width={248} + overscanRowCount={6} + itemSize={230} + rowCount={_events.size} + deferredMeasurementCache={this.cache} + rowHeight={this.cache.rowHeight} + rowRenderer={this.renderGroup} + scrollToAlignment="start" + /> + )} + </AutoSizer> + </div> + { testsAvaliable && <AutomateButton /> } + </div> + ); + } +} diff --git a/frontend/app/components/Session_/EventsBlock/LoadInfo.js b/frontend/app/components/Session_/EventsBlock/LoadInfo.js new file mode 100644 index 000000000..b149352e0 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/LoadInfo.js @@ -0,0 +1,48 @@ +import styles from './loadInfo.css'; +import { numberWithCommas } from 'App/utils' + +const LoadInfo = ({ showInfo = false, onClick, event: { fcpTime, visuallyComplete, timeToInteractive }, prorata: { a, b, c } }) => ( + <div> + <div className={ styles.bar } onClick={ onClick }> + { typeof fcpTime === 'number' && <div style={ { width: `${ a }%` } } /> } + { typeof visuallyComplete === 'number' && <div style={ { width: `${ b }%` } } /> } + { typeof timeToInteractive === 'number' && <div style={ { width: `${ c }%` } } /> } + </div> + <div className={ styles.bottomBlock } data-hidden={ !showInfo }> + { typeof fcpTime === 'number' && + <div className={ styles.wrapper }> + <div className={ styles.lines } /> + <div className={ styles.label } >{ 'Time to Render' }</div> + <div className={ styles.value }>{ `${ numberWithCommas(fcpTime || 0) }ms` }</div> + </div> + } + { typeof visuallyComplete === 'number' && + <div className={ styles.wrapper }> + <div className={ styles.lines } /> + <div className={ styles.label } >{ 'Visually Complete' }</div> + <div className={ styles.value }>{ `${ numberWithCommas(visuallyComplete || 0) }ms` }</div> + </div> + } + { typeof timeToInteractive === 'number' && + <div className={ styles.wrapper }> + <div className={ styles.lines } /> + <div className={ styles.label } >{ 'Time To Interactive' }</div> + <div className={ styles.value }>{ `${ numberWithCommas(timeToInteractive || 0) }ms` }</div> + </div> + } + {/* <div className={ styles.download }> + <a> + <Icon name="download" /> + { '.HAR' } + </a> + <div> + { new Date().toString() } + </div> + </div> */} + </div> + </div> +); + +LoadInfo.displayName = 'LoadInfo'; + +export default LoadInfo; diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/Metadata.js b/frontend/app/components/Session_/EventsBlock/Metadata/Metadata.js new file mode 100644 index 000000000..6d24be57b --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Metadata/Metadata.js @@ -0,0 +1,39 @@ +import React, { useCallback, useState } from 'react'; +import { connect } from 'react-redux'; +import { NoContent, IconButton } from 'UI'; +import withToggle from 'HOCs/withToggle'; +import MetadataItem from './MetadataItem'; +import stl from './metadata.css'; + +export default connect(state => ({ + metadata: state.getIn([ 'sessions', 'current', 'metadata' ]), +}))(function Metadata ({ metadata }) { + const [ visible, setVisible ] = useState(false); + const toggle = useCallback(() => setVisible(v => !v), []); + return ( + <> + <IconButton + className="w-full" + onClick={ toggle } + icon="id-card" + plain + label="Metadata" + primaryText + active={ visible } + disabled={metadata.length === 0} + id="metadata-button" + /> + { visible && + <div className={ stl.modal } > + <NoContent show={ metadata.size === 0 } size="small" > + { metadata.map((i) => { + const key = Object.keys(i)[0] + const value = i[key] + return <MetadataItem item={ { value, key } } key={ key } /> + }) } + </NoContent> + </div> + } + </> + ); +}); diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/MetadataItem.js b/frontend/app/components/Session_/EventsBlock/Metadata/MetadataItem.js new file mode 100644 index 000000000..8abd1913c --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Metadata/MetadataItem.js @@ -0,0 +1,74 @@ +import { List } from 'immutable'; +import cn from 'classnames'; +import { withRequest, withToggle } from 'HOCs'; +import { Button, Icon, SlideModal, TextEllipsis } from 'UI'; +import stl from './metadataItem.css'; +import SessionList from './SessionList'; + +@withToggle() +@withRequest({ + initialData: List(), + endpoint: '/metadata/session_search', + dataWrapper: data => Object.values(data), + dataName: 'similarSessions', +}) +export default class extends React.PureComponent { + state = { + requested: false, + } + switchOpen = () => { + const { + item: { + key, value + }, + request, + switchOpen, + } = this.props; + + const { requested } = this.state; + if (!requested) { + this.setState({ requested: true }); + request({ key, value }); + } + switchOpen(); + } + + render() { + const { + item, + similarSessions, + open, + loading, + } = this.props; + + return ( + <div> + <SlideModal + title={ <div className={ stl.searchResultsHeader }>{ `All Sessions Matching - ` } <span>{ item.key + ' - ' + item.value }</span> </div> } + isDisplayed={ open } + content={ open && <SessionList similarSessions={ similarSessions } loading={ loading } /> } + onClose={ open ? this.switchOpen : () => null } + /> + <div className={ cn("flex justify-between items-center p-3", stl.field) } > + <div> + <div className={ stl.key }>{ item.key }</div> + <TextEllipsis + maxWidth="210px" + popupProps={ { disabled: item.value && item.value.length < 30 } } + > + { item.value } + </TextEllipsis> + </div> + <Button + onClick={ this.switchOpen } + plain + className={ stl.searchButton } + id="metadata-item" + > + <Icon name="search" size="16" color="teal" /> + </Button> + </div> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/SessionLine.js b/frontend/app/components/Session_/EventsBlock/Metadata/SessionLine.js new file mode 100644 index 000000000..729271ece --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Metadata/SessionLine.js @@ -0,0 +1,40 @@ +import { BrowserIcon, OsIcon, Icon, CountryFlag, Link } from 'UI'; +import { deviceTypeIcon } from 'App/iconNames'; +import { session as sessionRoute } from 'App/routes'; +import { formatTimeOrDate } from 'App/date'; + + +const SessionLine = ({ session: { + userBrowser, + userOs, + userCountry, + siteId, + sessionId, + viewed, + userDeviceType, + startedAt + } }) => ( + <div className="flex justify-between items-center" style={{ padding: '5px 20px' }}> + <div className="color-gray-medium font-size-10" > + <CountryFlag country={ userCountry } className="mr-4" /> + { formatTimeOrDate(startedAt) } + </div> + <div className="flex"> + <BrowserIcon browser={ userBrowser } className="mr-4" /> + <OsIcon os={ userOs } size="20" className="mr-4" /> + <Icon name={ deviceTypeIcon(userDeviceType) } size="20" className="mr-4" /> + </div> + <Link to={ sessionRoute(sessionId) } siteId={ siteId } > + <Icon + name={ viewed ? 'play-fill' : 'play-circle-light' } + size="20" + color="teal" + /> + </Link> + </div> +); + + +SessionLine.displayName = "SessionLine"; + +export default SessionLine; diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/SessionList.js b/frontend/app/components/Session_/EventsBlock/Metadata/SessionList.js new file mode 100644 index 000000000..2f1a5c9fa --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Metadata/SessionList.js @@ -0,0 +1,49 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { NoContent, Icon, Loader } from 'UI'; +import Session from 'Types/session'; +import SessionItem from 'Shared/SessionItem'; +import stl from './sessionList.css'; + +@connect(state => ({ + currentSessionId: state.getIn([ 'sessions', 'current', 'sessionId' ]) +})) +class SessionList extends React.PureComponent { + render() { + const { + similarSessions, + loading, + currentSessionId, + } = this.props; + + const similarSessionWithoutCurrent = similarSessions.map(({sessions, ...rest}) => { + return { + ...rest, + sessions: sessions.map(Session).filter(({ sessionId }) => sessionId !== currentSessionId) + } + }).filter(site => site.sessions.length > 0); + + return ( + <Loader loading={ loading }> + <NoContent + show={ !loading && (similarSessionWithoutCurrent.length === 0 || similarSessionWithoutCurrent.size === 0 )} + title="No sessions found." + > + <div className={ stl.sessionList }> + { similarSessionWithoutCurrent.map(site => ( + <div className={ stl.siteWrapper } key={ site.host }> + <div className={ stl.siteHeader }> + <Icon name="window" size="14" color="gray-medium" marginRight="10" /> + <span>{ site.name }</span> + </div> + { site.sessions.map(session => <SessionItem key={ session.sessionId } session={ session } />) } + </div> + )) } + </div> + </NoContent> + </Loader> + ); + } +} + +export default SessionList; diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/index.js b/frontend/app/components/Session_/EventsBlock/Metadata/index.js new file mode 100644 index 000000000..17932470b --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Metadata/index.js @@ -0,0 +1 @@ +export { default } from './Metadata'; \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/metadata.css b/frontend/app/components/Session_/EventsBlock/Metadata/metadata.css new file mode 100644 index 000000000..268e04ba7 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Metadata/metadata.css @@ -0,0 +1,51 @@ + +@import 'mixins.css'; + +/* .wrapper { + position: relative; +} */ + +.modal { + /* width: 288px; */ + /* position: absolute; */ + /* top: 50px; */ + /* right: 0; */ + /* background-color: white; */ + /* border-radius: 3px; */ + /* z-index: 99; */ + /* padding: 10px; */ + /* min-height: 90px; */ + max-height: 300px; + overflow: auto; + /* @mixin shadow; */ + /* border: solid thin $gray-light; */ + + /* & .tooltipArrow { + width: 50px; + height: 25px; + position: absolute; + bottom: 100%; + right: 0; + transform: translateX(-50%); + overflow: hidden; + + &::after { + content: ""; + position: absolute; + width: 16px; + height: 16px; + background: white; + transform: translateX(-50%) translateY(50%) rotate(45deg); + bottom: 0; + left: 50%; + box-shadow: 2px 2px 6px 0px rgba(0,0,0,0.6); + } + } */ +} + +.header { + font-size: 18px; + font-weight: 500; + /* padding: 10px 20px; */ + border-bottom: solid thin $gray-light; +} diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/metadataItem.css b/frontend/app/components/Session_/EventsBlock/Metadata/metadataItem.css new file mode 100644 index 000000000..2dc522306 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Metadata/metadataItem.css @@ -0,0 +1,37 @@ + + +.field { + &:not(:last-child) { + border-bottom: solid thin $gray-light-shade; + } + /* padding: 10px 20px; */ +} + +.key { + color: $gray-medium; + font-weight: 500; +} + +.searchResultsHeader { + & span { + padding: 4px 8px; + font-size: 18px; + background-color: $gray-lightest; + border: solid thin $gray-light; + margin-left: 10px; + border-radius: 3px; + } +} + +.searchButton { + border-radius: 3px; + height: 30px !important; + width: 30px !important; + display: flex !important; + align-items: center !important; + padding: 0 !important; + justify-content: center !important; + &:hover { + background-color: $gray-lightest !important; + } +} diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/sessionList.css b/frontend/app/components/Session_/EventsBlock/Metadata/sessionList.css new file mode 100644 index 000000000..0c63d2ae0 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/Metadata/sessionList.css @@ -0,0 +1,26 @@ + + +.sessionList { + padding: 0 20px; + background-color: #f6f6f6; + min-height: calc(100vh - 59px); +} + +.siteWrapper { + padding-top: 10px; + margin-bottom: 10px; +} + +.siteHeader { + display: flex; + align-items: center; + margin-bottom: 15px; + font-weight: 400; + font-size: 14px; + background-color: white; + border-top: solid thin $gray-lightest; + margin: -15px; + margin-top: -10px; + margin-bottom: 20px; + padding: 10px; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/UserCard/UserCard.js b/frontend/app/components/Session_/EventsBlock/UserCard/UserCard.js new file mode 100644 index 000000000..ecd072498 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/UserCard/UserCard.js @@ -0,0 +1,50 @@ +import React, { useState } from 'react' +import { List } from 'immutable' +import { Avatar, TextEllipsis, SlideModal } from 'UI' +import cn from 'classnames' +import Metadata from '../Metadata' +import { withRequest } from 'HOCs' +import SessionList from '../Metadata/SessionList' + +function UserCard({ className, userNumericHash, userDisplayName, similarSessions, userId, userAnonymousId, request, loading }) { + const [showUserSessions, setShowUserSessions] = useState(false) + const hasUserDetails = !!userId || !!userAnonymousId; + + const showSimilarSessions = () => { + setShowUserSessions(true); + request({ key: !userId ? 'USERANONYMOUSID' : 'USERID', value: userId || userAnonymousId }); + } + + return ( + <div className={cn("bg-white rounded border", className)}> + <div className={ cn("flex items-center p-3")}> + <Avatar iconSize="36" width="50px" height="50px" seed={ userNumericHash } /> + <div className="ml-3 overflow-hidden leading-tight"> + <TextEllipsis + noHint + className={ cn("text-xl", { 'color-teal cursor-pointer' : hasUserDetails })} + onClick={hasUserDetails && showSimilarSessions} + > + { userDisplayName } + </TextEllipsis> + </div> + </div> + <div className="border-t"> + <Metadata /> + </div> + <SlideModal + title={ <div>User Sessions</div> } + isDisplayed={ showUserSessions } + content={ showUserSessions && <SessionList similarSessions={ similarSessions } loading={ loading } /> } + onClose={ () => showUserSessions ? setShowUserSessions(false) : null } + /> + </div> + ) +} + +export default withRequest({ + initialData: List(), + endpoint: '/metadata/session_search', + dataWrapper: data => Object.values(data), + dataName: 'similarSessions', +})(UserCard) diff --git a/frontend/app/components/Session_/EventsBlock/UserCard/index.js b/frontend/app/components/Session_/EventsBlock/UserCard/index.js new file mode 100644 index 000000000..30f2f5b8a --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/UserCard/index.js @@ -0,0 +1 @@ +export { default } from './UserCard'; \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/automateButton.css b/frontend/app/components/Session_/EventsBlock/automateButton.css new file mode 100644 index 000000000..5d96e3f58 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/automateButton.css @@ -0,0 +1,43 @@ +.automateBtnWrapper { + display: flex; + flex-direction: column; + position: relative; +} + +.automateButton { + display: flex; + align-items: center; + justify-content: center; + font-weight: 300; + cursor: pointer; + + &:hover { + color: white; + } + + & a { + display: flex; + padding: 0 30px; + height: 40px; + flex-direction: column; + color: white; + line-height: 15px; + text-align: center; + justify-content: center; + align-items: center; + border-radius: 5px; + background-color: $teal; + width: 100%; + + &:hover { + background-color: $teal-dark; + } + + & .subText { + font-size: 10px; + font-weight: 300; + color: rgba(255,255,255,.5); + } + } +} + diff --git a/frontend/app/components/Session_/EventsBlock/event.css b/frontend/app/components/Session_/EventsBlock/event.css new file mode 100644 index 000000000..e272e68b2 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/event.css @@ -0,0 +1,160 @@ +.contextMenu { + position: absolute; + top: 27px; + right: 15px; + padding: 2px 3px; + background: $white; + border: 1px solid $gray-light; + border-radius: 3px; + cursor: pointer; + color: $gray-medium; + font-size: 12px; + z-index: 2; +} + +.event { + position: relative; + background: #fff; + border-radius: 3px; + user-select: none; + /* box-shadow: 0px 1px 3px 0 $gray-light; */ + border: 1px solid #EEE; + transition: all 0.2s; + cursor: pointer; + &:hover { + background-color: $active-blue; + border: 1px solid $active-blue-border; + } + + & .title { + font-size: 13px; + } + + & .topBlock { + min-height: 30px; + position: relative; + padding: 8px 10px; + } + + & .checkbox { + position: absolute; + left: 10px; + top: 8px; + bottom: 0; + /* margin: auto; */ + display: none; + /* align-items: center; */ + } + + &.menuClosed:hover { + & .edit { + opacity: 1; + transition: all 0.2s; + } + } + + &.menuClosed.showSelection { + &:hover, &.selected { + background-color: #EFFCFB; + + & .checkbox { + display: flex; + } + + & .icon { + opacity: 0; + } + } + } + + &.highlighted { + background-color: $active-blue; + transition: all 0.2s; + box-shadow: 0px 2px 10px 0 $gray-light; + border-color: $active-blue-border; + } + + &.red { + border-color: $red; + } +} + +.firstLine { + display: flex; + justify-content: space-between; + align-items: center; +} + +.main { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: flex; + align-items: start; +} + + +.type { + color: $gray-dark; + font-size: 12px; + text-transform: capitalize; + font-weight: bold; +} + +.data { + margin-left: 5px; + color: $gray-medium; + font-size: 12px; + max-width: 100%; + /* overflow: hidden; */ + /* text-overflow: ellipsis; */ +} + +.badge { + display: inline-block; + padding: 0; + border-radius: 3px; + font-size: 9px; + /* margin-left: 28px; */ + max-width: 170px; + word-wrap: break-word; + line-height: normal; + color: #999; + text-transform: none; +} + +.icon { + margin-right: 10px; + display: inline-flex; + align-items: center; + justify-content: center; + & i { + width: 18px; + height: 18px; + } +} + + +.clickType, .inputType { + /* border: 1px solid $gray-light; */ + background-color: $gray-lightest; + cursor: pointer; +} + +.clickrageType { + background-color: #FFF3F3; + border: 1px solid #CC0000; + box-shadow: + /* The top layer shadow */ + /* 0 1px 1px rgba(0,0,0,0.15), */ + /* The second layer */ + 2px 2px 1px 1px white, + /* The second layer shadow */ + 2px 2px 0px 1px rgba(0,0,0,0.4); + /* Padding for demo purposes */ + /* padding: 12px; */ +} + +.highlight { + border: solid thin red; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/eventGroupWrapper.css b/frontend/app/components/Session_/EventsBlock/eventGroupWrapper.css new file mode 100644 index 000000000..025ce67c4 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/eventGroupWrapper.css @@ -0,0 +1,55 @@ + + +.container { + padding: 5px 7px; /*0.35rem 0.5rem */ + border-right: solid thin #E0E0E0; + border-left: solid thin #E0E0E0; + /* border: solid thin #E0E0E0; */ + /* background-color: rgba(255, 255, 255, 0.5); */ + background-color: white; +} + +.first { + padding-top: 7px; + border-top: solid thin #E0E0E0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +.last { + padding-bottom: 7px; + border-bottom: solid thin #E0E0E0; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} + +.dashAfter { + position: relative; + margin-bottom: 0.8rem; + &:after { + height: 0.9rem; + width: 2px; + background-color: #E0E0E0; + content: ''; + position: absolute; + left: 30px; + top: 100%; + } +} + +.referrer { + font-size: 14px; + margin-bottom: 10px; + color: $gray-dark; + font-weight: 500 !important; + display: flex; + align-items: center; + & .url { + margin-left: 5px; + font-weight: 300; + color: $gray-medium; + max-width: 70%; + overflow: hidden; + text-overflow: ellipsis; + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/eventsBlock.css b/frontend/app/components/Session_/EventsBlock/eventsBlock.css new file mode 100644 index 000000000..f88cad313 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/eventsBlock.css @@ -0,0 +1,74 @@ +.eventsBlock { + width: 270px; + /* padding: 0 10px; */ + margin-bottom: 5px; +} + +.header { + /* height: 40px; */ + /* margin-bottom: 15px; */ + padding-left: 2px; + /* padding-right: 0px; */ + + & .hAndProgress { + display:flex; + justify-content: space-between; + align-items: center; + /* margin-bottom: 5px; */ + /* height: 40px; */ + & .progress { + flex: 1; + margin: 0 0 0 15px; + & :global(.bar) { + background: #ffcc99; + } + & :global(.progress) { + font-size: 9px; + } + } + } + + & h5 { + margin: 0; /* get rid of semantic, please*/ + font-size: 14px; + font-weight: 700; + } +} + +.eventsList { + /* box-shadow: inset 0px 2px 4px rgba(0, 0, 0, 0.1); */ + /* border-top: solid thin $gray-light-shade; */ + &::-webkit-scrollbar { + width: 2px; + background: transparent !important; + background: rgba(0,0,0,0); + } + + &::-webkit-scrollbar-thumb { + background: transparent !important; + } + &::-webkit-scrollbar-track { + background: transparent !important; + } + &:hover { + &::-webkit-scrollbar { + width: 2px; + background: rgba(0,0,0,0.1) + } + &::-webkit-scrollbar-track { + background: rgba(0,0,0,0.1) + } + &::-webkit-scrollbar-thumb { + background: rgba(0,0,0,0.1) + } + } +} + +.sessionDetails { + display: flex; + font-size: 10px; + color: $gray-medium; + justify-content: space-between; +} + + diff --git a/frontend/app/components/Session_/EventsBlock/index.js b/frontend/app/components/Session_/EventsBlock/index.js new file mode 100644 index 000000000..47e4d4efb --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/index.js @@ -0,0 +1 @@ +export { default } from './EventsBlock'; \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/loadInfo.css b/frontend/app/components/Session_/EventsBlock/loadInfo.css new file mode 100644 index 000000000..1e2a95927 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/loadInfo.css @@ -0,0 +1,102 @@ + + +$green-light: #A0D6AE; +$green-middle: #859D9A; +$green-dark: #3A625E; + +.bar { + display: flex; + overflow: hidden; + cursor: pointer; + + /* margin: 0 -11px; + margin-bottom: -9px; */ + + & div { + height: 5px; + } + & div:nth-child(1) { + background-color: #C5E6E7; + } + & div:nth-child(2) { + background-color: #8BCCCF; + } + & div:nth-child(3) { + background-color :rgba(62, 170, 175, 1); + } +} + +.bottomBlock { + overflow: hidden; +} + +.wrapper { + position: relative; + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 5px 12px 34px; + font-size: 13px; + /* font-weight: 500; */ + + & .lines { + border-bottom: 1px solid $gray-light; + border-left: 2px solid; + position: absolute; + height: 100%; + top: -21px; + left: 14px; + width: 15px; + + &:before { + content: ""; + border-radius: 5px; + border: 5px solid; + display: block; + width: 0; + height: 0; + position: absolute; + bottom: -5px; + left: -6px; + z-index: 1; /* in context */ + } + } +} + +.wrapper:nth-child(1) { + /* overflow: hidden; */ + & .lines { + border-left-color: #C5E6E7; + &:before { + border-color: #C5E6E7; + } + } +} + +.wrapper:nth-child(2) { + & .lines { + border-left-color: #8BCCCF; + &:before { + border-color: #8BCCCF; + } + } +} + +.wrapper:nth-child(3) { + & .lines { + border-left-color: rgba(62, 170, 175, 1); + &:before { + border-color: rgba(62, 170, 175, 1); + } + } +} + +.value { + font-weight: 500; + color: $gray-medium; +} + +.download { + display: flex; + justify-content: space-between; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Exceptions/Exceptions.js b/frontend/app/components/Session_/Exceptions/Exceptions.js new file mode 100644 index 000000000..9cd646fe1 --- /dev/null +++ b/frontend/app/components/Session_/Exceptions/Exceptions.js @@ -0,0 +1,115 @@ +import { connect } from 'react-redux'; +import { getRE } from 'App/utils'; +import { NoContent, Loader, Input, ErrorItem, SlideModal, ErrorDetails, ErrorHeader,Link, QuestionMarkHint } from 'UI'; +import { fetchErrorStackList } from 'Duck/sessions' +import { connectPlayer, jump } from 'Player'; +import { error as errorRoute } from 'App/routes'; +import Autoscroll from '../Autoscroll'; +import BottomBlock from '../BottomBlock'; + +@connectPlayer(state => ({ + logs: state.logListNow, + exceptions: state.exceptionsListNow, +})) +@connect(state => ({ + session: state.getIn([ 'sessions', 'current' ]), + errorStack: state.getIn([ 'sessions', 'errorStack' ]), + sourceMapUploaded: state.getIn([ 'sessions', 'sourceMapUploaded' ]), + loading: state.getIn([ 'sessions', 'fetchErrorStackList', 'loading' ]) +}), { fetchErrorStackList }) +export default class Exceptions extends React.PureComponent { + state = { + filter: '', + currentError: null + } + + onFilterChange = (e, { value }) => this.setState({ filter: value }) + + setCurrentError = (err) => { + const { session } = this.props; + this.props.fetchErrorStackList(session.sessionId, err.errorId) + this.setState({ currentError: err}) + } + closeModal = () => this.setState({ currentError: null}) + + render() { + const { exceptions, loading, errorStack, sourceMapUploaded } = this.props; + const { filter, currentError } = this.state; + const filterRE = getRE(filter, 'i'); + + const filtered = exceptions.filter(e => filterRE.test(e.name) || filterRE.test(e.message)); + + return ( + <> + <SlideModal + title={ currentError && + <div className="mb-4"> + <div className="text-xl mb-2"> + <Link to={errorRoute(currentError.errorId)}> + <span className="font-bold">{currentError.name}</span> + </Link> + <span className="ml-2 text-sm color-gray-medium"> + {currentError.function} + </span> + </div> + <div>{currentError.message}</div> + </div> + } + isDisplayed={ currentError != null } + content={ currentError && + <div className="px-4"> + <Loader loading={ loading }> + <NoContent + show={ !loading && errorStack.size === 0 } + title="Nothing found!" + > + <ErrorDetails error={ currentError.name } errorStack={errorStack} sourceMapUploaded={sourceMapUploaded} /> + </NoContent> + </Loader> + </div> + } + onClose={ this.closeModal } + /> + <BottomBlock> + <BottomBlock.Header> + <Input + className="input-small" + placeholder="Filter by name or message" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + <QuestionMarkHint + content={ + <> + <a className="color-teal underline" target="_blank" href="https://docs.openreplay.com/plugins/sourcemaps">Upload Source Maps </a> + and see source code context obtained from stack traces in their original form. + </> + } + className="mr-8" + /> + </BottomBlock.Header> + <BottomBlock.Content> + <NoContent + size="small" + show={ filtered.length === 0} + > + <Autoscroll> + { filtered.map(e => ( + <ErrorItem + onJump={ () => jump(e.time) } + error={e} + key={e.key} + onErrorClick={() => this.setCurrentError(e)} + /> + )) + } + </Autoscroll> + </NoContent> + </BottomBlock.Content> + </BottomBlock> + </> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Fetch/Fetch.js b/frontend/app/components/Session_/Fetch/Fetch.js new file mode 100644 index 000000000..e3d34fd4e --- /dev/null +++ b/frontend/app/components/Session_/Fetch/Fetch.js @@ -0,0 +1,139 @@ + +//import cn from 'classnames'; +import { getRE } from 'App/utils'; +import { Label, NoContent, Input, SlideModal, CloseButton } from 'UI'; +import { connectPlayer } from 'Player'; +import Autoscroll from '../Autoscroll'; +import BottomBlock from '../BottomBlock'; +import TimeTable from '../TimeTable'; +import FetchDetails from './FetchDetails'; +import { renderName, renderDuration } from '../Network'; + +@connectPlayer(state => ({ + list: state.fetchList, +})) +export default class Fetch extends React.PureComponent { + state = { + filter: "", + current: null, + } + onFilterChange = (e, { value }) => this.setState({ filter: value }) + + setCurrent = (item, index) => { + this.setState({ current: item, currentIndex: index }); + } + + closeModal = () => this.setState({ current: null}) + + nextClickHander = () => { + const { list } = this.props; + const { currentIndex } = this.state; + + if (currentIndex === list.length - 1) return; + const newIndex = currentIndex + 1; + this.setCurrent(list[newIndex], newIndex); + } + + prevClickHander = () => { + const { list } = this.props; + const { currentIndex } = this.state; + + if (currentIndex === 0) return; + const newIndex = currentIndex - 1; + this.setCurrent(list[newIndex], newIndex); + } + + render() { + const { list } = this.props; + const { filter, current, currentIndex } = this.state; + const filterRE = getRE(filter, 'i'); + const filtered = list + .filter(({ name }) => filterRE.test(name)); + + return ( + <React.Fragment> + <SlideModal + overlay={false} + right + size="middle" + title={ + <div className="flex justify-between"> + <h1>Fetch Request</h1> + <div className="flex items-center"> + <div className="flex items-center"> + <span className="mr-2 color-gray-medium uppercase text-base">Status</span> + <Label + data-red={current && current.status >= 400} + data-green={current && current.status < 400} + > + <div className="uppercase w-16 justify-center code-font text-lg">{current && current.status}</div> + </Label> + </div> + <CloseButton onClick={ this.closeModal } size="18" className="ml-2" /> + </div> + </div> + } + isDisplayed={ current != null } + content={ current && + <FetchDetails + resource={ current } + nextClick={this.nextClickHander} + prevClick={this.prevClickHander} + first={currentIndex === 0} + last={currentIndex === filtered.length - 1} + /> + } + onClose={ this.closeModal } + /> + <BottomBlock> + <BottomBlock.Header> + <h4 className="text-lg">Fetch</h4> + <Input + className="input-small" + placeholder="Filter by Name" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + </BottomBlock.Header> + <BottomBlock.Content> + <NoContent + size="small" + show={ filtered.length === 0} + > + <TimeTable + rows={ filtered } + onRowClick={ this.setCurrent } + hoverable + // navigation + activeIndex={currentIndex} + > + {[ + { + label: "Status", + dataKey: 'status', + width: 70, + }, { + label: "Method", + dataKey: "method", + width: 60, + }, { + label: "Name", + width: 130, + render: renderName, + }, + { + label: "Time", + width: 80, + render: renderDuration, + } + ]} + </TimeTable> + </NoContent> + </BottomBlock.Content> + </BottomBlock> + </React.Fragment> + ); + } +} diff --git a/frontend/app/components/Session_/Fetch/FetchDetails.js b/frontend/app/components/Session_/Fetch/FetchDetails.js new file mode 100644 index 000000000..666406b9f --- /dev/null +++ b/frontend/app/components/Session_/Fetch/FetchDetails.js @@ -0,0 +1,153 @@ +import { JSONTree, Label, Button, Tabs } from 'UI' +import cn from 'classnames'; +import copy from 'copy-to-clipboard'; +import stl from './fetchDetails.css'; +import ResultTimings from '../../shared/ResultTimings/ResultTimings'; + +const REQUEST = 'REQUEST'; +const RESPONSE = 'RESPONSE'; +const TIMINGS = 'TIMINGS'; + +const TABS = [ REQUEST, RESPONSE, TIMINGS ].map(tab => ({ text: tab, key: tab })); + +export default class FetchDetails extends React.PureComponent { + state = { activeTab: REQUEST, tabs: [] }; + + onTabClick = activeTab => this.setState({ activeTab }) + + componentDidMount() { + this.checkTabs(); + } + + renderActiveTab = tab => { + const { resource: { duration, timings }, isResult } = this.props; + switch(tab) { + case REQUEST: + const { resource: { payload } } = this.props; + let jsonPayload = undefined; + try { + jsonPayload = typeof payload === 'string' ? JSON.parse(payload) : payload + } catch (e) {} + + return !!payload ? ( + <div> + <div className="mt-6"> + {/* <h5>{ 'Payload '}</h5> */} + { jsonPayload === undefined + ? <div className="ml-3 break-words my-3"> { payload } </div> + : <JSONTree src={ jsonPayload } collapsed={ false } enableClipboard /> + } + </div> + <div className="divider"/> + </div> + ) : '' + break; + case RESPONSE: + const { resource: { response = this.props.resource.body } } = this.props; // for IOS compat. + let jsonResponse = undefined; + try { + jsonResponse = JSON.parse(response); + } catch (e) {} + + return !!response ? ( + <div> + <div className="mt-6"> + {/* <h5>{ 'Response '}</h5> */} + { jsonResponse === undefined + ? <div className="ml-3 break-words my-3"> { response } </div> + : <JSONTree src={ jsonResponse } collapsed={ false } enableClipboard /> + } + </div> + <div className="divider"/> + </div> + // jsonResponse === undefined + // ? <div className="ml-3 break-words my-3"> { response } </div> + // : <JSONTree src={ jsonResponse } collapsed={ false } enableClipboard /> + ) : '' + break; + case TIMINGS: + return <ResultTimings duration={duration} timing={timings} /> + } + } + + componentDidUpdate(prevProps) { + if (prevProps.resource.index === this.props.resource.index) return; + + this.checkTabs(); + } + + checkTabs() { + const { resource: { payload, response, body }, isResult } = this.props; + const _tabs = TABS.filter(t => { + if (t.key == REQUEST && !!payload) { + return true + } + + if (t.key == RESPONSE && !!response) { + return true; + } + + if (t.key == TIMINGS && isResult) { + return true; + } + + return false; + }) + this.setState({ tabs: _tabs, activeTab: _tabs.length > 0 ? _tabs[0].key : null }) + } + + render() { + const { + resource: { + method, + url, + duration + }, + nextClick, + prevClick, + first = false, + last = false, + } = this.props; + const { activeTab, tabs } = this.state; + + return ( + <div className="px-4 pb-16"> + <h5 className="mb-2">{ 'URL'}</h5> + <div className={ cn(stl.url, 'color-gray-darkest')}>{ url }</div> + <div className="flex items-center mt-4"> + <div className="w-4/12"> + <div className="font-medium mb-2">Method</div> + <div>{method}</div> + </div> + <div className="w-4/12"> + <div className="font-medium mb-2">Duration</div> + <div>{parseInt(duration)} ms</div> + </div> + </div> + + <div className="mt-6"> + <div> + <Tabs + tabs={ tabs } + active={ activeTab } + onClick={ this.onTabClick } + border={ true } + /> + <div style={{ height: 'calc(100vh - 314px)', overflowY: 'auto' }}> + { this.renderActiveTab(activeTab) } + </div> + </div> + + <div className="flex justify-between absolute bottom-0 left-0 right-0 p-3 border-t bg-white"> + <Button primary plain onClick={prevClick} disabled={first}> + Prev + </Button> + <Button primary plain onClick={nextClick} disabled={last}> + Next + </Button> + </div> + </div> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Fetch/fetchDetails.css b/frontend/app/components/Session_/Fetch/fetchDetails.css new file mode 100644 index 000000000..75cae8d8f --- /dev/null +++ b/frontend/app/components/Session_/Fetch/fetchDetails.css @@ -0,0 +1,18 @@ + + +.url { + padding: 10px; + border-radius: 3px; + background-color: $gray-lightest; + /* border: solid thin $gray-light; */ + /* max-width: 90%; */ + word-break: break-all; + max-height: 300px; + overflow-y: auto; +} + +.status { + padding: 3px 8px; + border-radius: 12px; + /*border: 1px solid $gray-light;*/ +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Fetch/index.js b/frontend/app/components/Session_/Fetch/index.js new file mode 100644 index 000000000..83925f4c4 --- /dev/null +++ b/frontend/app/components/Session_/Fetch/index.js @@ -0,0 +1 @@ +export { default } from './Fetch'; \ No newline at end of file diff --git a/frontend/app/components/Session_/GraphQL/GQLDetails.js b/frontend/app/components/Session_/GraphQL/GQLDetails.js new file mode 100644 index 000000000..af4882bbd --- /dev/null +++ b/frontend/app/components/Session_/GraphQL/GQLDetails.js @@ -0,0 +1,48 @@ +import { JSONTree } from 'UI' +import cn from 'classnames'; + +export default class GQLDetails extends React.PureComponent { + render() { + const { + gql: { + variables, + response, + }, + } = this.props; + + let jsonVars = undefined; + let jsonResponse = undefined; + try { + jsonVars = JSON.parse(payload); + } catch (e) {} + try { + jsonResponse = JSON.parse(response); + } catch (e) {} + return ( + <div className="ph-20" > + <div className="divider"/> + { variables && variables !== "{}" && + <div> + <div className="mt-6"> + <h5>{ 'Variables'}</h5> + { jsonVars === undefined + ? <div className="ml-3"> { variables } </div> + : <JSONTree src={ jsonVars } /> + } + </div> + <div className="divider"/> + </div> + } + <div className="mt-6"> + <div className="flex justify-between items-start"> + <h5 className="mt-1 mr-1">{ 'Response' }</h5> + </div> + { jsonResponse === undefined + ? <div className="ml-3"> { response } </div> + : <JSONTree src={ jsonResponse } /> + } + </div> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/GraphQL/GraphQL.js b/frontend/app/components/Session_/GraphQL/GraphQL.js new file mode 100644 index 000000000..0fedbb85e --- /dev/null +++ b/frontend/app/components/Session_/GraphQL/GraphQL.js @@ -0,0 +1,90 @@ +//import cn from 'classnames'; +import { Icon, NoContent, Input, SlideModal } from 'UI'; +import { getRE } from 'App/utils'; +import { connectPlayer } from 'Player'; +import Autoscroll from '../Autoscroll'; +import BottomBlock from '../BottomBlock'; +import TimeTable from '../TimeTable'; +import GQLDetails from './GQLDetails'; + +function renderDefaultStatus() { + return "2xx-3xx"; +} + +@connectPlayer(state => ({ + list: state.graphqlListNow, +})) +export default class GraphQL extends React.PureComponent { + state = { + filter: "", + current: null, + } + onFilterChange = (e, { value }) => this.setState({ filter: value }) + + setCurrent = (item) => { + this.setState({ current: item }); + } + closeModal = () => this.setState({ current: null}) + + render() { + const { list } = this.props; + const { filter, current } = this.state; + const filterRE = getRE(filter, 'i'); + const filtered = list + .filter(({ operationName = "", operationKind = "" }) => filterRE.test(operationName) || filterRE.test(operationKind)); + + return ( + <React.Fragment> + <SlideModal + size="middle" + title={ current && <span><i className="color-gray-medium">{current.operationKind}</i> {current.operationName}</span> } + isDisplayed={ current != null } + content={ current && + <GQLDetails gql={ current }/> + } + onClose={ this.closeModal } + /> + <BottomBlock> + <BottomBlock.Header> + <Input + className="input-small" + placeholder="Filter by Name or Type" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + </BottomBlock.Header> + <BottomBlock.Content> + <NoContent + size="small" + show={ filtered.length === 0} + > + <TimeTable + rows={ filtered } + onRowClick={ this.setCurrent } + hoverable + > + {[ + { + label: "Status", + width: 70, + render: renderDefaultStatus, + }, { + label: "Type", + dataKey: "operationKind", + width: 60, + }, { + label: "Name", + width: 130, + dataKey: "operationName", + }, + ]} + </TimeTable> + </NoContent> + </BottomBlock.Content> + </BottomBlock> + </React.Fragment> + ); + } +} diff --git a/frontend/app/components/Session_/GraphQL/index.js b/frontend/app/components/Session_/GraphQL/index.js new file mode 100644 index 000000000..727b5cfa8 --- /dev/null +++ b/frontend/app/components/Session_/GraphQL/index.js @@ -0,0 +1 @@ +export { default } from './GraphQL'; \ No newline at end of file diff --git a/frontend/app/components/Session_/HeaderInfo.js b/frontend/app/components/Session_/HeaderInfo.js new file mode 100644 index 000000000..ccb8edeb3 --- /dev/null +++ b/frontend/app/components/Session_/HeaderInfo.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { Icon } from 'UI'; +import styles from './headerInfo.css'; + +const HeaderInfo = ({ icon, label }) => { + return ( + <div className="flex items-center mx-4"> + <Icon name={ icon } size="18" color="color-dark" /> + <div className="ml-2 mt-1 font-sm font-normal color-gray-darkest text-sm">{ label }</div> + </div> + ); +}; + +export default HeaderInfo; diff --git a/frontend/app/components/Session_/Issues/ActiveIssueClose.js b/frontend/app/components/Session_/Issues/ActiveIssueClose.js new file mode 100644 index 000000000..1c02f3a79 --- /dev/null +++ b/frontend/app/components/Session_/Issues/ActiveIssueClose.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Button } from 'UI'; +import { resetActiveIsue } from 'Duck/issues'; + +const ActiveIssueClose = ({ resetActiveIsue }) => { + return ( + <div className="absolute right-0 top-0 mr-4 mt-4"> + <Button + plain + onClick={ resetActiveIsue } + > + Close + </Button> + </div> + ); +}; + +export default connect(null, { + resetActiveIsue +})(ActiveIssueClose); diff --git a/frontend/app/components/Session_/Issues/ActivityList.js b/frontend/app/components/Session_/Issues/ActivityList.js new file mode 100644 index 000000000..361477d54 --- /dev/null +++ b/frontend/app/components/Session_/Issues/ActivityList.js @@ -0,0 +1,13 @@ +import React from 'react'; + +class ActivityList extends React.Component { + render() { + return ( + <div> + Hello + </div> + ); + } +} + +export default ActivityList; diff --git a/frontend/app/components/Session_/Issues/AuthoAvatar.js b/frontend/app/components/Session_/Issues/AuthoAvatar.js new file mode 100644 index 000000000..59ce52864 --- /dev/null +++ b/frontend/app/components/Session_/Issues/AuthoAvatar.js @@ -0,0 +1,12 @@ +import React from 'react'; +import cn from 'classnames'; + +const AuthorAvatar = ({ className, imgUrl, width = 32, height = 32 }) => { + return ( + <div className={ cn(className, "img-crcle")}> + <img src={ imgUrl } alt="" width={ width } height={ height } /> + </div> + ); +}; + +export default AuthorAvatar; diff --git a/frontend/app/components/Session_/Issues/ContentRender.js b/frontend/app/components/Session_/Issues/ContentRender.js new file mode 100644 index 000000000..cf609cbfe --- /dev/null +++ b/frontend/app/components/Session_/Issues/ContentRender.js @@ -0,0 +1,66 @@ +import React from 'react'; +import stl from './contentRender.css'; +import {UnControlled as CodeMirror} from 'react-codemirror2' + +const elType = { + PARAGRAPH: 'paragraph', + TEXT: 'text', + QUOTE: 'blockquote', + CODE_BLOCK: 'codeBlock', + MENTION: 'mention', + RULE: 'rule', + HARD_BREAK: 'hardBreak', +} + +const renderElement = (el, provider) => { + if (provider === 'github') + return el + + switch(el.type) { + case elType.PARAGRAPH: + return <p className={ stl.para }><ContentRender message={ el } /></p>; + case elType.QUOTE: + return <blockquote className={ stl.quote }><ContentRender message={ el } /></blockquote>; + case elType.CODE_BLOCK: + return <CodeMirror + className={ stl.codeMirror } + value={ codeRender(el.content)[0] } + options={{ + mode: el.attrs.language || '', + theme: 'material', + lineNumbers: true, + readOnly: true, + showCursorWhenSelecting: false, + scroll: true + }} + /> + case elType.MENTION: + return <span className={ stl.mention }>{ `@${el.attrs.text}` }</span>; + case elType.RULE: + return <hr className={ stl.rule } /> + case elType.HARD_BREAK: + return <br /> + case elType.RULE: + return <hr className={ stl.rule } /> + case elType.TEXT: + return el.text; + } + return <ContentRender key={el.text} message={ el } />; +} + +const codeRender = (content) => content.map(el => el.text); + +const ContentRender = props => { + const { message, provider } = props; + return ( + <React.Fragment> + { provider === 'github' ? message : + message && message.content && message.content.map(el => ( + <React.Fragment>{ renderElement(el, provider) }</React.Fragment> + )) + } + </React.Fragment> + ); +}; + +export default ContentRender; diff --git a/frontend/app/components/Session_/Issues/IssueComment.js b/frontend/app/components/Session_/Issues/IssueComment.js new file mode 100644 index 000000000..a3071ff82 --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssueComment.js @@ -0,0 +1,26 @@ +import React from 'react'; +import { checkRecentTime } from 'App/date'; +import AuthorAvatar from './AuthoAvatar'; +import ContentRender from './ContentRender'; + +const IssueComment = ({ activity, provider }) => { + return ( + <div className="mb-4 flex"> + <AuthorAvatar + className="flex-shrink-0 mr-4" + imgUrl={ activity.user && activity.user.avatarUrls['24x24'] } + width={24} + height={24} + /> + <div className="flex flex-col flex-1 mb-2"> + <div className="flex"> + <span className="font-medium mr-3">{ activity.user && activity.user.name }</span> + <span className="text-sm ">{ activity.createdAt && checkRecentTime(activity.createdAt) }</span> + </div> + <div>{ <ContentRender message={ activity.message } provider={provider} /> }</div> + </div> + </div> + ); +}; + +export default IssueComment; diff --git a/frontend/app/components/Session_/Issues/IssueCommentForm.js b/frontend/app/components/Session_/Issues/IssueCommentForm.js new file mode 100644 index 000000000..6af087220 --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssueCommentForm.js @@ -0,0 +1,50 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Input, Button, Form } from 'UI'; +import { addMessage } from 'Duck/assignments'; + +class IssueCommentForm extends React.PureComponent { + state = { comment: '' } + + write = ({ target: { name, value } }) => this.setState({ comment: value }); + + addComment = () => { + const { comment } = this.state; + const { sessionId, issueId, addMessage, loading } = this.props; + if (loading) return; + + addMessage(sessionId, issueId, { message: comment, type: 'message' }).then(() => { + this.setState({comment: ''}); + }) + } + + render() { + const { comment } = this.state; + const { loading } = this.props; + + return ( + <div className="p-6 bg-white"> + <h5 className="mb-1">Add Comment</h5> + <Form onSubmit={ this.addComment }> + <div className="flex mt-2 items-center"> + <Input + onChange={ this.write } + value={ comment } + fluid + placeholder="Type here" + className="flex-1 mr-3" + /> + <Button + disabled={ comment.length === 0 } + primary + loading={ loading }>{'Comment'}</Button> + </div> + </Form> + </div> + ); + } +}; + +export default connect(state => ({ + loading: state.getIn(['assignments', 'addMessage', 'loading']) +}), { addMessage })(IssueCommentForm) diff --git a/frontend/app/components/Session_/Issues/IssueDescription.js b/frontend/app/components/Session_/Issues/IssueDescription.js new file mode 100644 index 000000000..9087df233 --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssueDescription.js @@ -0,0 +1,13 @@ +import React from 'react'; +import ContentRender from './ContentRender'; + +const IssueDescription = ({ className, description, provider }) => { + return ( + <div className={ className }> + <h5 className="mb-4">Description</h5> + <ContentRender message={ description } provider={provider} /> + </div> + ); +}; + +export default IssueDescription; diff --git a/frontend/app/components/Session_/Issues/IssueDetails.js b/frontend/app/components/Session_/Issues/IssueDetails.js new file mode 100644 index 000000000..111dd15fe --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssueDetails.js @@ -0,0 +1,57 @@ +import { connect } from 'react-redux'; +import React from 'react'; +import cn from 'classnames'; +import { Loader } from 'UI'; +import IssueHeader from './IssueHeader'; +import IssueCommentForm from './IssueCommentForm'; +import IssueComment from './IssueComment'; +import stl from './issueDetails.css'; +import IssueDescription from './IssueDescription'; + +class IssueDetails extends React.PureComponent { + state = { searchQuery: ''} + + write = (e, { name, value }) => this.setState({ [ name ]: value }); + + render() { + const { sessionId, issue, loading, users, issueTypeIcons, provider } = this.props; + const activities = issue.activities; + + const assignee = users.filter(({id}) => issue.assignee === id).first(); + + return ( + <div className="flex flex-col"> + <Loader loading={ loading }> + <div> + <IssueHeader + issue={ issue } + typeIcon={ issueTypeIcons[issue.issueType] } + assignee={ assignee } + onSearchComment={ this.write } + /> + <div className={ cn( stl.activitiesList, 'p-6') }> + <IssueDescription + className="mb-10" + description={ issue.description } + provider={provider} + /> + + { activities.size > 0 && <h5 className="mb-4">Comments</h5>} + { activities.map(activity => ( + <IssueComment activity={ activity } key={activity.key} provider={provider} /> + ))} + </div> + <IssueCommentForm sessionId={ sessionId } issueId={ issue.id } /> + </div> + </Loader> + </div> + ); + } +} + +export default connect(state => ({ + users: state.getIn(['assignments', 'users']), + loading: state.getIn(['assignments', 'fetchAssignment', 'loading']), + issueTypeIcons: state.getIn(['assignments', 'issueTypeIcons']), + provider: state.getIn([ 'issues', 'list']).provider, +}))(IssueDetails); diff --git a/frontend/app/components/Session_/Issues/IssueForm.js b/frontend/app/components/Session_/Issues/IssueForm.js new file mode 100644 index 000000000..f305c3ee7 --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssueForm.js @@ -0,0 +1,154 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Form, Input, Button, Dropdown, CircularLoader } from 'UI'; +//import { } from 'Duck/issues'; +import { addActivity, init, edit, fetchAssignments, fetchMeta } from 'Duck/assignments'; + +const SelectedValue = ({ icon, text }) => { + return( + <div className="flex items-center"> + <img className="mr-2" src={ icon } width="13" height="13" /> + <span>{ text }</span> + </div> + ) +} + +class IssueForm extends React.PureComponent { + componentDidMount() { + const { projects, issueTypes } = this.props; + this.props.init({ + projectId: projects.first() ? projects.first().id : '', + issueType: issueTypes.first() ? issueTypes.first().id : '' + }); + } + + componentWillReceiveProps(newProps) { + const { instance } = this.props; + if (instance.projectId && newProps.instance.projectId != instance.projectId) { + this.props.fetchMeta(instance.projectId).then(() => { + this.props.edit({ issueType: '', assignee: '', projectId: newProps.instance.projectId }); + }); + } + } + + onSubmit = () => { + const { sessionId, addActivity } = this.props; + const { instance } = this.props; + + addActivity(sessionId, instance).then(() => { + const { errors } = this.props; + if (errors.length === 0) { + this.props.init({projectId: instance.projectId}); + this.props.fetchAssignments(sessionId); + this.props.closeHandler(); + } + }); + } + + write = ({ target: { name, value } }) => this.props.edit({ [ name ]: value }); + writeOption = (e, { name, value }) => this.props.edit({ [ name ]: value }); + + render() { + const { creating, projects, users, issueTypes, instance, closeHandler, metaLoading } = this.props; + const projectOptions = projects.map(({name, id}) => ({text: name, value: id })).toArray(); + const userOptions = users.map(({name, id}) => ({text: name, value: id })).toArray(); + const issueTypeOptions = issueTypes.map(({name, id, iconUrl }) => { + return {text: name, value: id, iconUrl, icon: <img className="pt-2" src={ iconUrl } /> } + }).toArray(); + + const selectedIssueType = issueTypes.filter(issue => issue.id == instance.issueType).first(); + + return ( + <Form onSubmit={ this.onSubmit }> + <Form.Field className="mb-15-imp"> + <label htmlFor="issueType"> + <span className="mr-2">Project</span> + <CircularLoader loading={ metaLoading } /> + </label> + <Dropdown + selection + name="projectId" + options={ projectOptions } + value={ instance.projectId } + fluid + onChange={ this.writeOption } + placeholder="Project" + /> + </Form.Field> + <Form.Field className="mb-15-imp"> + <label htmlFor="issueType">Issue Type</label> + <Dropdown + selection + name="issueType" + options={ issueTypeOptions } + value={ instance.issueType } + fluid + onChange={ this.writeOption } + placeholder="Select issue type" + text={ selectedIssueType ? <SelectedValue icon={ selectedIssueType.iconUrl } text={ selectedIssueType.name } /> : '' } + /> + </Form.Field> + + <Form.Field className="mb-15-imp"> + <label htmlFor="assignee">Assignee</label> + <Dropdown + selection + name="assignee" + options={ userOptions } + value={ instance.assignee } + fluid + onChange={ this.writeOption } + placeholder="Select a user" + /> + </Form.Field> + + <Form.Field className="mb-15-imp"> + <label htmlFor="title">Summary</label> + <Input + name="title" + value={ instance.title } + placeholder='Issue Title / Summary' + onChange={ this.write } + /> + </Form.Field> + + <Form.Field className="mb-15-imp"> + <label htmlFor="description"> + Description + {/* <span className="text-sm text-gray-500">(Optional)</span> */} + </label> + <textarea + name="description" + rows="2" + value={ instance.description } + placeholder="E.g. Found this issue at 3:29secs" + onChange={ this.write } + /> + </Form.Field> + + <Button + loading={ creating } + primary + disabled={ !instance.validate() } + marginRight + // outline + >{'Create'}</Button> + <Button + type="button" + outline + onClick={ closeHandler } + >{'Cancel'}</Button> + </Form> + ); + } +} + +export default connect(state => ({ + creating: state.getIn(['assignments', 'addActivity', 'loading']), + projects: state.getIn(['assignments', 'projects']), + users: state.getIn(['assignments', 'users']), + instance: state.getIn(['assignments', 'instance']), + metaLoading: state.getIn(['assignments', 'fetchMeta', 'loading']), + issueTypes: state.getIn(['assignments', 'issueTypes']), + errors: state.getIn([ 'assignments', 'addActivity', 'errors' ]) +}), { addActivity, init, edit, fetchAssignments, fetchMeta })(IssueForm) diff --git a/frontend/app/components/Session_/Issues/IssueHeader.js b/frontend/app/components/Session_/Issues/IssueHeader.js new file mode 100644 index 000000000..604d2352e --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssueHeader.js @@ -0,0 +1,34 @@ +import React from 'react'; +import { Icon, Input } from 'UI'; +import ActiveIssueClose from './ActiveIssueClose'; +import stl from './issueHeader.css'; + +const GotoSessionLink = props => ( + <a className="flex items-center absolute right-0 mr-3 cursor-pointer"> + {'Go to session'} + <Icon name="next1" size="16" /> + </a> +) + +const IssueHeader = ({issue, typeIcon, assignee}) => { + return ( + <div className="relative p-6 bg-white"> + {/* <GotoSessionLink /> */} + {/* <ActiveIssueClose /> */} + <div className="flex leading-none mb-2 items-center"> + <img className="mr-2" src={typeIcon} alt="" width={16} height={16} /> + <span className="mr-2 font-medium">{ issue.id }</span> + {/* <div className="text-gray-700 text-sm">{ '@ 00:13 Secs'}</div> */} + { assignee && + <div> + <span className="text-gray-600 mr-2">{'Assigned to'}</span> + <span className="font-medium" key={ assignee.id }>{ assignee.name }</span> + </div> + } + </div> + <h2 className="text-xl font-medium mb-2 truncate">{issue.title}</h2> + </div> + ); +}; + +export default IssueHeader; diff --git a/frontend/app/components/Session_/Issues/IssueListItem.js b/frontend/app/components/Session_/Issues/IssueListItem.js new file mode 100644 index 000000000..9145ffaa5 --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssueListItem.js @@ -0,0 +1,36 @@ +import React from 'react'; +import cn from 'classnames'; +import { Popup } from 'UI'; +import stl from './issueListItem.css'; + +const IssueListItem = ({ issue, onClick, icon, user, active }) => { + return ( + <div + onClick={ () => onClick(issue) } + className={ cn(stl.wrapper, active ? 'active-bg' : '', 'flex flex-col justify-between cursor-pointer text-base text-gray-800')} + > + <div className="flex items-center justify-between"> + <div className="flex items-center"> + <img src={ icon } width="16" height="16" className="mr-3" /> + <span>{ issue.id }</span> + </div> + <div className="flex items-center"> + { user && + <Popup + trigger={ + <img src={ user.avatarUrls['24x24'] } width="24" height="24" /> + } + content={ 'Assignee ' + user.name } + size="small" + position="top right" + inverted + /> + } + </div> + </div> + <div className={ stl.title }>{ issue.title }</div> + </div> + ); +}; + +export default IssueListItem; diff --git a/frontend/app/components/Session_/Issues/Issues.js b/frontend/app/components/Session_/Issues/Issues.js new file mode 100644 index 000000000..66fc80bc8 --- /dev/null +++ b/frontend/app/components/Session_/Issues/Issues.js @@ -0,0 +1,136 @@ +import React from 'react'; +import { connect } from 'react-redux'; +// import cn from 'classnames'; +import { SlideModal, Popup, Button, Icon, SplitButton } from 'UI'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import IssuesModal from './IssuesModal'; +// import { fetchIssue } from 'Duck/issues'; +import { fetchProjects, fetchAssignments, fetchMeta, fetchAssigment } from 'Duck/assignments'; +import SessionIssuesPanel from './SessionIssuesPanel'; +import IssueDetails from './IssueDetails'; +import withToggle from 'HOCs/withToggle'; +// import { withRequest } from 'HOCs'; +import stl from './issues.css'; + +@connect(state => ({ + issues: state.getIn(['assignments', 'list']), + metaLoading: state.getIn(['assignments', 'fetchMeta', 'loading']), + projects: state.getIn(['assignments', 'projects']), + projectsFetched: state.getIn(['assignments', 'projectsFetched']), + activeIssue: state.getIn(['assignments', 'activeIssue']), + fetchIssueLoading: state.getIn(['assignments', 'fetchAssignment', 'loading']), + fetchIssuesLoading: state.getIn(['assignments', 'fetchAssignments', 'loading']), + projectsLoading: state.getIn(['assignments', 'fetchProjects', 'loading']), + provider: state.getIn([ 'issues', 'list']).provider, +}), { fetchAssigment, fetchAssignments, fetchMeta, fetchProjects }) +@withToggle('isModalDisplayed', 'toggleModal') +class Issues extends React.Component { + state = {showModal: false }; + + constructor(props) { + super(props); + this.state = { showModal: false }; + if (!props.projectsFetched) { // cache projects fetch + this.props.fetchProjects().then(function() { + const { projects } = this.props; + if (projects && projects.first()) { + this.props.fetchMeta(projects.first().id) + } + }.bind(this)) + } + this.props.fetchAssignments(this.props.sessionId) + } + + closeModal = () => { + if (!this.props.isModalDisplayed) return; + this.props.toggleModal(); + } + + onIssueClick = (issue) => { + const { sessionId } = this.props; + this.setState({ showModal: true }); + this.props.fetchAssigment(sessionId, issue.id); + + if (this.props.isModalDisplayed) + this.props.toggleModal(); + } + + showIssuesList = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.setState({ showModal: true }); + } + + render() { + const { + sessionId, activeIssue, isModalDisplayed, projectsLoading, + fetchIssueLoading, issues, metaLoading, fetchIssuesLoading, provider + } = this.props; + const { showModal } = this.state; + + return ( + <div className="relative"> + <div className={ stl.buttonWrapper} > + <Popup + open={ isModalDisplayed } + onOpen={ this.handleOpen } + onClose={ this.handleClose } + trigger={ issues.size === 0 ? + <Button + outline + onClick={ this.props.toggleModal } + className={ stl.button } + size="small" + disabled={!isModalDisplayed && (metaLoading || fetchIssuesLoading || projectsLoading)} + > + <div className="h-full flex items-center"> + <Icon name={ `integrations/${ provider === 'jira' ? 'jira' : 'github'}` } size="16" color="teal" /> + <span className="ml-2">Report Issue</span> + </div> + </Button> + : <SplitButton + primary + disabled={!isModalDisplayed && (metaLoading || fetchIssuesLoading || projectsLoading)} + onIconClick={ this.props.toggleModal } + onButtonClick={ this.showIssuesList } + label="Issues" + icon="plus" + /> + } + on="click" + position="top right" + content={ + <OutsideClickDetectingDiv onClickOutside={this.closeModal}> + <IssuesModal + provider={provider} + sessionId={ sessionId } + closeHandler={ this.closeModal } + /> + </OutsideClickDetectingDiv> + } + /> + </div> + + <SlideModal + title={ `This session's issues` } + size="small" + isDisplayed={ showModal } + content={ showModal && + <SessionIssuesPanel + activeIssue={ activeIssue } + onIssueClick={ this.onIssueClick } + /> + } + detailContent={ ((activeIssue && activeIssue.id) || fetchIssueLoading) && + <div style={ { width: '600px'} }> + <IssueDetails issue={ activeIssue } sessionId={sessionId}/> + </div> + } + onClose={ () => this.setState({ showModal: false }) } + /> + </div> + ); + } +}; + +export default Issues; diff --git a/frontend/app/components/Session_/Issues/IssuesModal.js b/frontend/app/components/Session_/Issues/IssuesModal.js new file mode 100644 index 000000000..448d02486 --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssuesModal.js @@ -0,0 +1,22 @@ +import React from 'react'; +import stl from './issuesModal.css'; +import IssueForm from './IssueForm'; +import { Icon } from 'UI'; + +const IssuesModal = React.forwardRef(({ + sessionId, + closeHandler, + provider +}) => { + return ( + <div className={ stl.wrapper }> + <h3 className="mb-6 text-lg flex items-center"> + {/* <Icon name={headerIcon} size="18" color="color-gray-darkest" /> */} + <span>{`Report an Issue on ${provider === 'jira' ? 'Jira' : 'Github'}`}</span> + </h3> + <IssueForm sessionId={ sessionId } closeHandler={ closeHandler } /> + </div> + ); +}) + +export default IssuesModal; diff --git a/frontend/app/components/Session_/Issues/IssuesSortDropdown.js b/frontend/app/components/Session_/Issues/IssuesSortDropdown.js new file mode 100644 index 000000000..6c71225e1 --- /dev/null +++ b/frontend/app/components/Session_/Issues/IssuesSortDropdown.js @@ -0,0 +1,49 @@ +import { connect } from 'react-redux'; +import { Dropdown } from 'semantic-ui-react'; +import { IconButton } from 'UI'; +import { sort } from 'Duck/sessions'; +import { applyFilter } from 'Duck/filters'; + +const sessionSortOptions = { +// '': 'All', + 'open': 'Open', + 'closed': 'Closed', +}; + +const sortOptions = Object.entries(sessionSortOptions) + .map(([ value, text ]) => ({ value, text })); + +const IssuesSortDropdown = ({ onChange, value }) => { + // sort = (e, { value }) => { + // const [ sort, order ] = value.split('-'); + // const sign = order === 'desc' ? -1 : 1; + // this.props.applyFilter({ order, sort }); + + // this.props.sort(sort, sign) + // setTimeout(() => this.props.sort(sort, sign), 3000); + // } + + return ( + <Dropdown + name="issueType" + value={ value || sortOptions[ 0 ].value} + trigger={ + <IconButton + // outline + label="" + icon="filter" + size="medium" + // shadow + className="outline-none" + /> + } + pointing="top right" + options={ sortOptions } + onChange={ onChange } + // defaultValue={ sortOptions[ 0 ].value } + icon={ null } + /> + ); +} + +export default IssuesSortDropdown; diff --git a/frontend/app/components/Session_/Issues/SessionIssuesPanel.js b/frontend/app/components/Session_/Issues/SessionIssuesPanel.js new file mode 100644 index 000000000..851b443c9 --- /dev/null +++ b/frontend/app/components/Session_/Issues/SessionIssuesPanel.js @@ -0,0 +1,66 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { getRE } from 'App/utils'; +import { Input } from 'UI'; +import IssueListItem from './IssueListItem'; +import IssuesSortDropdown from './IssuesSortDropdown'; + +class SessionIssuesPanel extends React.Component { + state = { search: '', closed: false, issueType: 'open' } + write = ({ target: { value, name } }) => this.setState({ [ name ]: value }); + writeOption = (e, { name, value }) => this.setState({ [ name ]: value }); + + render() { + const { issueTypeIcons, users, activeIssue, issues = [], onIssueClick = () => null } = this.props; + const { search, closed, issueType } = this.state; + + let filteredIssues = issues.filter(({ closed, title }) => getRE(search, 'i').test(title)) + if (!issueType !== '') { + filteredIssues = filteredIssues.filter(({ closed }) => closed === ( this.state.issueType === 'closed')) + } + // .filter(({ closed }) => closed == this.state.closed); + + filteredIssues = filteredIssues.map(issue => { + issue.user = users.filter(user => user.id === issue.assignee).first(); + return issue; + }); + + return ( + <div> + <div className="p-3 bg-white flex items-center justify-between"> + <Input + name="search" + className="flex-1 mr-4" + icon="search" + iconPosition="left" + placeholder="Search" + onChange={ this.write } + /> + <IssuesSortDropdown + onChange={ this.writeOption } + value={ issueType } + /> + </div> + <div> + { filteredIssues.map(issue => ( + <IssueListItem + key={ issue.key } + onClick={ () => onIssueClick(issue) } + issue={ issue } + icon={ issueTypeIcons[issue.issueType] } + user={ issue.user } + active={ activeIssue && activeIssue.id === issue.id } + /> + )) + } + </div> + </div> + ); + } +} + +export default connect(state => ({ + issues: state.getIn(['assignments', 'list']), + issueTypeIcons: state.getIn(['assignments', 'issueTypeIcons']), + users: state.getIn(['assignments', 'users']), +}))(SessionIssuesPanel); diff --git a/frontend/app/components/Session_/Issues/contentRender.css b/frontend/app/components/Session_/Issues/contentRender.css new file mode 100644 index 000000000..d18d50630 --- /dev/null +++ b/frontend/app/components/Session_/Issues/contentRender.css @@ -0,0 +1,32 @@ + + +.codeMirror > div { + border: 1px solid #eee; + height: auto; +} + +.para { + padding: 3px 0; +} +.mention { + font-weight: 500; + margin-right: 5px; +} + +.quote { + padding: 5px; + padding-left: 10px; + border-left: solid 2px $gray-light; + color: $gray-dark; + margin: 5px 0; + margin-left: 10px; +} + +.code { + background-color: lightgray; + padding: 2px 5px; +} + +.rule { + margin: 6px 0; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Issues/index.js b/frontend/app/components/Session_/Issues/index.js new file mode 100644 index 000000000..161b5b097 --- /dev/null +++ b/frontend/app/components/Session_/Issues/index.js @@ -0,0 +1,2 @@ +export { defualt as Issues } from './Issues'; +export { defualt as IssueModal } from './IssuesModal'; \ No newline at end of file diff --git a/frontend/app/components/Session_/Issues/issueDetails.css b/frontend/app/components/Session_/Issues/issueDetails.css new file mode 100644 index 000000000..40d132a04 --- /dev/null +++ b/frontend/app/components/Session_/Issues/issueDetails.css @@ -0,0 +1,8 @@ +.activitiesList { + max-height: calc(100vh - 186px); + overflow-y: auto; + + &::-webkit-scrollbar { + width: 4px; + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Issues/issueHeader.css b/frontend/app/components/Session_/Issues/issueHeader.css new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/app/components/Session_/Issues/issueListItem.css b/frontend/app/components/Session_/Issues/issueListItem.css new file mode 100644 index 000000000..73ed34c6f --- /dev/null +++ b/frontend/app/components/Session_/Issues/issueListItem.css @@ -0,0 +1,21 @@ + + +.title { + max-width: 90%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.wrapper { + transition: all 0.4s; + padding: 8px 14px; + /* margin: 0 -14px; */ + height: 70px; + background-color: white; + border-bottom: solid thin $gray-light; + &:hover { + background-color: $active-blue; + transition: all 0.2s; + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Issues/issues.css b/frontend/app/components/Session_/Issues/issues.css new file mode 100644 index 000000000..07b79c740 --- /dev/null +++ b/frontend/app/components/Session_/Issues/issues.css @@ -0,0 +1,20 @@ +.modal { + width: 400px; + z-index: 999; +} + +.buttonWrapper { + height: 36px; + display: flex; + align-items: center; + /* &:hover { + background-color: white; + } */ +} +.button { + height: 36px !important; + display: flex !important; + &:hover { + background-color: $active-blue !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Issues/issuesModal.css b/frontend/app/components/Session_/Issues/issuesModal.css new file mode 100644 index 000000000..d5768976a --- /dev/null +++ b/frontend/app/components/Session_/Issues/issuesModal.css @@ -0,0 +1,6 @@ +.wrapper { + background-color: white; + width: 350px; + border-radius: 3px; + padding: 10px 8px; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Issues/issuesModal.stories.js b/frontend/app/components/Session_/Issues/issuesModal.stories.js new file mode 100644 index 000000000..6e71a3705 --- /dev/null +++ b/frontend/app/components/Session_/Issues/issuesModal.stories.js @@ -0,0 +1,310 @@ +import { storiesOf } from '@storybook/react'; +import { List } from 'immutable'; +import IssuesModal from './IssuesModal'; +import IssueHeader from './IssueHeader'; +import IssueComment from './IssueComment'; +import IssueCommentForm from './IssueCommentForm'; +import IssueDetails from './IssueDetails'; +import SessionIssuesPanel from './SessionIssuesPanel'; +import IssueForm from './IssueForm'; +import IssueListItem from './IssueListItem'; +import IssueDescription from './IssueDescription'; + +const description = { + "version": 1, + "type": "doc", + "content": [ + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "test para" + } + ] + }, + { + "type": "blockquote", + "content": [ + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "test quote" + } + ] + } + ] + }, + { + "type": "rule" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "another para" + } + ] + }, + { + "type": "paragraph", + "content": [] + }, + { + "type": "paragraph", + "content": [] + }, + { + "type": "codeBlock", + "attrs": {}, + "content": [ + { + "type": "text", + "text": "var d = \"test code\"\nvar e = \"test new line\"" + } + ] + }, + { + "type": "paragraph", + "content": [] + } + ] +} +const issueTypeIcons = { + '1': 'https://openreplay.atlassian.net/secure/viewavatar?size=medium&avatarId=10310&avatarType=issuetype', +} +const issueTypes = [ + { + id: 1, + iconUrl: 'https://openreplay.atlassian.net/secure/viewavatar?size=medium&avatarId=10310&avatarType=issuetype', + name: 'Improvement' + }, + { + id: 2, + iconUrl: 'https://openreplay.atlassian.net/secure/viewavatar?size=medium&avatarId=10310&avatarType=issuetype', + name: 'Bug' + } +] +const user = { + id: 1, + name: 'test', + avatarUrls: { + "16x16": "https://secure.gravatar.com/avatar/900294aa68b33490b16615b57e9709fc?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FMO-3.png&size=16&s=16", + "24x24": "https://secure.gravatar.com/avatar/900294aa68b33490b16615b57e9709fc?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FMO-3.png&size=24&s=24" + } +} +const activities = [ + { + id: 1, + message: { + "version": 1, + "type": "doc", + "content": [ + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "First Para" + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Second para" + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Third para", + "marks": [ + { + "type": "strong" + } + ] + } + ] + }, + { + "type": "blockquote", + "content": [ + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Quote" + } + ] + } + ] + }, + { + "type": "paragraph", + "content": [] + }, + { + "type": "codeBlock", + "attrs": {}, + "content": [ + { + "type": "text", + "text": "alert('test')\nvar dd = \"Another line\"" + } + ] + }, + { + "type": "rule" + }, + { + "type": "paragraph", + "content": [ + { + "type": "mention", + "attrs": { + "id": "5d8398868a50e80c2feed3f6", + "text": "Someone" + } + }, + { + "type": "text", + "text": " " + } + ] + }, + { + "type": "paragraph", + "content": [] + }, + { + "type": "codeBlock", + "attrs": { + "language": "javascript" + }, + "content": [ + { + "type": "text", + "text": "var d = \"test\"" + } + ] + }, + { + "type": "paragraph", + "content": [] + } + ] + }, + author: 1, + user: user + }, + { + id: 1, + message: { + "version": 1, + "type": "doc", + "content": [ + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "happy debugging" + } + ] + } + ] + }, + author: 1, + user: user + } +] +const issues = [ + { + title: 'Crash Report - runtime error: index out of range', + description: description, + commentsCount: 4, + activities: List(activities), + assignee: user.id, + issueType: 1, + id: 'APP-222' + }, + { + title: 'this is the second one', + description: description, + commentsCount: 10, + activities: activities, + assignee: user.id, + issueType: 1, + id: 'APP-333' + }, + { + title: 'this is the third one', + description: description, + commentsCount: 0, + activities: activities, + assignee: user.id, + issueType: 1, + id: 'APP-444' + } +]; + +const onIssueClick = (issue) => { + console.log(issue); +} + +storiesOf('Issues', module) + .add('IssuesModal', () => ( + <IssuesModal issues={ issues } /> + )) + .add('IssueHeader', () => ( + <IssueHeader issue={ issues[0] } typeIcon={ issueTypeIcons[1] }/> + )) + .add('IssueComment', () => ( + <div className="p-4"> + <IssueComment activity={ activities[0] } /> + </div> + )) + .add('IssueDescription', () => ( + <div className="p-4 bg-gray-100"> + <IssueDescription description={ description } /> + </div> + )) + .add('IssueCommentForm', () => ( + <IssueCommentForm /> + )) + .add('IssueDetails', () => ( + <IssueDetails + sessionId={ 1} + issue={ issues[0] } + users={ List([user]) } + issueTypeIcons={ issueTypeIcons } + /> + )) + .add('IssueListItem', () => ( + <IssueListItem issue={ issues[0] } icon={ issueTypeIcons[1] } user={ user } /> + )) + .add('IssueForm', () => ( + <div className="p-4"> + <IssueForm issueTypes={ List(issueTypes) } /> + </div> + )) + .add('SessionIssuesPanel', () => ( + <div className="bg-white"> + <SessionIssuesPanel + issues={ issues } + onIssueClick={ onIssueClick } + issueTypeIcons={ issueTypeIcons } + /> + </div> + )) + diff --git a/frontend/app/components/Session_/Issues/sessionIssuesPanel.css b/frontend/app/components/Session_/Issues/sessionIssuesPanel.css new file mode 100644 index 000000000..d13bcfbbf --- /dev/null +++ b/frontend/app/components/Session_/Issues/sessionIssuesPanel.css @@ -0,0 +1,9 @@ + + +.searchInput { + padding: 10px 6px !important; + + &:focus { + border-color: $teal !important; + } + } \ No newline at end of file diff --git a/frontend/app/components/Session_/LongTasks/LongTasks.js b/frontend/app/components/Session_/LongTasks/LongTasks.js new file mode 100644 index 000000000..1baa7a2eb --- /dev/null +++ b/frontend/app/components/Session_/LongTasks/LongTasks.js @@ -0,0 +1,121 @@ +//import cn from 'classnames'; +import { Icon, NoContent, Input, SlideModal, QuestionMarkHint } from 'UI'; +import { getRE } from 'App/utils'; +import { connectPlayer, jump } from 'Player'; +import BottomBlock from '../BottomBlock'; +import TimeTable from '../TimeTable'; + + +const CONTEXTS = [ "unknown", "self", "same-origin-ancestor", "same-origin-descendant", "same-origin", "cross-origin-ancestor", "cross-origin-descendant", "cross-origin-unreachable", "multiple-contexts" ]; +const CONTAINER_TYPES = [ "window", "iframe", "embed", "object" ]; + +function renderContext({ context }) { + return CONTEXTS[ context ]; +} + +function renderDuration({ duration }) { + return `${ duration }ms`; +} + +function renderContainerType({ containerType }) { + return CONTAINER_TYPES[ containerType ] +} + +@connectPlayer(state => ({ + list: state.longtasksList, + time: state.time, +})) +export default class GraphQL extends React.PureComponent { + state = { + filter: "", + } + onFilterChange = (e, { value }) => this.setState({ filter: value }) + + jump = ({ time }) => { + jump(time); + } + + render() { + const { list, time} = this.props; + const { filter, current } = this.state; + const filterRE = getRE(filter, 'i'); + const filtered = list + .filter(({ containerType, context, containerName = "", containerId = "", containerSrc="" }) => + filterRE.test(containerName) || + filterRE.test(containerId) || + filterRE.test(containerSrc) || + filterRE.test(CONTEXTS[ context ]) || + filterRE.test(CONTAINER_TYPES[ containerType ])); + const lastIndex = filtered.filter(item => item.time <= time).length - 1; + return ( + <BottomBlock> + <BottomBlock.Header> + <h4 className="text-lg">Long Tasks</h4> + <div className="flex items-center"> + <Input + className="input-small mr-3" + style={{ width: "350px" }} + placeholder="Filter by Context or Container Type/Id/Src" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + <QuestionMarkHint + content={ + <> + <a className="color-teal underline mr-2" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Long_Tasks_API">Learn more </a> + about Long Tasks API + </> + } + // className="mr-4" + /> + </div> + </BottomBlock.Header> + <BottomBlock.Content> + <NoContent + size="small" + show={ filtered.length === 0} + > + <TimeTable + rows={ filtered } + onRowClick={ this.jump } + hoverable + activeIndex={lastIndex} + > + {[ + { + label: "Context", + render: renderContext, + width: 140, + }, { + label: "Container Type", + width: 110, + render: renderContainerType, + }, + // { + // label: "ID", + // width: 70, + // dataKey: "containerId" + // }, { + // label: "Name", + // width: 70, + // dataKey: "containerName" + // }, { + // label: "SRC", + // width: 70, + // dataKey: "containerSrc" + // }, + { + label: "Duration", + width: 100, + render: renderDuration, + } + ]} + </TimeTable> + </NoContent> + </BottomBlock.Content> + </BottomBlock> + ); + } +} diff --git a/frontend/app/components/Session_/LongTasks/index.js b/frontend/app/components/Session_/LongTasks/index.js new file mode 100644 index 000000000..521f0e2a7 --- /dev/null +++ b/frontend/app/components/Session_/LongTasks/index.js @@ -0,0 +1 @@ +export { default } from './LongTasks'; diff --git a/frontend/app/components/Session_/Network/Network.js b/frontend/app/components/Session_/Network/Network.js new file mode 100644 index 000000000..b3ea3dafb --- /dev/null +++ b/frontend/app/components/Session_/Network/Network.js @@ -0,0 +1,290 @@ +import cn from 'classnames'; +import { connectPlayer } from 'Player'; +import { QuestionMarkHint, Popup, Tabs, Input } from 'UI'; +import { getRE } from 'App/utils'; +import { TYPES } from 'Types/session/resource'; +import { formatBytes } from 'App/utils'; +import { formatMs } from 'App/date'; + +import TimeTable from '../TimeTable'; +import BottomBlock from '../BottomBlock'; +import InfoLine from '../BottomBlock/InfoLine'; +import stl from './network.css'; +import NetworkContent from './NetworkContent'; + +const ALL = 'ALL'; +const XHR = 'xhr'; +const JS = 'js'; +const CSS = 'css'; +const IMG = 'img'; +const MEDIA = 'media'; +const OTHER = 'other'; + +const TAB_TO_TYPE_MAP = { + [ XHR ]: TYPES.XHR, + [ JS ]: TYPES.JS, + [ CSS ]: TYPES.CSS, + [ IMG ]: TYPES.IMG, + [ MEDIA ]: TYPES.MEDIA, + [ OTHER ]: TYPES.OTHER +} +const TABS = [ ALL, XHR, JS, CSS, IMG, MEDIA, OTHER ].map(tab => ({ + text: tab, + key: tab, +})); + +const DOM_LOADED_TIME_COLOR = "teal"; +const LOAD_TIME_COLOR = "red"; + +export function renderName(r) { + return ( + <Popup + trigger={ <div className={ stl.popupNameTrigger }>{ r.name }</div> } + content={ <div className={ stl.popupNameContent }>{ r.url }</div> } + size="mini" + position="right center" + /> + ); +} + +const renderXHRText = () => ( + <span className="flex items-center"> + {XHR} + <QuestionMarkHint + onHover + content={ + <> + Use our <a className="color-teal underline" target="_blank" href="https://docs.openreplay.com/plugins/fetch">Fetch plugin</a> + {' to capture HTTP requests and responses, including status codes and bodies.'} <br/> + We also provide <a className="color-teal underline" target="_blank" href="https://docs.openreplay.com/plugins/graphql">support for GraphQL</a> + {' for easy debugging of your queries.'} + </> + } + className="ml-1" + /> + </span> +); + +function renderSize(r) { + let triggerText; + let content; + if (r.decodedBodySize == null) { + triggerText = "x"; + content = "Not captured"; + } else { + const headerSize = r.headerSize || 0; + const encodedSize = r.encodedBodySize || 0; + const transferred = headerSize + encodedSize; + const showTransferred = r.headerSize != null; + + triggerText = formatBytes(r.decodedBodySize); + content = ( + <ul> + { showTransferred && + <li>{`${formatBytes( r.encodedBodySize + headerSize )} transfered over network`}</li> + } + <li>{`Resource size: ${formatBytes(r.decodedBodySize)} `}</li> + </ul> + ); + } + + return ( + <Popup + trigger={ <div>{ triggerText }</div> } + content={ content } + size="mini" + position="right center" + /> + ); +} + +export function renderDuration(r) { + if (!r.success) return 'x'; + + const text = `${ r.duration }ms`; + if (!r.isRed() && !r.isYellow()) return text; + + let tooltipText; + let className = "w-full h-full flex items-center "; + if (r.isYellow()) { + tooltipText = "Slower than average"; + className += "warn color-orange"; + } else { + tooltipText = "Much slower than average"; + className += "error color-red"; + } + + return ( + <Popup + content={ tooltipText } + inverted + trigger={ + <div className={ cn(className, stl.duration) } > { text } </div> + } + /> + ); +} + +@connectPlayer(state => ({ + location: state.location, + resources: state.resourceList, + domContentLoadedTime: state.domContentLoadedTime, + loadTime: state.loadTime, + time: state.time, + domBuildingTime: state.domBuildingTime, + fetchPresented: state.fetchList.length > 0, +})) +export default class Network extends React.PureComponent { + state = { + filter: '', + activeTab: ALL, + } + + onTabClick = activeTab => this.setState({ activeTab }) + onFilterChange = (e, { value }) => this.setState({ filter: value }) + + render() { + const { + location, + resources, + domContentLoadedTime, + loadTime, + domBuildingTime, + fetchPresented, + time + } = this.props; + const { filter, activeTab } = this.state; + const filterRE = getRE(filter, 'i'); + let filtered = resources.filter(({ type, name }) => + filterRE.test(name) && (activeTab === ALL || type === TAB_TO_TYPE_MAP[ activeTab ])); + + const referenceLines = []; + if (domContentLoadedTime != null) { + referenceLines.push({ + time: domContentLoadedTime, + color: DOM_LOADED_TIME_COLOR, + }) + } + if (loadTime != null) { + referenceLines.push({ + time: loadTime, + color: LOAD_TIME_COLOR, + }) + } + + let tabs = TABS; + if (!fetchPresented) { + tabs = TABS.map(tab => tab.key === XHR + ? { + text: renderXHRText(), + key: XHR, + } + : tab + ); + } + + const resourcesSize = filtered.reduce((sum, { decodedBodySize }) => sum + (decodedBodySize || 0), 0); + const transferredSize = filtered + .reduce((sum, { headerSize, encodedBodySize }) => sum + (headerSize || 0) + (encodedBodySize || 0), 0); + + return ( + <React.Fragment> + <NetworkContent + // {...this.props } + time = { time } + location = { location } + resources = { resources } + domContentLoadedTime = { domContentLoadedTime } + loadTime = { loadTime } + domBuildingTime = { domBuildingTime } + fetchPresented = { fetchPresented } + resourcesSize={resourcesSize} + transferredSize={transferredSize} + /> + {/* <BottomBlock> + <BottomBlock.Header> + <Tabs + className="uppercase" + tabs={ tabs } + active={ activeTab } + onClick={ this.onTabClick } + border={ false } + /> + <Input + className="input-small" + placeholder="Filter by Name" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + </BottomBlock.Header> + <BottomBlock.Content> + <InfoLine> + <InfoLine.Point label={ filtered.length } value=" requests" /> + <InfoLine.Point + label={ formatBytes(transferredSize) } + value="transferred" + display={ transferredSize > 0 } + /> + <InfoLine.Point + label={ formatBytes(resourcesSize) } + value="resources" + display={ resourcesSize > 0 } + /> + <InfoLine.Point + label="DOM Building Time" + value={ formatMs(domBuildingTime)} + display={ domBuildingTime != null } + /> + <InfoLine.Point + label="DOMContentLoaded" + value={ formatMs(domContentLoadedTime)} + display={ domContentLoadedTime != null } + dotColor={ DOM_LOADED_TIME_COLOR } + /> + <InfoLine.Point + label="Load" + value={ formatMs(loadTime)} + display={ loadTime != null } + dotColor={ LOAD_TIME_COLOR } + /> + </InfoLine> + <TimeTable + rows={ filtered } + referenceLines={referenceLines} + renderPopup + navigation + > + {[ + { + label: "Status", + dataKey: 'status', + width: 70, + }, { + label: "Type", + dataKey: 'type', + width: 60, + }, { + label: "Name", + width: 130, + render: renderName, + }, + { + label: "Size", + width: 60, + render: renderSize, + }, + { + label: "Time", + width: 80, + render: renderDuration, + } + ]} + </TimeTable> + </BottomBlock.Content> + </BottomBlock> */} + </React.Fragment> + ); + } +} diff --git a/frontend/app/components/Session_/Network/NetworkContent.js b/frontend/app/components/Session_/Network/NetworkContent.js new file mode 100644 index 000000000..1f10eaffe --- /dev/null +++ b/frontend/app/components/Session_/Network/NetworkContent.js @@ -0,0 +1,295 @@ +import cn from 'classnames'; +// import { connectPlayer } from 'Player'; +import { QuestionMarkHint, Popup, Tabs, Input } from 'UI'; +import { getRE } from 'App/utils'; +import { TYPES } from 'Types/session/resource'; +import { formatBytes } from 'App/utils'; +import { formatMs } from 'App/date'; + +import TimeTable from '../TimeTable'; +import BottomBlock from '../BottomBlock'; +import InfoLine from '../BottomBlock/InfoLine'; +import stl from './network.css'; + +const ALL = 'ALL'; +const XHR = 'xhr'; +const JS = 'js'; +const CSS = 'css'; +const IMG = 'img'; +const MEDIA = 'media'; +const OTHER = 'other'; + +const TAB_TO_TYPE_MAP = { + [ XHR ]: TYPES.XHR, + [ JS ]: TYPES.JS, + [ CSS ]: TYPES.CSS, + [ IMG ]: TYPES.IMG, + [ MEDIA ]: TYPES.MEDIA, + [ OTHER ]: TYPES.OTHER +} +const TABS = [ ALL, XHR, JS, CSS, IMG, MEDIA, OTHER ].map(tab => ({ + text: tab, + key: tab, +})); + +const DOM_LOADED_TIME_COLOR = "teal"; +const LOAD_TIME_COLOR = "red"; + +export function renderType(r) { + return ( + <Popup + trigger={ <div className={ stl.popupNameTrigger }>{ r.type }</div> } + content={ <div className={ stl.popupNameContent }>{ r.type }</div> } + size="mini" + position="right center" + /> + ); +} + +export function renderName(r) { + return ( + <Popup + trigger={ <div className={ stl.popupNameTrigger }>{ r.name }</div> } + content={ <div className={ stl.popupNameContent }>{ r.url }</div> } + size="mini" + position="right center" + /> + ); +} + +const renderXHRText = () => ( + <span className="flex items-center"> + {XHR} + <QuestionMarkHint + content={ + <> + Use our <a className="color-teal underline" target="_blank" href="https://docs.openreplay.com/plugins/fetch">Fetch plugin</a> + {' to capture HTTP requests and responses, including status codes and bodies.'} <br/> + We also provide <a className="color-teal underline" target="_blank" href="https://docs.openreplay.com/plugins/graphql">support for GraphQL</a> + {' for easy debugging of your queries.'} + </> + } + className="ml-1" + /> + </span> +); + +function renderSize(r) { + if (r.responseBodySize) return formatBytes(r.responseBodySize); + let triggerText; + let content; + if (r.decodedBodySize == null) { + triggerText = "x"; + content = "Not captured"; + } else { + const headerSize = r.headerSize || 0; + const encodedSize = r.encodedBodySize || 0; + const transferred = headerSize + encodedSize; + const showTransferred = r.headerSize != null; + + triggerText = formatBytes(r.decodedBodySize); + content = ( + <ul> + { showTransferred && + <li>{`${formatBytes( r.encodedBodySize + headerSize )} transfered over network`}</li> + } + <li>{`Resource size: ${formatBytes(r.decodedBodySize)} `}</li> + </ul> + ); + } + + return ( + <Popup + trigger={ <div>{ triggerText }</div> } + content={ content } + size="mini" + position="right center" + /> + ); +} + +export function renderDuration(r) { + if (!r.success) return 'x'; + + const text = `${ Math.floor(r.duration) }ms`; + if (!r.isRed() && !r.isYellow()) return text; + + let tooltipText; + let className = "w-full h-full flex items-center "; + if (r.isYellow()) { + tooltipText = "Slower than average"; + className += "warn color-orange"; + } else { + tooltipText = "Much slower than average"; + className += "error color-red"; + } + + return ( + <Popup + content={ tooltipText } + inverted + trigger={ + <div className={ cn(className, stl.duration) } > { text } </div> + } + /> + ); +} + +export default class NetworkContent extends React.PureComponent { + state = { + filter: '', + activeTab: ALL, + } + + onTabClick = activeTab => this.setState({ activeTab }) + onFilterChange = (e, { value }) => this.setState({ filter: value }) + + render() { + const { + location, + resources, + domContentLoadedTime, + loadTime, + domBuildingTime, + fetchPresented, + onRowClick, + isResult = false, + additionalHeight = 0, + resourcesSize, + transferredSize, + time + } = this.props; + const { filter, activeTab } = this.state; + const filterRE = getRE(filter, 'i'); + let filtered = resources.filter(({ type, name }) => + filterRE.test(name) && (activeTab === ALL || type === TAB_TO_TYPE_MAP[ activeTab ])); + const lastIndex = filtered.filter(item => item.time <= time).length - 1; + + const referenceLines = []; + if (domContentLoadedTime != null) { + referenceLines.push({ + time: domContentLoadedTime, + color: DOM_LOADED_TIME_COLOR, + }) + } + if (loadTime != null) { + referenceLines.push({ + time: loadTime, + color: LOAD_TIME_COLOR, + }) + } + + let tabs = TABS; + if (!fetchPresented) { + tabs = TABS.map(tab => !isResult && tab.key === XHR + ? { + text: renderXHRText(), + key: XHR, + } + : tab + ); + } + + // const resourcesSize = filtered.reduce((sum, { decodedBodySize }) => sum + (decodedBodySize || 0), 0); + // const transferredSize = filtered + // .reduce((sum, { headerSize, encodedBodySize }) => sum + (headerSize || 0) + (encodedBodySize || 0), 0); + + return ( + <React.Fragment> + <BottomBlock style={{ height: 300 + additionalHeight + 'px' }} className="border"> + <BottomBlock.Header showClose={!isResult}> + <Tabs + className="uppercase" + tabs={ tabs } + active={ activeTab } + onClick={ this.onTabClick } + border={ false } + /> + <Input + className="input-small" + placeholder="Filter by Name" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + </BottomBlock.Header> + <BottomBlock.Content> + {/* <div className={ stl.location }> */} + {/* <Icon name="window" marginRight="8" /> */} + {/* <div>{ location }</div> */} + {/* <div></div> */} + {/* </div> */} + <InfoLine> + <InfoLine.Point label={ filtered.length } value=" requests" /> + <InfoLine.Point + label={ formatBytes(transferredSize) } + value="transferred" + display={ transferredSize > 0 } + /> + <InfoLine.Point + label={ formatBytes(resourcesSize) } + value="resources" + display={ resourcesSize > 0 } + /> + <InfoLine.Point + label="DOM Building Time" + value={ formatMs(domBuildingTime)} + display={ domBuildingTime != null } + /> + <InfoLine.Point + label="DOMContentLoaded" + value={ formatMs(domContentLoadedTime)} + display={ domContentLoadedTime != null } + dotColor={ DOM_LOADED_TIME_COLOR } + /> + <InfoLine.Point + label="Load" + value={ formatMs(loadTime)} + display={ loadTime != null } + dotColor={ LOAD_TIME_COLOR } + /> + </InfoLine> + <TimeTable + rows={ filtered } + referenceLines={referenceLines} + renderPopup + // navigation + onRowClick={onRowClick} + additionalHeight={additionalHeight} + activeIndex={lastIndex} + > + {[ + { + label: "Status", + dataKey: 'status', + width: 70, + }, { + label: "Type", + dataKey: 'type', + width: 90, + render: renderType, + }, { + label: "Name", + width: 200, + render: renderName, + }, + { + label: "Size", + width: 60, + render: renderSize, + }, + { + label: "Time", + width: 80, + render: renderDuration, + } + ]} + </TimeTable> + </BottomBlock.Content> + </BottomBlock> + </React.Fragment> + ); + } +} + diff --git a/frontend/app/components/Session_/Network/index.js b/frontend/app/components/Session_/Network/index.js new file mode 100644 index 000000000..446e76ea6 --- /dev/null +++ b/frontend/app/components/Session_/Network/index.js @@ -0,0 +1,2 @@ +export { default } from './Network'; +export * from './Network'; diff --git a/frontend/app/components/Session_/Network/network.css b/frontend/app/components/Session_/Network/network.css new file mode 100644 index 000000000..eb37e49c9 --- /dev/null +++ b/frontend/app/components/Session_/Network/network.css @@ -0,0 +1,31 @@ + + +.location { + min-height: 32px; + display: flex; + align-items: center; + padding: 5px 10px; + font-size: 12px; + line-height: 12px; + + & > div:last-child { + font-weight: 300; + max-width: 80%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + padding: 5px 0; + } +} + +.popupNameTrigger { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + max-width: 100%; + width: fit-content; +} +.popupNameContent { + max-width: 600px; + overflow-wrap: break-word; +} diff --git a/frontend/app/components/Session_/Performance/Performance.js b/frontend/app/components/Session_/Performance/Performance.js new file mode 100644 index 000000000..b31d1ed85 --- /dev/null +++ b/frontend/app/components/Session_/Performance/Performance.js @@ -0,0 +1,548 @@ +import { connect } from 'react-redux'; +import { Controls as PlayerControls, connectPlayer } from 'Player'; +import { + AreaChart, + Area, + ComposedChart, + Line, + XAxis, + YAxis, + Tooltip, + ResponsiveContainer, + ReferenceLine, + CartesianGrid, + Label, +} from 'recharts'; +import { Checkbox } from 'UI'; +import { durationFromMsFormatted } from 'App/date'; +import { formatBytes } from 'App/utils'; + +import stl from './performance.css'; + +import BottomBlock from '../BottomBlock'; +import InfoLine from '../BottomBlock/InfoLine'; + + +const CPU_VISUAL_OFFSET = 10; + + +const FPS_COLOR = '#C5E5E7'; +const FPS_STROKE_COLOR = "#92C7CA"; +const FPS_LOW_COLOR = "pink"; +const FPS_VERY_LOW_COLOR = "red"; +const CPU_COLOR = "#A8D1DE"; +const CPU_STROKE_COLOR = "#69A5B8"; +const USED_HEAP_COLOR = '#A9ABDC'; +const USED_HEAP_STROKE_COLOR = "#8588CF"; +const TOTAL_HEAP_STROKE_COLOR = '#4A4EB7'; +const NODES_COUNT_COLOR = "#C6A9DC"; +const NODES_COUNT_STROKE_COLOR = "#7360AC"; +const HIDDEN_SCREEN_COLOR = "#CCC"; + + +const CURSOR_COLOR = "#394EFF"; + +const Gradient = ({ color, id }) => ( + <linearGradient id={ id } x1="-1" y1="0" x2="0" y2="1"> + <stop offset="5%" stopColor={ color } stopOpacity={ 0.7 } /> + <stop offset="95%" stopColor={ color } stopOpacity={ 0.2 } /> + </linearGradient> +); + + +const TOTAL_HEAP = "Allocated Heap"; +const USED_HEAP = "JS Heap"; +const FPS = "Framerate"; +const CPU = "CPU Load"; +const NODES_COUNT = "Nodes Сount"; + + +const FPSTooltip = ({ active, payload }) => { + if (!active || payload.length < 3) { + return null; + } + if (payload[0].value === null) { + return ( + <div className={ stl.tooltipWrapper } style={{ color: HIDDEN_SCREEN_COLOR }}> + {"Page is not active. User switched the tab or hid the window."} + </div> + ); + } + + let style; + if (payload[1].value != null && payload[1].value > 0) { + style = { color: FPS_LOW_COLOR }; + } + if (payload[2].value != null && payload[2].value > 0) { + style = { color: FPS_VERY_LOW_COLOR }; + } + + return ( + <div className={ stl.tooltipWrapper } style={ style }> + <span className="font-medium">{`${ FPS }: `}</span> + { Math.trunc(payload[0].value) } + </div> + ); +}; + +const CPUTooltip = ({ active, payload }) => { + if (!active || payload.length < 1 || payload[0].value === null) { + return null; + } + return ( + <div className={ stl.tooltipWrapper } > + <span className="font-medium">{`${ CPU }: `}</span> + { payload[0].value - CPU_VISUAL_OFFSET } + {"%"} + </div> + ); +}; + +const HeapTooltip = ({ active, payload}) => { + if (!active || payload.length < 2) return null; + return ( + <div className={ stl.tooltipWrapper } > + <p> + <span className="font-medium">{`${ TOTAL_HEAP }: `}</span> + { formatBytes(payload[0].value)} + </p> + <p> + <span className="font-medium">{`${ USED_HEAP }: `}</span> + { formatBytes(payload[1].value)} + </p> + </div> + ); +} + +const NodesCountTooltip = ({ active, payload} ) => { + if (!active || payload.length === 0) return null; + return ( + <div className={ stl.tooltipWrapper } > + <p> + <span className="font-medium">{`${ NODES_COUNT }: `}</span> + { payload[0].value } + </p> + </div> + ); +} + +const TICKS_COUNT = 10; +function generateTicks(data: Array<Timed>): Array<number> { + if (data.length === 0) return []; + console.log(data, data[0]) + const minTime = data[0].time; + const maxTime = data[data.length-1].time; + + const ticks = []; + const tickGap = (maxTime - minTime) / (TICKS_COUNT + 1); + for (let i = 0; i < TICKS_COUNT; i++) { + const tick = tickGap * (i + 1) + minTime; + ticks.push(tick); + } + return ticks; +} + +const LOW_FPS = 30; +const VERY_LOW_FPS = 20; +const LOW_FPS_MARKER_VALUE = 5; +const HIDDEN_SCREEN_MARKER_VALUE = 20; +function addFpsMetadata(data) { + return data.map((point, i) => { + let fpsVeryLowMarker = null; + let fpsLowMarker = null; + let hiddenScreenMarker = 0; + if (point.fps != null) { + fpsVeryLowMarker = 0; + fpsLowMarker = 0; + if (point.fps < VERY_LOW_FPS) { + fpsVeryLowMarker = LOW_FPS_MARKER_VALUE; + } else if (point.fps < LOW_FPS) { + fpsLowMarker = LOW_FPS_MARKER_VALUE; + } + } + if (point.fps == null || + (i > 0 && data[i - 1].fps == null) //|| + //(i < data.length-1 && data[i + 1].fps == null) + ) { + hiddenScreenMarker = HIDDEN_SCREEN_MARKER_VALUE; + } + if (point.cpu != null) { + point.cpu += CPU_VISUAL_OFFSET; + } + return { + ...point, + fpsLowMarker, + fpsVeryLowMarker, + hiddenScreenMarker, + } + }); +} + +@connect(state => ({ + userDeviceHeapSize: state.getIn([ "sessions", "current", "userDeviceHeapSize" ]), + userDeviceMemorySize: state.getIn([ "sessions", "current", "userDeviceMemorySize" ]), +})) +export default class Performance extends React.PureComponent { + _timeTicks = generateTicks(this.props.performanceChartData) + _data = addFpsMetadata(this.props.performanceChartData) + // state = { + // totalHeap: false, + // usedHeap: true, + // fps: true, + // } + // onCheckboxClick = (e, { name, checked }) => this.setState({ [ name ]: checked }) + + onDotClick = ({ index }) => { + const point = this._data[index]; + if (!!point) { + PlayerControls.jump(point.time); + } + } + + onChartClick = (e) => { + if (e === null) return; + const { activeTooltipIndex } = e; + const point = this._data[activeTooltipIndex]; + if (!!point) { + PlayerControls.jump(point.time); + } + } + + render() { + const { + userDeviceHeapSize, + userDeviceMemorySize, + connType, + connBandwidth, + performanceChartTime, + avaliability = {}, + } = this.props; + const { fps, cpu, heap, nodes } = avaliability; + const avaliableCount = [ fps, cpu, heap, nodes ].reduce((c, av) => av ? c + 1 : c, 0); + const height = avaliableCount === 0 ? "0" : `${100 / avaliableCount}%`; + + return ( + <BottomBlock> + <BottomBlock.Header> + <InfoLine> + <InfoLine.Point + label="Device Heap Size" + value={ formatBytes(userDeviceHeapSize) } + display={ userDeviceHeapSize != null } + /> + {/* <InfoLine.Point */} + {/* label="Device Memory Size" */} + {/* value={ formatBytes(userDeviceMemorySize*1e6) } */} + {/* /> */} + <InfoLine.Point + label="Connection Type" + value={ connType } + display={ connType != null && connType !== "unknown" } + /> + <InfoLine.Point + label="Connection Speed" + value={ connBandwidth >= 1000 + ? `${ connBandwidth / 1000 } Mbps` + : `${ connBandwidth } Kbps` + } + display={ connBandwidth != null } + /> + </InfoLine> + </BottomBlock.Header> + <BottomBlock.Content> + { fps && + <ResponsiveContainer height={ height }> + <AreaChart + onClick={ this.onChartClick } + data={this._data} + syncId="s" + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + > + <defs> + <Gradient id="fpsGradient" color={ FPS_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="1 1" stroke="#ddd" horizontal={ false } /> */} + {/* <CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={ false } + tickFormatter={ durationFromMsFormatted } + tick={{ fontSize: "12px" }} + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="FPS" position="insideTopRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={ false } + tick={ false } + mirror + domain={[0, 85]} + /> + {/* <YAxis */} + {/* yAxisId="r" */} + {/* axisLine={ false } */} + {/* tick={ false } */} + {/* mirror */} + {/* domain={[0, 120]} */} + {/* orientation="right" */} + {/* /> */} + <Area + dataKey="fps" + type="stepBefore" + stroke={FPS_STROKE_COLOR} + fill="url(#fpsGradient)" + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <Area + dataKey="fpsLowMarker" + type="stepBefore" + stroke="none" + fill={ FPS_LOW_COLOR } + activeDot={false} + isAnimationActive={ false } + /> + <Area + dataKey="fpsVeryLowMarker" + type="stepBefore" + stroke="none" + fill={ FPS_VERY_LOW_COLOR } + activeDot={false} + isAnimationActive={ false } + /> + <Area + dataKey="hiddenScreenMarker" + type="stepBefore" + stroke="none" + fill={ HIDDEN_SCREEN_COLOR } + activeDot={false} + isAnimationActive={ false } + /> + {/* <Area */} + {/* yAxisId="r" */} + {/* dataKey="cpu" */} + {/* type="monotone" */} + {/* stroke={CPU_COLOR} */} + {/* fill="none" */} + {/* // fill="url(#fpsGradient)" */} + {/* dot={false} */} + {/* activeDot={{ */} + {/* onClick: this.onDotClick, */} + {/* style: { cursor: "pointer" }, */} + {/* }} */} + {/* isAnimationActive={ false } */} + {/* /> */} + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={FPSTooltip} + filterNull={ false } + /> + </AreaChart> + </ResponsiveContainer> + } + { cpu && + <ResponsiveContainer height={ height }> + <AreaChart + onClick={ this.onChartClick } + data={this._data} + syncId="s" + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + > + <defs> + <Gradient id="cpuGradient" color={ CPU_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={false} + tickFormatter={()=> ""} + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="CPU" position="insideTopRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={ false } + tick={ false } + mirror + domain={[ 0, 120]} + orientation="right" + /> + <Area + dataKey="cpu" + type="monotone" + stroke={CPU_STROKE_COLOR} + // fill="none" + fill="url(#cpuGradient)" + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <Area + dataKey="hiddenScreenMarker" + type="stepBefore" + stroke="none" + fill={ HIDDEN_SCREEN_COLOR } + activeDot={false} + isAnimationActive={ false } + /> + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={CPUTooltip} + filterNull={ false } + /> + </AreaChart> + </ResponsiveContainer> + } + + { heap && + <ResponsiveContainer height={ height }> + <ComposedChart + onClick={ this.onChartClick } + data={this._data} + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + syncId="s" + > + <defs> + <Gradient id="usedHeapGradient" color={ USED_HEAP_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="1 1" stroke="#ddd" horizontal={ false } /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={false} + tickFormatter={()=> ""} // tick={false} + this._timeTicks to cartesian array + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="HEAP" position="insideTopRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={false} + tickFormatter={formatBytes} + mirror + // Hack to keep only end tick + minTickGap={Number.MAX_SAFE_INTEGER} + domain={[0, max => max*1.2]} + /> + <Line + type="monotone" + dataKey="totalHeap" + // fill="url(#totalHeapGradient)" + stroke={TOTAL_HEAP_STROKE_COLOR} + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <Area + dataKey="usedHeap" + type="monotone" + fill="url(#usedHeapGradient)" + stroke={USED_HEAP_STROKE_COLOR} + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={HeapTooltip} + filterNull={ false } + /> + </ComposedChart> + </ResponsiveContainer> + } + { nodes && + <ResponsiveContainer height={ height }> + <AreaChart + onClick={ this.onChartClick } + data={this._data} + syncId="s" + margin={{ + top: 0, right: 0, left: 0, bottom: 0, + }} + > + <defs> + <Gradient id="nodesGradient" color={ NODES_COUNT_COLOR } /> + </defs> + {/* <CartesianGrid strokeDasharray="1 1" stroke="#ddd" horizontal={ false } /> */} + <XAxis + dataKey="time" + type="number" + mirror + orientation="top" + tickLine={false} + tickFormatter={()=> ""} + domain={[0, 'dataMax']} + ticks={this._timeTicks} + > + <Label value="NODES" position="insideTopRight" className="fill-gray-medium" /> + </XAxis> + <YAxis + axisLine={ false } + tick={ false } + mirror + orientation="right" + domain={[0, max => max*1.2]} + /> + <Area + dataKey="nodesCount" + type="monotone" + stroke={NODES_COUNT_STROKE_COLOR} + // fill="none" + fill="url(#nodesGradient)" + dot={false} + activeDot={{ + onClick: this.onDotClick, + style: { cursor: "pointer" }, + }} + isAnimationActive={ false } + /> + <ReferenceLine x={performanceChartTime} stroke={CURSOR_COLOR} /> + <Tooltip + content={NodesCountTooltip} + filterNull={ false } + /> + </AreaChart> + </ResponsiveContainer> + } + </BottomBlock.Content> + </BottomBlock> + ); + } +} + +export const ConnectedPerformance = connectPlayer(state => ({ + performanceChartTime: state.performanceChartTime, + performanceChartData: state.performanceChartData, + connType: state.connType, + connBandwidth: state.connBandwidth, + avaliability: state.performanceAvaliability, +}))(Performance); diff --git a/frontend/app/components/Session_/Performance/index.js b/frontend/app/components/Session_/Performance/index.js new file mode 100644 index 000000000..e0e5ed895 --- /dev/null +++ b/frontend/app/components/Session_/Performance/index.js @@ -0,0 +1,2 @@ +export { default } from './Performance'; +export * from './Performance'; \ No newline at end of file diff --git a/frontend/app/components/Session_/Performance/performance.css b/frontend/app/components/Session_/Performance/performance.css new file mode 100644 index 000000000..4bd075eec --- /dev/null +++ b/frontend/app/components/Session_/Performance/performance.css @@ -0,0 +1,6 @@ +.tooltipWrapper { + background: white; + padding: 2px 5px; + border-radius: 3px; + border: 1px solid #ccc; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/ControlButton.js b/frontend/app/components/Session_/Player/Controls/ControlButton.js new file mode 100644 index 000000000..752c68631 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/ControlButton.js @@ -0,0 +1,23 @@ +import cn from 'classnames'; +import { Icon } from 'UI'; +import stl from './controlButton.css'; + +const ControlButton = ({ label, icon, disabled=false, onClick, count = 0, hasErrors=false, active=false }) => ( + <button + className={ cn(stl.controlButton, { [stl.disabled]: disabled, [stl.active]: active }) } + onClick={ onClick } + id={"control-button-" + label.toLowerCase()} + disabled={disabled} + > + <div className="relative"> + { count > 0 && <div className={ stl.countLabel }>{ count }</div>} + { hasErrors && <div className={ stl.errorSymbol } /> } + <Icon name={ icon } size="20" color="gray-dark"/> + </div> + <span className={ stl.label }>{ label }</span> + </button> +); + +ControlButton.displayName = 'ControlButton'; + +export default ControlButton; \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/Controls.js b/frontend/app/components/Session_/Player/Controls/Controls.js new file mode 100644 index 000000000..ed5c6f307 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/Controls.js @@ -0,0 +1,425 @@ +import cn from 'classnames'; +import { connect } from 'react-redux'; +import { + connectPlayer, + STORAGE_TYPES, + selectStorageType, + selectStorageListNow, +} from 'Player/store'; + +import { Popup, Icon } from 'UI'; +import { + fullscreenOn, + fullscreenOff, + toggleBottomBlock, + CONSOLE, + NETWORK, + STACKEVENTS, + STORAGE, + PROFILER, + PERFORMANCE, + GRAPHQL, + FETCH, + EXCEPTIONS, + LONGTASKS, +} from 'Duck/components/player'; +import { ReduxTime } from './Time'; +import Timeline from './Timeline'; +import ControlButton from './ControlButton'; + +import styles from './controls.css'; + + +function getStorageIconName(type) { + switch(type) { + case STORAGE_TYPES.REDUX: + return "vendors/redux"; + case STORAGE_TYPES.MOBX: + return "vendors/mobx" + case STORAGE_TYPES.VUEX: + return "vendors/vuex"; + case STORAGE_TYPES.NGRX: + return "vendors/ngrx"; + case STORAGE_TYPES.NONE: + return "store" + } +} + +function getStorageName(type) { + switch(type) { + case STORAGE_TYPES.REDUX: + return "Redux"; + case STORAGE_TYPES.MOBX: + return "MobX"; + case STORAGE_TYPES.VUEX: + return "Vuex"; + case STORAGE_TYPES.NGRX: + return "NgRx"; + case STORAGE_TYPES.NONE: + return "State"; + } +} + +@connectPlayer(state => ({ + time: state.time, + endTime: state.endTime, + live: state.live, + livePlay: state.livePlay, + playing: state.playing, + completed: state.completed, + skip: state.skip, + speed: state.speed, + disabled: state.cssLoading || state.messagesLoading, + fullscreenDisabled: state.messagesLoading, + logCount: state.logListNow.length, + logRedCount: state.logRedCountNow, + // resourceCount: state.resourceCountNow, + resourceRedCount: state.resourceRedCountNow, + fetchRedCount: state.fetchRedCountNow, + showStack: state.stackList.length > 0, + stackCount: state.stackListNow.length, + stackRedCount: state.stackRedCountNow, + profilesCount: state.profilesListNow.length, + storageCount: selectStorageListNow(state).length, + storageType: selectStorageType(state), + showStorage: selectStorageType(state) !== STORAGE_TYPES.NONE, + showProfiler: state.profilesList.length > 0, + showGraphql: state.graphqlList.length > 0, + showFetch: state.fetchCount > 0, + fetchCount: state.fetchCountNow, + graphqlCount: state.graphqlListNow.length, + exceptionsCount: state.exceptionsListNow.length, + showExceptions: state.exceptionsList.length > 0, + showLongtasks: state.longtasksList.length > 0, +})) +@connect((state, props) => ({ + showDevTools: state.getIn([ 'user', 'account', 'appearance', 'sessionsDevtools' ]), + fullscreen: state.getIn([ 'components', 'player', 'fullscreen' ]), + bottomBlock: state.getIn([ 'components', 'player', 'bottomBlock' ]), + showStorage: props.showStorage || !state.getIn(['components', 'player', 'hiddenHints', 'storage']), + showStack: props.showStack || !state.getIn(['components', 'player', 'hiddenHints', 'stack']), +}), { + fullscreenOn, + fullscreenOff, + toggleBottomBlock, +}) +export default class Controls extends React.Component { + + componentDidMount() { + document.addEventListener('keydown', this.onKeyDown); + } + componentWillUnmount() { + document.removeEventListener('keydown', this.onKeyDown); + //this.props.toggleInspectorMode(false); + } + + shouldComponentUpdate(nextProps) { + if (nextProps.showDevTools !== this.props.showDevTools || + nextProps.fullscreen !== this.props.fullscreen || + nextProps.bottomBlock !== this.props.bottomBlock || + nextProps.endTime !== this.props.endTime || + nextProps.live !== this.props.live || + nextProps.livePlay !== this.props.livePlay || + nextProps.playing !== this.props.playing || + nextProps.completed !== this.props.completed || + nextProps.skip !== this.props.skip || + nextProps.speed !== this.props.speed || + nextProps.disabled !== this.props.disabled || + nextProps.fullscreenDisabled !== this.props.fullscreenDisabled || + //nextProps.inspectorMode !== this.props.inspectorMode || + nextProps.logCount !== this.props.logCount || + nextProps.logRedCount !== this.props.logRedCount || + nextProps.resourceRedCount !== this.props.resourceRedCount || + nextProps.fetchRedCount !== this.props.fetchRedCount || + nextProps.showStack !== this.props.showStack || + nextProps.stackCount !== this.props.stackCount || + nextProps.stackRedCount !== this.props.stackRedCount || + nextProps.profilesCount !== this.props.profilesCount || + nextProps.storageCount !== this.props.storageCount || + nextProps.storageType !== this.props.storageType || + nextProps.showStorage !== this.props.showStorage || + nextProps.showProfiler !== this.props.showProfiler || + nextProps.showGraphql !== this.props.showGraphql || + nextProps.showFetch !== this.props.showFetch || + nextProps.fetchCount !== this.props.fetchCount || + nextProps.graphqlCount !== this.props.graphqlCount || + nextProps.showExceptions !== this.props.showExceptions || + nextProps.exceptionsCount !== this.props.exceptionsCount || + nextProps.showLongtasks !== this.props.showLongtasks + ) return true; + return false; + } + + onKeyDown = (e) => { + if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) { + return; + } + //if (this.props.inspectorMode) return; + if (e.key === ' ') { + document.activeElement.blur(); + this.props.togglePlay(); + } + if (e.key === 'Esc' || e.key === 'Escape') { + this.props.fullscreenOff(); + } + if (e.key === "ArrowRight") { + this.forthTenSeconds(); + } + if (e.key === "ArrowLeft") { + this.backTenSeconds(); + } + if (e.key === "ArrowDown") { + this.props.speedDown(); + } + if (e.key === "ArrowUp") { + this.props.speedUp(); + } + } + + // toggleInspectorMode = () => { + // this.props.pause(); + // this.props.toggleInspectorMode(); + // } + + forthTenSeconds = () => { + const { time, endTime, jump } = this.props; + jump(Math.min(endTime, time + 1e4)) + } + + backTenSeconds = () => { //shouldComponentUpdate + const { time, jump } = this.props; + jump(Math.max(0, time - 1e4)); + } + + goLive =() => this.props.jump(this.props.endTime) + + renderPlayBtn = () => { + const { completed, playing, disabled } = this.props; + let label; + let icon; + if (completed) { + label = 'Replay'; + icon = 'redo'; + } else if (playing) { + label = 'Pause'; + icon = 'pause'; + } else { + label = 'Play'; + icon = 'play'; + } + return ( + <ControlButton + disabled={ disabled } + onClick={ this.props.togglePlay } + icon={ icon } + label={ label } + /> + ); + } + + render() { + const { + showDevTools, + bottomBlock, + toggleBottomBlock, + live, + livePlay, + skip, + speed, + disabled, + fullscreenDisabled, + logCount, + logRedCount, + resourceRedCount, + fetchRedCount, + showStack, + stackCount, + stackRedCount, + profilesCount, + storageCount, + showStorage, + storageType, + showProfiler, + showGraphql, + showFetch, + fetchCount, + graphqlCount, + showLongtasks, + exceptionsCount, + showExceptions, + fullscreen, + } = this.props; + + return ( + <div className={ styles.controls }> + <Timeline jump={ this.props.jump } /> + { !fullscreen && + <div className={ styles.buttons } data-is-live={ live }> + { !live ? + <div className={ styles.buttonsLeft }> + { this.renderPlayBtn() } + <ControlButton + onClick={ this.backTenSeconds } + disabled={ disabled } + label="Back" + icon="replay-10" + /> + </div> + : + <div className={ styles.buttonsLeft }> + <button onClick={ this.goLive } className={ styles.liveTag } data-is-live={ livePlay }> + <Icon name="circle" size="8" marginRight="5" color="white" /> + <div>{'Live'}</div> + </button> + {'Elapsed'} + <ReduxTime name="time" /> + </div> + } + <div className={ styles.butonsRight }> + {!live && + <React.Fragment> + <button + className={ styles.speedButton } + onClick={ this.props.toggleSpeed } + data-disabled={ disabled } + > + <div>{ speed + 'x' }</div> + </button> + <div className={ styles.divider } /> + <button + className={ cn(styles.skipIntervalButton, { [styles.withCheckIcon]: skip }) } + onClick={ this.props.toggleSkip } + data-disabled={ disabled } + > + <span className={ styles.checkIcon } /> + { 'Skip Inactivity' } + </button> + </React.Fragment> + } + <div className={ styles.divider } /> + { !live && showDevTools && + <ControlButton + disabled={ disabled } + onClick={ () => toggleBottomBlock(NETWORK) } + active={ bottomBlock === NETWORK } + label="Network" + // count={ redResourceCount } + hasErrors={ resourceRedCount > 0 } + icon="wifi" + /> + } + { showFetch && + <ControlButton + disabled={disabled} + onClick={ ()=> toggleBottomBlock(FETCH) } + active={ bottomBlock === FETCH } + hasErrors={ fetchRedCount > 0 } + count={ fetchCount } + label="Fetch" + icon="fetch" + /> + } + { showGraphql && + <ControlButton + disabled={disabled} + onClick={ ()=> toggleBottomBlock(GRAPHQL) } + active={ bottomBlock === GRAPHQL } + count={ graphqlCount } + label="GraphQL" + icon="vendors/graphql" + /> + } + { showStorage && showDevTools && + <ControlButton + disabled={ disabled } + onClick={ () => toggleBottomBlock(STORAGE) } + active={ bottomBlock === STORAGE } + count={ storageCount } + label={ getStorageName(storageType) } + icon={ getStorageIconName(storageType) } + /> + } + { showDevTools && + <ControlButton + disabled={ disabled } + onClick={ () => toggleBottomBlock(CONSOLE) } + active={ bottomBlock === CONSOLE } + label="Console" + icon="console" + count={ logCount } + hasErrors={ logRedCount > 0 } + /> + } + { showExceptions && showDevTools && + <ControlButton + disabled={ disabled } + onClick={ () => toggleBottomBlock(EXCEPTIONS) } + active={ bottomBlock === EXCEPTIONS } + label="Exceptions" + icon="console/error" + count={ exceptionsCount } + hasErrors={ exceptionsCount > 0 } + /> + } + { !live && showDevTools && showStack && + <ControlButton + disabled={ disabled } + onClick={ () => toggleBottomBlock(STACKEVENTS) } + active={ bottomBlock === STACKEVENTS } + label="Events" + icon="puzzle-piece" + count={ stackCount } + hasErrors={ stackRedCount > 0 } + /> + } + { showProfiler && showDevTools && + <ControlButton + disabled={ disabled } + onClick={ () => toggleBottomBlock(PROFILER) } + active={ bottomBlock === PROFILER } + count={ profilesCount } + label="Profiler" + icon="code" + /> + } + <ControlButton + disabled={ disabled } + onClick={ () => toggleBottomBlock(PERFORMANCE) } + active={ bottomBlock === PERFORMANCE } + label="Performance" + icon="tachometer-slow" + /> + { showLongtasks && + <ControlButton + disabled={ disabled } + onClick={ () => toggleBottomBlock(LONGTASKS) } + active={ bottomBlock === LONGTASKS } + label="Long Tasks" + icon="business-time" + /> + } + <div className={ styles.divider } /> + { !live && + <React.Fragment> + <ControlButton + disabled={ fullscreenDisabled } + onClick={ this.props.fullscreenOn } + label="Full Screen" + icon="fullscreen" + /> + </React.Fragment> + } + {/* + <ControlButton + disabled={ disabled && !inspectorMode } + onClick={ this.toggleInspectorMode } + icon={ inspectorMode ? 'close' : 'inspect' } + label="Inspect" + /> */} + </div> + </div> + } + </div> + ); + } +} diff --git a/frontend/app/components/Session_/Player/Controls/Time.js b/frontend/app/components/Session_/Player/Controls/Time.js new file mode 100644 index 000000000..45233af91 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/Time.js @@ -0,0 +1,21 @@ +import { Duration } from 'luxon'; +import { connectPlayer } from 'Player'; +import styles from './time.css'; + +const Time = ({ time }) => ( + <div className={ styles.time }> + { Duration.fromMillis(time).toFormat('m:ss') } + </div> +) + +Time.displayName = "Time"; + + +const ReduxTime = connectPlayer((state, { name }) => ({ + time: state[ name ], +}))(Time); + +ReduxTime.displayName = "ReduxTime"; + +export default Time; +export { ReduxTime }; \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/TimeTracker.js b/frontend/app/components/Session_/Player/Controls/TimeTracker.js new file mode 100644 index 000000000..be91f69fe --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/TimeTracker.js @@ -0,0 +1,22 @@ +import { connectPlayer } from 'Player'; +import styles from './timeTracker.css'; + + +const TimeTracker = ({ time, scale }) => ( + <React.Fragment> + <div + className={ styles.positionTracker } + style={ { left: `${ time * scale }%` } } + /> + <span + className={ styles.playedTimeline } + style={ { width: `${ time * scale }%` } } + /> + </React.Fragment> +); + +TimeTracker.displayName = 'TimeTracker'; + +export default connectPlayer(state => ({ + time: state.time, +}))(TimeTracker); \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/Timeline.js b/frontend/app/components/Session_/Player/Controls/Timeline.js new file mode 100644 index 000000000..aeab1af64 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/Timeline.js @@ -0,0 +1,457 @@ +import { DateTime } from 'luxon'; +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { connectPlayer } from 'Player'; +import { Popup, TimelinePointer } from 'UI'; +import TimeTracker from './TimeTracker'; +import { ReduxTime } from './Time'; +import stl from './timeline.css'; +import { TYPES } from 'Types/session/event'; + +const getPointerIcon = (type) => { + // exception, + switch(type) { + case 'fetch': + return 'funnel/file-earmark-minus-fill'; + case 'exception': + return 'funnel/exclamation-circle'; + case 'log': + return 'funnel/exclamation-circle'; + case 'stack': + return 'funnel/file-exclamation'; + case 'resource': + return 'funnel/file-medical-alt'; + + case 'dead_click': + return 'funnel/dizzy'; + case 'excessive_scrolling': + return 'funnel/mouse'; + case 'bad_request': + return 'funnel/file-medical-alt'; + case 'missing_resource': + return 'funnel/file-earmark-minus-fill'; + case 'memory': + return 'funnel/sd-card'; + case 'cpu': + return 'funnel/microchip'; + case 'slow_resource': + return 'funnel/hourglass-top'; + case 'slow_page_load': + return 'funnel/hourglass-top'; + case 'crash': + return 'funnel/file-exclamation'; + case 'js_exception': + return 'funnel/exclamation-circle'; + } + + return 'info'; +} + +@connectPlayer(state => ({ + skipIntervals: state.skipIntervals, + events: state.eventList, + skip: state.skip, + disabled: state.cssLoading || state.messagesLoading, + endTime: state.endTime, + live: state.live, + logList: state.logList, + exceptionsList: state.exceptionsList, + resourceList: state.resourceList, + stackList: state.stackList, + fetchList: state.fetchList, +})) +@connect(state => ({ + showDevTools: state.getIn([ 'user', 'account', 'appearance', 'sessionsDevtools' ]), + clickRageTime: state.getIn([ 'sessions', 'current', 'clickRage' ]) && + state.getIn([ 'sessions', 'current', 'clickRageTime' ]), + returningLocationTime: state.getIn([ 'sessions', 'current', 'returningLocation' ]) && + state.getIn([ 'sessions', 'current', 'returningLocationTime' ]), +})) +export default class Timeline extends React.PureComponent { + seekProgress = (e) => { + const { endTime } = this.props; + const p = e.nativeEvent.offsetX / e.target.offsetWidth; + const time = Math.max(Math.round(p * endTime), 0); + this.props.jump(time); + } + + createEventClickHandler = time => (e) => { + e.stopPropagation(); + this.props.jump(time) + } + + render() { + const { + events, + skip, + skipIntervals, + disabled, + endTime, + live, + logList, + exceptionsList, + resourceList, + showDevTools, + clickRageTime, + stackList, + fetchList, + } = this.props; + + const scale = 100 / endTime; + return ( + <div + className={ cn("flex items-center") } + > + { !live && <ReduxTime name="time" /> } + <div className={ stl.progress } onClick={ disabled ? null : this.seekProgress }> + <TimeTracker scale={ scale } /> + { skip && skipIntervals.map(interval => + (<div + key={ interval.start } + className={ stl.skipInterval } + style={ { + left: `${ interval.start * scale }%`, + width: `${ (interval.end - interval.start) * scale }%`, + } } + />)) + } + <div className={ stl.timeline }/> + { events.map(e => ( + <div + key={ e.key } + className={ stl.event } + style={ { left: `${ e.time * scale }%` } } + /> + )) + } + { events.filter(e => e.type === TYPES.CLICKRAGE).map(e => ( + <div + style={ { + left: `${ e.time * scale }%`, + top: '-30px' + //width: `${ 2000 * scale }%` + } } + className={ stl.clickRage } + onClick={ this.createEventClickHandler(e.time) } + > + <TimelinePointer + icon={getPointerIcon('click_rage')} + content={ + <div className={ stl.popup }> + <b>{ "Click Rage" }</b> + </div> + } + /> + </div> + // <Popup + // pinned + // offset="-19" + // trigger={ + // <div + // style={ { + // left: `${ e.time * scale }%`, + // //width: `${ 2000 * scale }%` + // } } + // className={ stl.clickRage } + // /> + // } + // content={ + // <div className={ stl.popup }> + // <b>{ "Click Rage" }</b> + // </div> + // } + // /> + ))} + { typeof clickRageTime === 'number' && + <div + style={ { + left: `${ clickRageTime * scale }%`, + top: '-30px' + //width: `${ 2000 * scale }%` + } } + className={ stl.clickRage } + > + <TimelinePointer + icon={getPointerIcon('click_rage')} + content={ + <div className={ stl.popup }> + <b>{ "Click Rage" }</b> + </div> + } + /> + </div> + // <Popup + // pinned + // offset="-19" + // trigger={ + // <div + // style={ { + // left: `${ clickRageTime * scale }%`, + // //width: `${ 2000 * scale }%` + // } } + // className={ stl.clickRage } + // /> + // } + // content={ + // <div className={ stl.popup }> + // <b>{ "Click Rage" }</b> + // </div> + // } + // /> + } + { /* typeof returningLocationTime === 'number' && + <Popup + pinned + offset="-19" + trigger={ + <div + style={ { + left: `${ returningLocationTime * scale }%`, + //width: `${ 2000 * scale }%` + } } + className={ stl.returningLocation } + onClick={ this.createEventClickHandler(returningLocationTime) } + /> + } + content={ + <div className={ stl.popup }> + <b>{ "Returning Location" }</b> + </div> + } + /> + */ } + { showDevTools && exceptionsList + .map(e => ( + <div + key={ e.key } + className={ cn(stl.markup, stl.error) } + style={ { left: `${ e.time * scale }%`, top: '-30px' } } + onClick={ this.createEventClickHandler(e.time) } + > + <TimelinePointer + icon={getPointerIcon('exception')} + content={ + <div className={ stl.popup } > + <b>{ "Exception:" }</b> + <br/> + <span>{ e.message }</span> + </div> + } + /> + </div> + // <Popup + // key={ e.key } + // offset="-19" + // pinned + // className="error" + // trigger={ + // <div + // key={ e.key } + // className={ cn(stl.markup, stl.error) } + // style={ { left: `${ e.time * scale }%` } } + // onClick={ this.createEventClickHandler(e.time) } + // /> + // } + // content={ + // <div className={ stl.popup } > + // <b>{ "Exception:" }</b> + // <br/> + // <span>{ e.message }</span> + // </div> + // } + // /> + )) + } + { showDevTools && logList + .map(l => l.isRed() && ( + <div + key={ l.key } + className={ cn(stl.markup, { + [ stl.error ]: l.isRed(), + //[ stl.warning ]: l.isYellow(), + //[ stl.info ]: !l.isYellow() && !l.isRed(), + }) } + style={ { left: `${ l.time * scale }%`, top: '-30px' } } + onClick={ this.createEventClickHandler(l.time) } + > + <TimelinePointer + icon={getPointerIcon('log')} + content={ + <div className={ stl.popup } > + <b>{ "Console:" }</b> + <br/> + <span>{ l.value }</span> + </div> + } + /> + </div> + // <Popup + // //on="click" + // key={ l.key } + // offset="-19" + // pinned + // className={ cn({ + // "info": !l.isYellow() && !l.isRed(), + // "warn": l.isYellow(), + // "error": l.isRed(), + // })} + // trigger={ + // <div + // key={ l.key } + // className={ cn(stl.markup, { + // [ stl.error ]: l.isRed(), + // //[ stl.warning ]: l.isYellow(), + // //[ stl.info ]: !l.isYellow() && !l.isRed(), + // }) } + // style={ { left: `${ l.time * scale }%` } } + // onClick={ this.createEventClickHandler(l.time) } + // /> + // } + // content={ + // <div className={ stl.popup } > + // <b>{ "Console:" }</b> + // <br/> + // <span>{ l.value }</span> + // </div> + // } + // /> + )) + } + { showDevTools && resourceList + .filter(r => r.isRed() || r.isYellow()) + .map(r => ( + <div + key={ r.key } + className={ cn(stl.markup, { + [ stl.error ]: r.isRed(), + [ stl.warning ]: r.isYellow(), + }) } + style={ { left: `${ r.time * scale }%`, top: '-30px' } } + onClick={ this.createEventClickHandler(r.time) } + > + <TimelinePointer + icon={getPointerIcon('resource')} + content={ + <div className={ stl.popup }> + <b>{ r.success ? "Slow resource: " : "Missing resource:" }</b> + <br/> + { r.name } + </div> + } + /> + </div> + // <Popup + // key={ r.key } + // offset="-19" + // pinned + // trigger={ + // <div + // key={ r.key } + // className={ cn(stl.markup, { + // [ stl.error ]: r.isRed(), + // [ stl.warning ]: r.isYellow(), + // }) } + // style={ { left: `${ r.time * scale }%` } } + // onClick={ this.createEventClickHandler(r.time) } + // > + + // </div> + // } + // content={ + // <div className={ stl.popup }> + // <b>{ r.success ? "Slow resource: " : "Missing resource:" }</b> + // <br/> + // { r.name } + // </div> + // } + // /> + )) + } + { showDevTools && fetchList + .filter(e => e.isRed()) + .map(e => ( + <div + key={ e.key } + className={ cn(stl.markup, stl.error) } + style={ { left: `${ e.time * scale }%`, top: '-30px' } } + onClick={ this.createEventClickHandler(e.time) } + > + <TimelinePointer + icon={getPointerIcon('fetch')} + content={ + <div className={ stl.popup }> + <b>{ "Failed Fetch:" }</b> + <br/> + { e.name } + </div> + } + /> + </div> + // <Popup + // offset="-19" + // pinned + // trigger={ + // <div + // key={ e.key } + // className={ cn(stl.markup, stl.error) } + // style={ { left: `${ e.time * scale }%` } } + // onClick={ this.createEventClickHandler(e.time) } + // /> + // } + // content={ + // <div className={ stl.popup }> + // <b>{ "Failed Fetch:" }</b> + // <br/> + // { e.name } + // </div> + // } + // /> + )) + } + { showDevTools && stackList + .filter(e => e.isRed()) + .map(e => ( + <div + key={ e.key } + className={ cn(stl.markup, stl.error) } + style={ { left: `${ e.time * scale }%`, top: '-30px' } } + onClick={ this.createEventClickHandler(e.time) } + > + <TimelinePointer + icon={getPointerIcon('stack')} + content={ + <div className={ stl.popup }> + <b> { "Stack Event:" }</b> + <br/> + { e.name } + </div> + } + /> + </div> + // <Popup + // offset="-19" + // pinned + // trigger={ + // <div + // key={ e.key } + // className={ cn(stl.markup, stl.error) } + // style={ { left: `${ e.time * scale }%` } } + // onClick={ this.createEventClickHandler(e.time) } + // /> + // } + // content={ + // <div className={ stl.popup }> + // <b> { "Stack Event:" }</b> + // <br/> + // { e.name } + // </div> + // } + // /> + )) + } + </div> + { !live && <ReduxTime name="endTime" /> } + </div> + ); + } +} diff --git a/frontend/app/components/Session_/Player/Controls/controlButton.css b/frontend/app/components/Session_/Player/Controls/controlButton.css new file mode 100644 index 000000000..90d85a359 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/controlButton.css @@ -0,0 +1,55 @@ + +.controlButton { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 5px 10px; + cursor: pointer; + min-width: 60px; + position: relative; + border-radius: 3px; + &.active, &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } + + & .errorSymbol { + width: 6px; + height: 6px; + border-radius: 3px; + background-color: red; + top: 12px; + left: 23px; + position: absolute; + } + + & .countLabel { + position: absolute; + top: -6px; + left: 12px; + background-color: $gray-dark; + color: white; + font-size: 9px; + font-weight: 300; + min-width: 20px; + height: 16px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + padding: 3px; + } + + & .label { + /* padding-top: 5px; */ + font-size: 10px; + color: $gray-darkest; + height: 16px; + } + + &.disabled { + pointer-events: none; + opacity: 0.5; + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/controls.css b/frontend/app/components/Session_/Player/Controls/controls.css new file mode 100644 index 000000000..79baf1d09 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/controls.css @@ -0,0 +1,118 @@ +@import "icons.css"; + +@keyframes fade { + 0% { opacity: 1} + 50% { opacity: 0} + 100% { opacity: 1} +} + +.controls { + /* margin-top: 10px; */ + border-top: solid thin $gray-light; + padding-top: 36px; + padding-bottom: 10px; +} + +.buttons { + display: flex; + justify-content: space-between; + margin-top: 7px; + align-items: center; + padding: 0 30px; + &[data-is-live=true] { + padding: 0; + } +} + +.buttonsLeft { + margin-right: auto; + display: flex; + align-items: center; +} + +.butonsRight { + display: flex; + align-items: center; +} + +.speedButton { + cursor: pointer; + color: $gray-darkest; + font-size: 14px; + padding: 0 10px; + height: 30px; + border-radius: 3px; + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } +} + + +.skipIntervalButton { + font-weight: normal !important; + display: flex; + align-items: center; + cursor: pointer; + font-size: 12px; + color: $gray-darkest; + /* margin-right: 5px; */ + padding: 0 10px; + height: 30px; + border-radius: 3px; + /* margin: 0 5px; */ + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } +} + +.divider { + height: 30px; + width: 1px; + margin: 0 5px; + background-color: $gray-light-shade; +} + +.withCheckIcon { + color: $gray-darkest; + & .checkIcon { + /* opacity: 1 !important; */ + display: block; + } +} + +.checkIcon { + @mixin icon check, $gray-dark, 12px; + margin-right: 8px; + display: none; +} + +.liveTag { + cursor: pointer; + user-select: none; + height: 26px; + width: 56px; + border-radius: 3px; + background-color: $gray-light; + display: flex; + align-items: center; + justify-content: center; + color: $gray-dark; + text-transform: uppercase; + font-size: 10px; + letter-spacing: 1px; + margin-right: 10px; + & svg { + fill: $gray-dark; + } + &[data-is-live=true] { + background-color: #42AE5E; + color: white; + & svg { + fill: white; + animation: fade 1s infinite; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/index.js b/frontend/app/components/Session_/Player/Controls/index.js new file mode 100644 index 000000000..a8c3b0a3b --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/index.js @@ -0,0 +1 @@ +export { default } from './Controls'; \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/time.css b/frontend/app/components/Session_/Player/Controls/time.css new file mode 100644 index 000000000..59ad17330 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/time.css @@ -0,0 +1,5 @@ + +.time { + padding: 0 12px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/timeTracker.css b/frontend/app/components/Session_/Player/Controls/timeTracker.css new file mode 100644 index 000000000..acf755071 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/timeTracker.css @@ -0,0 +1,24 @@ +@import 'zindex.css'; + +.positionTracker { + width: 15px; + height: 15px; + border: solid 1px $teal; + margin-left: -7px; + border-radius: 50%; + background-color: $active-blue; + position: absolute; + left: 0; + z-index: $positionTracker; + pointer-events: none; /* temporary. DnD should be */ +} + +.playedTimeline { + display: block; + height: 100%; + border-radius: 4px; + background-color: $teal; + pointer-events: none; + height: 2px; + z-index: 1; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Controls/timeline.css b/frontend/app/components/Session_/Player/Controls/timeline.css new file mode 100644 index 000000000..89187e3b4 --- /dev/null +++ b/frontend/app/components/Session_/Player/Controls/timeline.css @@ -0,0 +1,150 @@ + + +.progress { + height: 10px; + border-radius: 1px; + background: transparent; + cursor: pointer; + width: 100%; + position: relative; + display: flex; + align-items: center; +} + + +.skipInterval { + position: absolute; + top: 0; + bottom: 0; + border-radius: 4px; + background-color: rgba(0, 0, 0, 0.15); + pointer-events: none; +} + + +.event { + position: absolute; + width: 8px; + height: 8px; + border: solid 1px white; + margin-left: -4px; + border-radius: 50%; + background: rgba(136, 136, 136, 0.8); + pointer-events: none; + /* top: 0; */ + /* bottom: 0; */ + /* &:hover { + width: 10px; + height: 10px; + margin-left: -6px; + z-index: 1; + };*/ +} + +/* .event.click, .event.input { + background: $green; +} +.event.location { + background: $blue; +} */ + +.markup { + position: absolute; + width: 2px; + height: 8px; + border-radius: 2px; + margin-left: -15px; + &:hover { + z-index: 9999; + } +} + +/* .markup.log { + background: $blue; +} + +.markup.error { + background: $red; +} + +.markup.warning { + background: $orange; +} */ + +.markup.info { + background: $blue2; +} + +.popup { + max-width: 300px !important; + /* max-height: 300px !important; */ + overflow: hidden; + text-overflow: ellipsis; + & span { + display: block; + max-height: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.timeline { + border-radius: 5px; + overflow: hidden; + position: absolute; + left: 0; + right: 0; + height: 2px; + background-color: $gray-light; + display: flex; + align-items: center; +} + +.clickRage { + position: absolute; + width: 2px; + height: 8px; + border-radius: 2px; + margin-left: -1px; + /* background: $red; */ +} + +.returningLocation { + position: absolute; + height: 20%; + border-radius: 50%; + /* background: $red; */ + width: 12px; +} + +.feedbackIcon { + position: absolute; + margin-top: -20px; + margin-left: -9px; + background-color: $gray-lightest; + padding: 2px; + border-radius: 3px; + box-shadow: 0px 0px 0px 1px rgba(0,0,0,0.1); + + & .tooltipArrow { + width: 50px; + height: 25px; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + overflow: hidden; + &::after { + content: ""; + position: absolute; + width: 6px; + height: 6px; + background: $gray-lightest; + transform: translateX(-50%) translateY(50%) rotate(45deg); + bottom: 100%; + left: 50%; + box-shadow: 0px 0px 0px 1px rgba(0,0,0,0.1); + } + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Player/Player.js b/frontend/app/components/Session_/Player/Player.js new file mode 100644 index 000000000..671e3d08f --- /dev/null +++ b/frontend/app/components/Session_/Player/Player.js @@ -0,0 +1,154 @@ +import { connect } from 'react-redux'; +import { findDOMNode } from 'react-dom'; +import cn from 'classnames'; +import { Loader, IconButton, EscapeButton } from 'UI'; +import { hide as hideTargetDefiner, toggleInspectorMode } from 'Duck/components/targetDefiner'; +import { fullscreenOff } from 'Duck/components/player'; +import withOverlay from 'Components/hocs/withOverlay'; +import { attach as attachPlayer, Controls as PlayerControls, connectPlayer } from 'Player'; +import Controls from './Controls'; +import stl from './player.css'; + + +const ScreenWrapper = withOverlay()(React.memo(() => <div className={ stl.screenWrapper } />)); + +@connectPlayer(state => ({ + playing: state.playing, + loading: state.messagesLoading, + disconnected: state.disconnected, +})) +@connect(state => ({ + //session: state.getIn([ 'sessions', 'current' ]), + targetSelector: state.getIn([ 'components', 'targetDefiner', 'target', 'path' ]), + targetDefinerDisplayed: state.getIn([ 'components', 'targetDefiner', 'isDisplayed' ]), + inspectorMode: state.getIn([ 'components', 'targetDefiner', 'inspectorMode' ]), + fullscreen: state.getIn([ 'components', 'player', 'fullscreen' ]), +}), { + hideTargetDefiner, + toggleInspectorMode: () => toggleInspectorMode(false), + fullscreenOff, +}) +@withOverlay('targetDefinerDisplayed', 'hideTargetDefiner') +export default class Player extends React.PureComponent { + state = { + showPlayOverlayIcon: false, + + startedToPlayAt: Date.now(), + }; + screenWrapper = React.createRef(); + + componentDidMount() { + const parentElement = findDOMNode(this.screenWrapper.current); //TODO: good architecture + attachPlayer(parentElement); + } + + componentDidUpdate(prevProps) { + if (prevProps.targetSelector !== this.props.targetSelector) { + PlayerControls.mark(this.props.targetSelector); + } + if (prevProps.playing !== this.props.playing) { + if (this.props.playing) { + this.setState({ startedToPlayAt: Date.now() }); + } else { + this.updateWatchingTime(); + } + } + } + + componentWillUnmount() { + if (this.props.playing) { + this.updateWatchingTime(); + } + } + + updateWatchingTime() { + const diff = Date.now() - this.state.startedToPlayAt; + } + + + // onTargetClick = (targetPath) => { + // const { targetCustomList, location } = this.props; + // const targetCustomFromList = targetCustomList !== this.props.targetSelector + // .find(({ path }) => path === targetPath); + // const target = targetCustomFromList + // ? targetCustomFromList.set('location', location) + // : { path: targetPath, isCustom: true, location }; + // this.props.showTargetDefiner(target); + // } + + togglePlay = () => { + this.setState({ showPlayOverlayIcon: true }); + PlayerControls.togglePlay(); + + setTimeout( + () => this.setState({ showPlayOverlayIcon: false }), + 800, + ); + } + + render() { + const { + showPlayOverlayIcon, + } = this.state; + const { + className, + playing, + inspectorMode, + targetDefinerDisplayed, + bottomBlockIsActive, + loading, + disconnected, + fullscreen, + fullscreenOff, + } = this.props; + + return ( + <div + className={ cn(className, stl.playerBody, "flex flex-col relative") } + data-bottom-block={ bottomBlockIsActive } + > + { fullscreen && + <EscapeButton onClose={ fullscreenOff } /> + // <IconButton + // size="18" + // className="ml-auto mb-5" + // style={{ marginTop: '-5px' }} + // onClick={ fullscreenOff } + // size="small" + // icon="close" + // label="Esc" + // /> + } + <div className={ cn(stl.playerView, targetDefinerDisplayed ? stl.inspectorMode : '') }> + { !inspectorMode && // TODO: beauty + <React.Fragment> + <div className={ stl.overlay }> + <Loader loading={ loading } /> + { disconnected && <div className={ stl.disconnected }>{ "Disconnected" }</div> } + </div> + <div + className={ stl.overlay } + onClick={ this.togglePlay } + > + <div + className={ cn(stl.iconWrapper, { + [ stl.zoomIcon ]: showPlayOverlayIcon + }) } + > + <div className={ playing ? stl.playIcon : stl.pauseIcon } /> + </div> + </div> + </React.Fragment> + } + <ScreenWrapper + ref={ this.screenWrapper } + overlayed={ targetDefinerDisplayed } + /> + </div> + <Controls + { ...PlayerControls } + /> + </div> + ); + } +} diff --git a/frontend/app/components/Session_/Player/index.js b/frontend/app/components/Session_/Player/index.js new file mode 100644 index 000000000..2b570d433 --- /dev/null +++ b/frontend/app/components/Session_/Player/index.js @@ -0,0 +1 @@ +export { default } from './Player'; diff --git a/frontend/app/components/Session_/Player/player.css b/frontend/app/components/Session_/Player/player.css new file mode 100644 index 000000000..ebf3d88c9 --- /dev/null +++ b/frontend/app/components/Session_/Player/player.css @@ -0,0 +1,80 @@ +@import 'icons.css'; + +.playerBody { + background: $white; + /* border-radius: 3px; */ + /* padding: 10px 10px 5px 10px; */ + /* box-shadow: 0px 2px 10px 0 $gray-light; */ + height: 100%; + /* border: solid thin $gray-light; */ + border-right: solid thin $gray-light; +} + +.screenWrapper { + width: 100%; + position: relative; + height: 100%; + /* border: solid thin $gray-light; */ + /* border-radius: 3px; */ + overflow: hidden; + background: $gray-lightest; +} + +.disconnected { + font-size: 40px; + font-weight: 200; + color: $gray-medium; +} +.overlay { + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + + +/* &[data-protect] { + pointer-events: none; + background: $white; + opacity: 0.3; +} + */ + & .iconWrapper { + background-color: rgba(0, 0, 0, 0.1); + width: 50px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + opacity: 0; + transition: all .2s; /* Animation */ + } + + & .zoomIcon { + opacity: 1; + transform: scale(1.8); + transition: all .8s; + } + + & .playIcon { + @mixin icon play, $gray-medium, 30px; + } + + & .pauseIcon { + @mixin icon pause, $gray-medium, 30px; + } +} + +.playerView { + position: relative; + flex: 1; +} + +.inspectorMode { + z-index: 99991 !important; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/PlayerBlock.js b/frontend/app/components/Session_/PlayerBlock.js new file mode 100644 index 000000000..0588763d5 --- /dev/null +++ b/frontend/app/components/Session_/PlayerBlock.js @@ -0,0 +1,91 @@ +import cn from "classnames"; +import { connect } from 'react-redux'; +import { scale as scalePlayerScreen } from 'Player'; +import { + NONE, + CONSOLE, + NETWORK, + STACKEVENTS, + STORAGE, + PROFILER, + PERFORMANCE, + GRAPHQL, + FETCH, + EXCEPTIONS, + LONGTASKS, +} from 'Duck/components/player'; +import Player from './Player'; +import Network from './Network'; +import Console from './Console/Console'; +import StackEvents from './StackEvents/StackEvents'; +import Storage from './Storage'; +import Profiler from './Profiler'; +import { ConnectedPerformance } from './Performance'; +import PlayerBlockHeader from './PlayerBlockHeader'; +import GraphQL from './GraphQL'; +import Fetch from './Fetch'; +import Exceptions from './Exceptions/Exceptions'; +import LongTasks from './LongTasks'; +import styles from './playerBlock.css'; + + +@connect(state => ({ + fullscreen: state.getIn([ 'components', 'player', 'fullscreen' ]), + bottomBlock: state.getIn([ 'components', 'player', 'bottomBlock' ]), +})) +export default class PlayerBlock extends React.PureComponent { + componentDidUpdate(prevProps) { + if ([ prevProps.bottomBlock, this.props.bottomBlock ].includes(NONE) || + prevProps.fullscreen !== this.props.fullscreen) { + scalePlayerScreen(); + } + } + + render() { + const { fullscreen, bottomBlock } = this.props; + + return ( + <div className={ cn(styles.playerBlock, "flex flex-col") }> + {/* { !fullscreen && <PlayerBlockHeader /> } */} + <Player + className="flex-1" + bottomBlockIsActive={ !fullscreen && bottomBlock !== NONE } + /> + { !fullscreen && !!bottomBlock && + <div className=""> + { bottomBlock === CONSOLE && + <Console /> + } + { bottomBlock === NETWORK && + <Network /> + } + { bottomBlock === STACKEVENTS && + <StackEvents /> + } + { bottomBlock === STORAGE && + <Storage /> + } + { bottomBlock === PROFILER && + <Profiler /> + } + { bottomBlock === PERFORMANCE && + <ConnectedPerformance /> + } + { bottomBlock === GRAPHQL && + <GraphQL /> + } + { bottomBlock === FETCH && + <Fetch /> + } + { bottomBlock === EXCEPTIONS && + <Exceptions /> + } + { bottomBlock === LONGTASKS && + <LongTasks /> + } + </div> + } + </div> + ); + } +} diff --git a/frontend/app/components/Session_/PlayerBlockHeader.js b/frontend/app/components/Session_/PlayerBlockHeader.js new file mode 100644 index 000000000..837713685 --- /dev/null +++ b/frontend/app/components/Session_/PlayerBlockHeader.js @@ -0,0 +1,143 @@ +import { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom'; +import { browserIcon, osIcon, deviceTypeIcon } from 'App/iconNames'; +import { formatTimeOrDate } from 'App/date'; +import { sessions as sessionsRoute, funnelIssue as funnelIssueRoute, withSiteId } from 'App/routes'; +import { Icon, CountryFlag, IconButton, BackLink } from 'UI'; +import { toggleFavorite } from 'Duck/sessions'; +import cn from 'classnames'; +import { connectPlayer } from 'Player'; +import HeaderInfo from './HeaderInfo'; +import SharePopup from '../shared/SharePopup/SharePopup'; +import { fetchList as fetchListIntegration } from 'Duck/integrations/actions'; + +import cls from './playerBlockHeader.css'; +import Issues from './Issues/Issues'; + +const SESSIONS_ROUTE = sessionsRoute(); + +function capitalise(str) { + return str[0].toUpperCase() + str.slice(1); +} +@connectPlayer(state => ({ + width: state.width, + height: state.height, + live: state.live, + loading: state.cssLoading || state.messagesLoading, +})) +@connect((state, props) => ({ + session: state.getIn([ 'sessions', 'current' ]), + loading: state.getIn([ 'sessions', 'toggleFavoriteRequest', 'loading' ]), + disabled: state.getIn([ 'components', 'targetDefiner', 'inspectorMode' ]) || props.loading, + jiraConfig: state.getIn([ 'issues', 'list' ]).first(), + issuesFetched: state.getIn([ 'issues', 'issuesFetched' ]), + local: state.getIn(['sessions', 'timezone']), + funnelRef: state.getIn(['funnels', 'navRef']), + siteId: state.getIn([ 'user', 'siteId' ]), +}), { + toggleFavorite, fetchListIntegration +}) +@withRouter +export default class PlayerBlockHeader extends React.PureComponent { + componentDidMount() { + if (!this.props.issuesFetched) + this.props.fetchListIntegration('issues') + } + + getDimension = (width, height) => ( + <div className="flex items-center"> + { width || 'x' } <Icon name="close" size="12" className="mx-1" /> { height || 'x' } + </div> + ); + + backHandler = () => { + const { funnelRef, history, siteId } = this.props; + if (history.action !== 'POP') + history.goBack(); + else + history.push(withSiteId(SESSIONS_ROUTE), siteId); + // if (funnelRef) { + // history.push(withSiteId(funnelIssueRoute(funnelRef.funnelId, funnelRef.issueId), funnelRef.siteId)); + // } else { + // history.push(withSiteId(SESSIONS_ROUTE), siteId); + // } + } + + toggleFavorite = () => { + const { session } = this.props; + this.props.toggleFavorite(session); + } + + render() { + const { + width, + height, + session: { + sessionId, + userCountry, + userId, + favorite, + startedAt, + userBrowser, + userOs, + userDevice, + userBrowserVersion, + userDeviceType, + }, + loading, + live, + disabled, + jiraConfig, + fullscreen + } = this.props; + + return ( + <div className={ cn(cls.header, "flex justify-between", { "hidden" : fullscreen}) }> + <div className="flex w-full"> + <BackLink onClick={this.backHandler} label="Back" /> + + <div className={ cls.divider } /> + + <div className="mx-4 flex items-center"> + <CountryFlag country={ userCountry } /> + <div className="ml-2 font-normal color-gray-dark mt-1 text-sm"> + { formatTimeOrDate(startedAt) } <span>{ this.props.local === 'UTC' ? 'UTC' : ''}</span> + </div> + </div> + + <HeaderInfo icon={ browserIcon(userBrowser) } label={ `v${ userBrowserVersion }` } /> + <HeaderInfo icon={ deviceTypeIcon(userDeviceType) } label={ capitalise(userDevice) } /> + <HeaderInfo icon="expand-wide" label={ this.getDimension(width, height) } /> + <HeaderInfo icon={ osIcon(userOs) } label={ userOs } /> + + <div className='ml-auto flex items-center'> + <IconButton + className="mr-2" + tooltip="Bookmark" + onClick={ this.toggleFavorite } + loading={ loading } + icon={ favorite ? 'star-solid' : 'star' } + // label={ favorite ? 'Favourited' : 'Favourite' } + plain + /> + <SharePopup + entity="sessions" + id={ sessionId } + trigger={ + <IconButton + className="mr-2" + tooltip="Share Session" + disabled={ disabled } + icon={ 'share-alt' } + //label="Share" + plain + /> + } + /> + { !live && jiraConfig && jiraConfig.token && <Issues sessionId={ sessionId } /> } + </div> + </div> + </div> + ); + } +} diff --git a/frontend/app/components/Session_/Profiler/ProfileInfo.js b/frontend/app/components/Session_/Profiler/ProfileInfo.js new file mode 100644 index 000000000..c772f2dae --- /dev/null +++ b/frontend/app/components/Session_/Profiler/ProfileInfo.js @@ -0,0 +1,37 @@ +import { JSONTree } from 'UI' +import cn from 'classnames'; + +export default class ProfileInfo extends React.PureComponent { + render() { + const { + profile: { + name, + args, + result, + } + } = this.props; + + // let jsonPayload = undefined; + // let jsonResponse = undefined; + // try { + // jsonPayload = JSON.parse(payload); + // } catch (e) {} + // try { + // jsonResponse = JSON.parse(response); + // } catch (e) {} + return ( + <div className="px-6" > + <h5 className="py-3">{"Arguments"}</h5> + <ul className="color-gray-medium"> + { args.split(',').map(arg => ( + <li> { `${ arg }` } </li> + ))} + </ul> + <h5 className="py-3" >{"Result"}</h5> + <div className="color-gray-medium" > + { `${ result }` } + </div> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/Profiler/Profiler.js b/frontend/app/components/Session_/Profiler/Profiler.js new file mode 100644 index 000000000..4609a1427 --- /dev/null +++ b/frontend/app/components/Session_/Profiler/Profiler.js @@ -0,0 +1,79 @@ +import { connectPlayer } from 'Player'; +import { Icon, SlideModal, TextEllipsis, Input } from 'UI'; +import { getRE } from 'App/utils'; + +import ProfileInfo from './ProfileInfo'; +import TimeTable from '../TimeTable'; +import BottomBlock from '../BottomBlock'; + +const renderDuration = p => `${ p.duration }ms`; +const renderName = p => <TextEllipsis text={ p.name } />; + +@connectPlayer(state => ({ + profiles: state.profilesList, +})) +export default class Profiler extends React.PureComponent { + state = { + filter: '', + modalProfile: null, + } + onFilterChange = (e, { value }) => this.setState({ filter: value }) + + onProfileClick = resource => { + this.setState({ modalProfile: resource }); + } + closeModal = () => this.setState({ modalProfile: null }) + + render() { + const { profiles } = this.props; + const { filter, modalProfile } = this.state; + const filterRE = getRE(filter, 'i'); + const filteredProfiles = profiles.filter(({ name }) => filterRE.test(name)); + + return ( + <React.Fragment> + <SlideModal + title={ modalProfile && modalProfile.name } + isDisplayed={ modalProfile !== null } + content={ modalProfile && <ProfileInfo profile={ modalProfile } />} + size="middle" + onClose={ this.closeModal } + /> + <BottomBlock> + <BottomBlock.Header> + <h4 className="text-lg">Profiler</h4> + <Input + className="input-small" + placeholder="Filter by Name" + icon="search" + iconPosition="left" + name="filter" + onChange={ this.onFilterChange } + /> + </BottomBlock.Header> + <BottomBlock.Content> + <TimeTable + rows={ filteredProfiles } + onRowClick={ this.onProfileClick } + hoverable + > + {[ + { + label: "Name", + dataKey: 'name', + width: 200, + render: renderName, + }, { + label: "Time", + key: 'duration', + width: 80, + render: renderDuration, + } + ]} + </TimeTable> + </BottomBlock.Content> + </BottomBlock> + </React.Fragment> + ); + } +} diff --git a/frontend/app/components/Session_/Profiler/index.js b/frontend/app/components/Session_/Profiler/index.js new file mode 100644 index 000000000..1c54b4641 --- /dev/null +++ b/frontend/app/components/Session_/Profiler/index.js @@ -0,0 +1 @@ +export { default } from './Profiler'; \ No newline at end of file diff --git a/frontend/app/components/Session_/StackEvents/StackEvents.js b/frontend/app/components/Session_/StackEvents/StackEvents.js new file mode 100644 index 000000000..7145bf7fd --- /dev/null +++ b/frontend/app/components/Session_/StackEvents/StackEvents.js @@ -0,0 +1,77 @@ +import { connect } from 'react-redux'; +import { connectPlayer } from 'Player'; +import { NoContent, Tabs } from 'UI'; +import withEnumToggle from 'HOCs/withEnumToggle'; +import { hideHint } from 'Duck/components/player'; +import { typeList } from 'Types/session/stackEvent'; +import UserEvent from './UserEvent'; +import Autoscroll from '../Autoscroll'; +import BottomBlock from '../BottomBlock'; + +const ALL = 'ALL'; + +const TABS = [ ALL, ...typeList ].map(tab =>({ text: tab, key: tab })); + +@withEnumToggle('activeTab', 'setActiveTab', ALL) +@connectPlayer(state => ({ + stackEvents: state.stackList, +})) +@connect(state => ({ + hintIsHidden: state.getIn(['components', 'player', 'hiddenHints', 'stack']) || + !state.getIn([ 'user', 'client', 'sites' ]).some(s => s.stackIntegrations), +}), { + hideHint +}) +export default class StackEvents extends React.PureComponent { +// onFilterChange = (e, { value }) => this.setState({ filter: value }) + + render() { + const { stackEvents, activeTab, setActiveTab, hintIsHidden } = this.props; + //const filterRE = new RegExp(filter, 'i'); + + const tabs = TABS.filter(({ key }) => key === ALL || stackEvents.some(({ source }) => key === source)); + + const filteredStackEvents = stackEvents +// .filter(({ data }) => data.includes(filter)) + .filter(({ source }) => activeTab === ALL || activeTab === source); + + return ( + <BottomBlock> + <BottomBlock.Header> + <Tabs + className="uppercase" + tabs={ tabs } + active={ activeTab } + onClick={ setActiveTab } + border={ false } + /> + </BottomBlock.Header> + <BottomBlock.Content> + <NoContent + title="Nothing to display yet." + subtext={ !hintIsHidden + ? + <> + <a className="underline color-teal" href="https://docs.openreplay.com/integrations" target="_blank">Integrations</a> + {' and '} + <a className="underline color-teal" href="https://docs.openreplay.com/api#event" target="_blank">Events</a> + { ' make debugging easier. Sync your backend logs and custom events with session replay.' } + <br/><br/> + <button className="color-teal" onClick={() => this.props.hideHint("stack")}>Got It!</button> + </> + : null + } + size="small" + show={ filteredStackEvents.length === 0 } + > + <Autoscroll> + { filteredStackEvents.map(userEvent => ( + <UserEvent key={ userEvent.key } userEvent={ userEvent }/> + ))} + </Autoscroll> + </NoContent> + </BottomBlock.Content> + </BottomBlock> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/StackEvents/UserEvent/JsonViewer.js b/frontend/app/components/Session_/StackEvents/UserEvent/JsonViewer.js new file mode 100644 index 000000000..9815a660f --- /dev/null +++ b/frontend/app/components/Session_/StackEvents/UserEvent/JsonViewer.js @@ -0,0 +1,14 @@ +import { Icon, JSONTree } from 'UI'; + +export default class JsonViewer extends React.PureComponent { + render() { + const { data, title, icon } = this.props; + return ( + <div className="p-5"> + <Icon name={ icon } size="54" /> + <h4 className="my-5"> { title }</h4> + <JSONTree src={ data } collapsed={ false } /> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/StackEvents/UserEvent/Sentry.js b/frontend/app/components/Session_/StackEvents/UserEvent/Sentry.js new file mode 100644 index 000000000..859d1ce60 --- /dev/null +++ b/frontend/app/components/Session_/StackEvents/UserEvent/Sentry.js @@ -0,0 +1,76 @@ +import { getIn, get } from 'immutable'; +import cn from 'classnames'; +import { withRequest } from 'HOCs'; +import { Loader, Modal, Icon, JSONTree } from 'UI'; +import { Accordion } from 'semantic-ui-react' +import stl from './sentry.css'; + +@withRequest({ + endpoint: props => `/integrations/sentry/events/${ props.event.id }`, + dataName: "detailedEvent", + loadOnInitialize: true +}) +export default class SentryEventInfo extends React.PureComponent { + + makePanelsFromStackTrace(stacktrace) { + return get(stacktrace, 'frames', []).map(({ filename, function: method, lineNo, context = [] }) => ({ + key: `${ filename }_${ method }_${ lineNo }`, + title: { + content: ( + <span className={ stl.accordionTitle }> + <b>{ filename }</b> + { ' in ' } + <b>{ method }</b> + { ' at line '} + <b>{ lineNo }</b> + </span> + ), + }, + content: { + content: ( + <ol start={ getIn(context, [ 0, 0 ], 0) } className={ stl.lineList }> + { context.map(([ ctxLineNo, codeText ]) => ( + <li className={ cn(stl.codeLine, { [ stl.highlighted ]: ctxLineNo === lineNo }) }> + { codeText } + </li> + ))} + </ol> + )} + })); + } + + renderBody() { + const { detailedEvent, requestError, event } = this.props; + + const exceptionEntry = get(detailedEvent, ['entries'], []).find(({ type }) => type === "exception"); + const stacktraces = getIn(exceptionEntry, ['data', 'values']); + if (!stacktraces) { + return <JSONTree src={ requestError ? event : detailedEvent } sortKeys={ false } enableClipboard /> + } + return stacktraces.map(({ type, value, stacktrace }) => ( + <div key={ type } className={ stl.stacktrace } > + <h6>{ type }</h6> + <p> + { value } + </p> + <Accordion styled panels={ this.makePanelsFromStackTrace(stacktrace) }/> + </div> + )); + } + + render() { + const { + open, + toggleOpen, + loading, + } = this.props; + return ( + <div className={ stl.wrapper }> + <Icon className={ stl.icon } name="integrations/sentry-text" height="25" width="70" color="gray-medium"/> + <Loader loading={ loading } > + { this.renderBody() } + </Loader> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/StackEvents/UserEvent/UserEvent.js b/frontend/app/components/Session_/StackEvents/UserEvent/UserEvent.js new file mode 100644 index 000000000..dc58d8b81 --- /dev/null +++ b/frontend/app/components/Session_/StackEvents/UserEvent/UserEvent.js @@ -0,0 +1,113 @@ +import cn from 'classnames'; +import { OPENREPLAY, SENTRY, DATADOG, STACKDRIVER } from 'Types/session/stackEvent'; +import { Modal, Icon, SlideModal } from 'UI'; +import withToggle from 'HOCs/withToggle'; +import Sentry from './Sentry'; +import JsonViewer from './JsonViewer'; +import stl from './userEvent.css'; + +// const modalSources = [ SENTRY, DATADOG ]; + +@withToggle() // +export default class UserEvent extends React.PureComponent { + getIconProps() { + const { source } = this.props.userEvent; + return { + name: `integrations/${ source }`, + size: 18, + marginRight: source === OPENREPLAY ? 11 : 10 + } + } + + getLevelClassname() { + const { userEvent } = this.props; + if (userEvent.isRed()) return "error color-red"; + return ''; + } + + // getEventMessage() { + // const { userEvent } = this.props; + // switch(userEvent.source) { + // case SENTRY: + // case DATADOG: + // return null; + // default: + // return JSON.stringify(userEvent.data); + // } + // } + + renderPopupContent() { + const { userEvent: { source, payload, name} } = this.props; + switch(source) { + case SENTRY: + return <Sentry event={ payload } />; + case DATADOG: + return <JsonViewer title={ name } data={ payload } icon="integrations/datadog" />; + case STACKDRIVER: + return <JsonViewer title={ name } data={ payload } icon="integrations/stackdriver" />; + default: + return <JsonViewer title={ name } data={ payload } icon={ `integrations/${ source }-text` } />; + } + } + + ifNeedModal() { + return !!this.props.userEvent.payload; + } + + renderContent(modalTrigger) { + const { userEvent } = this.props; + //const message = this.getEventMessage(); + return ( + <div + data-scroll-item={ userEvent.isRed() } + onClick={ this.props.switchOpen } // + className={ + cn( + stl.userEvent, + this.getLevelClassname(), + { [ stl.modalTrigger ]: modalTrigger } + ) + } + > + <div className={ stl.infoWrapper }> + <div + className={ stl.title } + > + <Icon { ...this.getIconProps() } /> + { userEvent.name } + </div> + { /* message && + <div className={ stl.message }> + { message } + </div> */ + } + </div> + </div> + ); + } + + render() { + const { userEvent } = this.props; + if (this.ifNeedModal()) { + return ( + <React.Fragment> + <SlideModal + //title="Add Custom Field" + size="middle" + isDisplayed={ this.props.open } + content={ this.props.open && this.renderPopupContent() } + onClose={ this.props.switchOpen } + /> + { this.renderContent(true) } + </React.Fragment> + //<Modal + // trigger={ this.renderContent(true) } + // content={ this.renderPopupContent() } + // centered={ false } + // size="small" + // /> + ); + } + return this.renderContent(); + } +} diff --git a/frontend/app/components/Session_/StackEvents/UserEvent/index.js b/frontend/app/components/Session_/StackEvents/UserEvent/index.js new file mode 100644 index 000000000..0a10efe3e --- /dev/null +++ b/frontend/app/components/Session_/StackEvents/UserEvent/index.js @@ -0,0 +1 @@ +export { default } from './UserEvent'; \ No newline at end of file diff --git a/frontend/app/components/Session_/StackEvents/UserEvent/sentry.css b/frontend/app/components/Session_/StackEvents/UserEvent/sentry.css new file mode 100644 index 000000000..75956a074 --- /dev/null +++ b/frontend/app/components/Session_/StackEvents/UserEvent/sentry.css @@ -0,0 +1,47 @@ + +.wrapper { + padding: 20px 40px 30px; +} +.icon { + margin-left: -5px; +} +.stacktrace { + & h6 { + display: flex; + align-items: center; + font-size: 17px; + padding-top: 7px; + margin-bottom: 10px; + } + & p { + font-family: 'Menlo', 'monaco', 'consolas', monospace; + } +} + + +.accordionTitle { + font-weight: 100; + & > b { + font-weight: 700; + } +} + +.lineList { + list-style-position: inside; + list-style-type: decimal-leading-zero; + background: $gray-lightest; +} + +.codeLine { + font-family: 'Menlo', 'monaco', 'consolas', monospace; + line-height: 24px; + font-size: 12px; + white-space: pre-wrap; + word-wrap: break-word; + min-height: 24px; + padding: 0 25px; + &.highlighted { + background: $red; + color: $white; + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/StackEvents/UserEvent/userEvent.css b/frontend/app/components/Session_/StackEvents/UserEvent/userEvent.css new file mode 100644 index 000000000..57388ffe5 --- /dev/null +++ b/frontend/app/components/Session_/StackEvents/UserEvent/userEvent.css @@ -0,0 +1,38 @@ + +.userEvent { + border-radius: 3px; + background-color: rgba(0, 118, 255, 0.05); + font-family: 'Menlo', 'monaco', 'consolas', monospace; + padding: 8px 10px; + margin: 3px 0; + + &.modalTrigger { + cursor: pointer; + } +} + +.infoWrapper { + overflow: hidden; + display: flex; + align-items: flex-start; +} + +.title { + display: block; + color: $gray-dark; + display: flex; + align-items: center; + font-size: 13px; + font-weight: 500; + margin-right: 10px; +} + +.message { + /* padding-left: 26px; */ + /* padding-top: 10px; */ + font-size: 13px; + overflow-x: auto; + &::-webkit-scrollbar { + height: 1px; + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/StackEvents/stackEvents.css b/frontend/app/components/Session_/StackEvents/stackEvents.css new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/app/components/Session_/Storage/Storage.js b/frontend/app/components/Session_/Storage/Storage.js new file mode 100644 index 000000000..db6d9216b --- /dev/null +++ b/frontend/app/components/Session_/Storage/Storage.js @@ -0,0 +1,248 @@ +//import cn from 'classnames'; +//import withEnumToggle from 'HOCs/withEnumToggle'; +import { connect } from 'react-redux'; +import { hideHint } from 'Duck/components/player'; +import { + connectPlayer, + selectStorageType, + STORAGE_TYPES, + selectStorageListNow, + selectStorageList, +} from 'Player/store'; +import { JSONTree, IconButton, Icon, Popup, Tabs, NoContent } from 'UI'; +import { formatMs } from 'App/date'; + +import { jump } from 'Player'; +import Autoscroll from '../Autoscroll'; +import BottomBlock from '../BottomBlock/index'; + +import stl from './storage.css'; + +// const STATE = 'STATE'; +// const DIFF = 'DIFF'; +// const TABS = [ DIFF, STATE ].map(tab => ({ text: tab, key: tab })); + + +function getActionsName(type) { + switch(type) { + case STORAGE_TYPES.MOBX: + return "EVENTS"; + case STORAGE_TYPES.VUEX: + return "MUTATIONS"; + default: + return "ACTIONS"; + } +} + +@connectPlayer(state => ({ + type: selectStorageType(state), + list: selectStorageList(state), + listNow: selectStorageListNow(state), +})) +@connect(state => ({ + hintIsHidden: state.getIn(['components', 'player', 'hiddenHints', 'storage']), +}), { + hideHint +}) +//@withEnumToggle('activeTab', 'setActiveTab', DIFF) +export default class Storage extends React.PureComponent { + lastBtnRef = React.createRef() + + focusNextButton() { + if (this.lastBtnRef.current) { + this.lastBtnRef.current.focus(); + } + } + + componentDidMount() { + this.focusNextButton(); + } + + componentDidUpdate(prevProps) { + if (prevProps.listNow.length !== this.props.listNow.length) { + this.focusNextButton(); + } + } + + renderDiff() { + // const { listNow, type } = this.props; + // const lastRAction = listNow[ listNow.length - 1 ]; + // if (lastRAction.state) { + // const greenPaths = Object.keys(lastRAction.state).map(key => [ key ]); + // return <DiffTree data={ lastRAction.state } greenPaths={ greenPaths } />; + // } + // const df = {}; + // const redPaths = []; + // const yellowPaths = []; + // const greenPaths = []; + // lastRAction.diff.forEach(d => { + // try { + // let { path, kind, rhs: value } = d; + // if (kind === 'A') { + // path.slice().push(d.index); + // kind = d.item.kind; + // value = d.item.rhs; + // } + // setIn(df, path, value); + // if (kind === 'N') greenPaths.push(d.path.slice().reverse()); + // if (kind === 'D') redPaths.push(d.path.slice().reverse()); + // if (kind === 'E') yellowPaths.push(d.path.slice().reverse()); + // } catch (e) { + // } + // }); + // return ( + // <DiffTree + // data={ df } + // redPaths={ redPaths } + // yellowPaths={ yellowPaths } + // greenPaths={ greenPaths } + // /> + // ); + } + + ensureString(actionType) { + if (typeof actionType === 'string') return actionType; + return "UNKNOWN"; + } + + goNext = () => { + const { list, listNow } = this.props; + jump(list[ listNow.length ].time, list[ listNow.length ]._index); + } + + + renderTab () { + // switch(this.props.activeTab) { + // case DIFF: + // return this.renderDiff(); + // case STATE: + const { listNow } = this.props; + if (listNow.length === 0) { + return "Not initialized"; //? + } + return <JSONTree src={ listNow[ listNow.length - 1 ].state } />; + // } + // return null; + } + + renderItem(item, i) { + const { type, listNow, list } = this.props; + let src; + let name; + switch(type) { + case STORAGE_TYPES.REDUX: + case STORAGE_TYPES.NGRX: + src = item.action; + name = src && src.type; + break; + case STORAGE_TYPES.VUEX: + src = item.mutation; + name = src && src.type; + break; + case STORAGE_TYPES.MOBX: + src = item.payload; + name = `@${item.type} ${src && src.name}`; + break; + } + + return ( + <div className="flex justify-between items-start" key={ `store-${i}` }> + <JSONTree + name={ this.ensureString(name) } + src={ src } + collapsed + collapseStringsAfterLength={ 7 } + /> + <div className="flex items-center"> + { i + 1 < listNow.length && + <button + className={ stl.button } + onClick={ () => jump(item.time, item._index) } + > + {"JUMP"} + </button> + } + { i + 1 === listNow.length && i + 1 < list.length && + <button + className={ stl.button } + ref={ this.lastBtnRef } + onClick={ this.goNext } + > + {"NEXT"} + </button> + } + { typeof item.duration === 'number' && + <div className="font-size-12 color-gray-medium"> + { formatMs(item.duration) } + </div> + } + </div> + </div> + ); + } + + render() { + const { + type, + listNow, + activeTab, + setActiveTab, + list, + hintIsHidden, + } = this.props; + + const showStore = type !== STORAGE_TYPES.MOBX; + return ( + <BottomBlock> + <BottomBlock.Header> + { list.length > 0 && + <div className="flex w-full"> + { showStore && + <h3 style={{ width: "40%" }}> + {"STORE"} + </h3> + } + <h3 style={{ width: "40%" }}> + {getActionsName(type)} + </h3> + </div> + } + </BottomBlock.Header> + <BottomBlock.Content className="flex" > + <NoContent + title="Nothing to display yet." + subtext={ !hintIsHidden + ? + <> + {'Inspect your application state while you’re replaying your users sessions. OpenReplay supports '} + <a className="underline color-teal" href="https://docs.openreplay.com/plugins/redux" target="_blank">Redux</a>{', '} + <a className="underline color-teal" href="https://docs.openreplay.com/plugins/vuex" target="_blank">VueX</a>{', '} + <a className="underline color-teal" href="https://docs.openreplay.com/plugins/mobx" target="_blank">MobX</a>{' and '} + <a className="underline color-teal" href="https://docs.openreplay.com/plugins/ngrx" target="_blank">NgRx</a>. + <br/><br/> + <button className="color-teal" onClick={() => this.props.hideHint("storage")}>Got It!</button> + </> + : null + } + size="small" + show={ listNow.length === 0 } + > + { showStore && + <div className="ph-10 scroll-y" style={{ width: "40%" }} > + { listNow.length === 0 + ? <div className="color-gray-light font-size-16 mt-20 text-center" >{ "Empty state." }</div> + : this.renderTab() + } + </div> + } + <div className="flex" style={{ width: showStore ? "60%" : "100%" }} > + <Autoscroll className="ph-10" > + { listNow.map((item, i) => this.renderItem(item, i)) } + </Autoscroll> + </div> + </NoContent> + </BottomBlock.Content> + </BottomBlock> + ); + } +} diff --git a/frontend/app/components/Session_/Storage/index.js b/frontend/app/components/Session_/Storage/index.js new file mode 100644 index 000000000..9917ce146 --- /dev/null +++ b/frontend/app/components/Session_/Storage/index.js @@ -0,0 +1 @@ +export { default } from './Storage'; \ No newline at end of file diff --git a/frontend/app/components/Session_/Storage/storage.css b/frontend/app/components/Session_/Storage/storage.css new file mode 100644 index 000000000..55f04d5db --- /dev/null +++ b/frontend/app/components/Session_/Storage/storage.css @@ -0,0 +1,17 @@ + +.button { + padding: 2px 6px; + cursor: pointer; + width: 60px; + border-radius: 3px; + color: $gray-light; + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + color: $gray-darkest; + } + + font-size: 12px; + + margin-right: 5px; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/TimeTable/BarRow.js b/frontend/app/components/Session_/TimeTable/BarRow.js new file mode 100644 index 000000000..278cb9006 --- /dev/null +++ b/frontend/app/components/Session_/TimeTable/BarRow.js @@ -0,0 +1,83 @@ +import { Popup } from 'UI'; +import { percentOf } from 'App/utils'; +import styles from './barRow.css' +import tableStyles from './timeTable.css'; + +const formatTime = time => time < 1000 ? `${ time.toFixed(2) }ms` : `${ time / 1000 }s`; + +const BarRow = ({ resource: { time, ttfb = 0, duration, key }, popup=false, timestart = 0, timewidth }) => { + const timeOffset = time - timestart; + ttfb = ttfb || 0; + const trigger = ( + <div + className={ styles.barWrapper } + style={ { + left: `${ percentOf(timeOffset, timewidth) }%`, + right: `${ 100 - percentOf(timeOffset + duration, timewidth) }%`, + minWidth: '5px' + } } + > + <div + className={ styles.ttfbBar } + style={ { + width: `${ percentOf(ttfb, duration) }%`, + } } + /> + <div + className={ styles.downloadBar } + style={ { + width: `${ percentOf(duration - ttfb, duration) }%`, + minWidth: '5px' + } } + /> + </div> + ); + if (!popup) return <div key={ key } className={ tableStyles.row } > { trigger } </div>; + + return ( + <div key={ key } className={ tableStyles.row } > + <Popup + basic + trigger={ trigger } + content={ + <React.Fragment> + { ttfb != null && + <div className={ styles.popupRow }> + <div className={ styles.title }>{ 'Waiting (TTFB)' }</div> + <div className={ styles.popupBarWrapper} > + <div + className={ styles.ttfbBar } + style={{ + left: 0, + width: `${ percentOf(ttfb, duration) }%`, + }} + /> + </div> + <div className={ styles.time } >{ formatTime(ttfb) }</div> + </div> + } + <div className={ styles.popupRow }> + <div className={ styles.title } >{ 'Content Download' }</div> + <div className= { styles.popupBarWrapper }> + <div + className={ styles.downloadBar } + style={{ + left: `${ percentOf(ttfb, duration) }%`, + width: `${ percentOf(duration - ttfb, duration) }%`, + }} + /> + </div> + <div className={ styles.time }>{ formatTime(duration - ttfb) }</div> + </div> + </React.Fragment> + } + size="mini" + position="top center" + /> + </div> + ); +} + +BarRow.displayName = "BarRow"; + +export default BarRow; \ No newline at end of file diff --git a/frontend/app/components/Session_/TimeTable/TimeTable.js b/frontend/app/components/Session_/TimeTable/TimeTable.js new file mode 100644 index 000000000..7ab37101a --- /dev/null +++ b/frontend/app/components/Session_/TimeTable/TimeTable.js @@ -0,0 +1,334 @@ +// @flow +import { List, AutoSizer } from "react-virtualized"; + +import cn from 'classnames'; +import { NoContent, IconButton } from 'UI'; +import { percentOf } from 'App/utils'; +import { formatMs } from 'App/date'; + +import BarRow from './BarRow'; +import stl from './timeTable.css'; + +import autoscrollStl from '../autoscroll.css'; //aaa + + +type Timed = { + +time: number, +} + +type Durationed = { + +duration: number, +} + +type CanBeRed = { + //+isRed: boolean, + isRed: () => boolean, +} + +type Row = Timed & Durationed & CanBeRed + +type Line = { + color: string, // Maybe use typescript? + hint?: string, + onClick?: Line => any, +} & Timed + +type Column = { + label: string, + width: number, + referenceLines: ?Array<Line>, + style?: Object, +} & RenderOrKey + +type RenderOrKey = { // Disjoint? + render: Row => React.Node +} | { + dataKey: string, +} + + +type Props = { + className?: string, + rows: Array<Row>, + + children: Array<Column> +} + +type TimeLineInfo = { + timestart: number, + timewidth: number, +} + +type State = TimeLineInfo & typeof initialState; + +//const TABLE_HEIGHT = 195; +let _additionalHeight = 0; +const ROW_HEIGHT = 32; +//const VISIBLE_COUNT = Math.ceil(TABLE_HEIGHT/ROW_HEIGHT); + +const TIME_SECTIONS_COUNT = 8; +const ZERO_TIMEWIDTH = 1000; +function formatTime(ms) { + if(ms < 0) return ""; + return formatMs(ms); +} + +function computeTimeLine(rows: Array<Row>, firstVisibleRowIndex: number, visibleCount): TimeLineInfo { + const visibleRows = rows.slice(firstVisibleRowIndex, firstVisibleRowIndex + visibleCount + _additionalHeight); + let timestart = visibleRows.length > 0 + ? Math.min(...visibleRows.map(r => r.time)) + : 0; + const timeend = visibleRows.length > 0 + ? Math.max(...visibleRows.map(r => r.time + r.duration)) + : 0; + let timewidth = timeend - timestart; + const offset = timewidth / 70; + if (timestart >= offset) { + timestart -= offset; + } + timewidth *= 1.5; // += offset; + if (timewidth === 0) { + timewidth = ZERO_TIMEWIDTH; + } + return { + timestart, + timewidth, + }; +} + +const initialState = { + firstVisibleRowIndex: 0, +} + +export default class TimeTable extends React.PureComponent<Props, State> { + state = { + ...computeTimeLine(this.props.rows, initialState.firstVisibleRowIndex, this.visibleCount), + ...initialState, + } + + get tableHeight() { + return this.props.tableHeight || 195; + } + + get visibleCount() { + return Math.ceil(this.tableHeight/ROW_HEIGHT); + } + + scroller = React.createRef(); + autoScroll = true; + + // componentDidMount() { + // if (this.scroller.current != null) { + // this.scroller.current.scrollToRow(this.props.rows.length - 1); + // } + // } + + componentDidUpdate(prevProps, prevState) { + // if (prevProps.rows.length !== this.props.rows.length && + // this.autoScroll && + // this.scroller.current != null) { + // this.scroller.current.scrollToRow(this.props.rows.length); + // } + if (prevState.firstVisibleRowIndex !== this.state.firstVisibleRowIndex || + (this.props.rows.length <= (this.visibleCount + _additionalHeight) && prevProps.rows.length !== this.props.rows.length)) { + this.setState({ + ...computeTimeLine(this.props.rows, this.state.firstVisibleRowIndex, this.visibleCount), + }); + } + if (this.props.activeIndex && prevProps.activeIndex !== this.props.activeIndex) { + this.scroller.current.scrollToRow(this.props.activeIndex); + } + } + + onScroll = ({ scrollTop, scrollHeight, clientHeight }: + { scrollTop: number, scrollHeight: number, clientHeight: number }):void => { + const firstVisibleRowIndex = Math.floor(scrollTop / ROW_HEIGHT + 0.33); + + if (this.state.firstVisibleRowIndex !== firstVisibleRowIndex) { + this.autoScroll = (scrollHeight - clientHeight - scrollTop) < ROW_HEIGHT / 2; + this.setState({ firstVisibleRowIndex }); + } + } + + renderRow = ({ index, key, style: rowStyle }) => { + const { activeIndex } = this.props; + const { + children: columns, + rows, + renderPopup, + hoverable, + onRowClick, + } = this.props; + const { + timestart, + timewidth, + } = this.state; + const row = rows[ index ]; + return ( + <div + style={ rowStyle } + key={ key } + className={ cn('border-b border-color-gray-light-shade', stl.row, { [ stl.hoverable ]: hoverable, "error color-red": !!row.isRed && row.isRed(), 'cursor-pointer' : typeof onRowClick === "function", [stl.activeRow] : activeIndex === index, 'color-white' : activeIndex === index }) } + onClick={ typeof onRowClick === "function" ? () => onRowClick(row, index) : null } + id="table-row" + > + { columns.map(({ dataKey, render, width }) => ( + <div className={ stl.cell } style={{ width: `${width}px`}}> + { render ? render(row) : (row[ dataKey ] || <i className="color-gray-light">{"empty"}</i>) } + </div> + ))} + <div className={ cn("relative flex-1 flex", stl.timeBarWrapper)}> + <BarRow + resource={ row } + timestart={ timestart } + timewidth={ timewidth } + popup={ renderPopup } + /> + </div> + </div> + ); + } + + onPrevClick = () => { + let prevRedIndex = -1; + for (let i = this.state.firstVisibleRowIndex-1; i >= 0; i--) { + if (this.props.rows[ i ].isRed()) { + prevRedIndex = i; + break; + } + } + if (this.scroller.current != null) { + this.scroller.current.scrollToRow(prevRedIndex); + } + } + + onNextClick = () => { + let prevRedIndex = -1; + for (let i = this.state.firstVisibleRowIndex+1; i < this.props.rows.length; i++) { + if (this.props.rows[ i ].isRed()) { + prevRedIndex = i; + break; + } + } + if (this.scroller.current != null) { + this.scroller.current.scrollToRow(prevRedIndex); + } + } + + render() { + const { + className, + rows, + children: columns, + navigation=false, + referenceLines = [], + additionalHeight = 0, + activeIndex + } = this.props; + const { + timewidth, + timestart, + } = this.state; + + _additionalHeight = additionalHeight; + + const sectionDuration = Math.round(timewidth / TIME_SECTIONS_COUNT); + const timeColumns = []; + if (timewidth > 0) { + for (let i = 0; i < TIME_SECTIONS_COUNT; i++) { + timeColumns.push(timestart + i * sectionDuration); + } + } + + const visibleRefLines = referenceLines.filter(({ time }) => time > timestart && time < timestart + timewidth); + + const columnsSumWidth = columns.reduce((sum, { width }) => sum + width, 0); + + return ( + <div className={ cn(className, "relative") }> + { navigation && + <div className={ cn(autoscrollStl.navButtons, "flex items-center") } style={{ top: '-33px', right: '30px' }} > + <IconButton + size="small" + icon="chevron-up" + onClick={this.onPrevClick} + /> + <IconButton + size="small" + icon="chevron-down" + onClick={this.onNextClick} + /> + </div> + } + <div className={ stl.headers }> + <div className={ stl.infoHeaders }> + { columns.map(({ label, width }) => ( + <div + className={ stl.headerCell } + style={{ width: `${width}px` + }}> + { label } + </div> + )) } + </div> + <div className={ stl.waterfallHeaders } > + { timeColumns.map((time, i) => ( + <div + className={ stl.timeCell } + key={ `tc-${ i }` } + > + { formatTime(time) } + </div> + )) + } + </div> + </div> + + <NoContent + size="small" + show={ rows.length === 0 } + > + <div className="relative"> + <div className={ stl.timePart } style={{ left: `${ columnsSumWidth }px` }}> + { timeColumns.map((_, index) => ( + <div + key={ `tc-${ index }` } + className={ stl.timeCell } + /> + )) + } + { visibleRefLines.map(({ time, color, onClick }) => ( + <div + className={cn(stl.refLine, `bg-${color}`)} + style={{ + left: `${ percentOf(time - timestart, timewidth) }%`, + cursor: typeof onClick === "function" ? "click" : "auto", + }} + onClick={ onClick } + /> + ))} + </div> + <AutoSizer disableHeight> + {({ width }) => ( + <List + ref={ this.scroller } + className={ stl.list } + height={this.tableHeight + additionalHeight} + width={width} + overscanRowCount={20} + rowCount={rows.length} + rowHeight={ROW_HEIGHT} + rowRenderer={this.renderRow} + onScroll={ this.onScroll } + scrollToAlignment="start" + forceUpdateProp={ timestart | timewidth | activeIndex } + /> + )} + </AutoSizer> + </div> + </NoContent> + </div> + ); + } +} + diff --git a/frontend/app/components/Session_/TimeTable/barRow.css b/frontend/app/components/Session_/TimeTable/barRow.css new file mode 100644 index 000000000..e45d1f7b2 --- /dev/null +++ b/frontend/app/components/Session_/TimeTable/barRow.css @@ -0,0 +1,45 @@ + + + +.barWrapper { + display: flex; + position: absolute; + top: 35%; + bottom: 35%; + border-radius: 3px; + overflow: hidden; +} + +.downloadBar, .ttfbBar { + /* box-shadow: inset 0px 0px 0px 1px $teal; */ + height: 100%; + box-sizing: border-box; + position: relative; +} +.ttfbBar { + background-color: rgba(175, 226, 221, 0.8); +} +.downloadBar { + background-color: rgba(133, 200, 192, 0.8); +} + +.popupRow { + color: $gray-medium; + display: flex; + align-items: center; + padding: 2px 0; + font-size: 12px; +} +.title { + width: 105px; +} +.time { + width: 60px; + padding-left: 10px; +} +.popupBarWrapper { + width: 220px; + height: 15px; + border-radius: 3px; + overflow: hidden; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/TimeTable/index.js b/frontend/app/components/Session_/TimeTable/index.js new file mode 100644 index 000000000..c3c329b0a --- /dev/null +++ b/frontend/app/components/Session_/TimeTable/index.js @@ -0,0 +1 @@ +export { default } from './TimeTable'; \ No newline at end of file diff --git a/frontend/app/components/Session_/TimeTable/timeTable.css b/frontend/app/components/Session_/TimeTable/timeTable.css new file mode 100644 index 000000000..de070634b --- /dev/null +++ b/frontend/app/components/Session_/TimeTable/timeTable.css @@ -0,0 +1,106 @@ + + +$offset: 10px; + +.timeCell { + border-left: solid thin rgba(0, 0, 0, 0.05); +} + +.headers { + box-shadow: 0 1px 2px 0 $gray-light; + background-color: $gray-lightest; + color: $gray-medium; + font-size: 12px; + overflow-x: hidden; + white-space: nowrap; + width: 100%; + display: flex; + padding: 0 $offset; +} +.infoHeaders { + text-transform: uppercase; + display: flex; + & .headerCell { + padding: 4px 2px; + } +} +.waterfallHeaders { + display: flex; + flex: 1; + & .timeCell { + flex: 1; + overflow: hidden; + padding: 4px 0; + } +} + +.list { + /* TODO hide the scrollbar track */ + &::-webkit-scrollbar { + width: 1px; + } + scrollbar-width: thin; + font-size: 12px; + font-family: 'Menlo', 'monaco', 'consolas', monospace; +} + +.row { + display: flex; + padding: 0 $offset; + /*align-items: center; + cursor: pointer; + */ + /* &:nth-child(even) { + background-color: $gray-lightest; + } */ + /* & > div:first-child { + padding-left: 5px; + }*/ +} +.cell { + height: 100%; + display: flex; + align-items: center; + overflow: hidden; + padding: 0 2px; +} +.hoverable { + transition: all 0.3s; + cursor: pointer; + &:hover { + background-color: $active-blue; + transition: all 0.2s; + color: $gray-dark; + } +} +.timeBarWrapper{ + overflow: hidden; +} + +.timePart { + position: absolute; + top: 0; + bottom: 0; + /*left:0;*/ + right: 0; + display: flex; + margin: 0 $offset; + & .timeCell { + height: 100%; + flex: 1; + z-index: 1; + pointer-events: none; + } + & .refLine { + position: absolute; + height: 100%; + width: 1px; + z-index: 1; + } +} + + + +.activeRow { + background-color: $teal; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/autoscroll.css b/frontend/app/components/Session_/autoscroll.css new file mode 100644 index 000000000..639151439 --- /dev/null +++ b/frontend/app/components/Session_/autoscroll.css @@ -0,0 +1,19 @@ +.wrapper { + & .navButtons { + opacity: 0; + transition: opacity .3s + } + &:hover { + & .navButtons { + opacity: .7; + } + } +} + +.navButtons { + position: absolute; + right: 40px; + top: 10px; +} + + diff --git a/frontend/app/components/Session_/headerInfo.css b/frontend/app/components/Session_/headerInfo.css new file mode 100644 index 000000000..b9c3b106c --- /dev/null +++ b/frontend/app/components/Session_/headerInfo.css @@ -0,0 +1,8 @@ +.wrapper { + display: flex; + flex-flow: column; + height: 40px; + justify-content: space-between; + font-size: 12px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/Session_/playerBlock.css b/frontend/app/components/Session_/playerBlock.css new file mode 100644 index 000000000..3c38ff2b3 --- /dev/null +++ b/frontend/app/components/Session_/playerBlock.css @@ -0,0 +1,4 @@ +.playerBlock { + flex: 1; + min-width: 800px; +} diff --git a/frontend/app/components/Session_/playerBlockHeader.css b/frontend/app/components/Session_/playerBlockHeader.css new file mode 100644 index 000000000..325e34256 --- /dev/null +++ b/frontend/app/components/Session_/playerBlockHeader.css @@ -0,0 +1,14 @@ +.header { + height: 50px; + border-bottom: solid thin $gray-light; + padding: 10px 15px; + background-color: white; +} + +.divider { + width: 1px; + height: 100%; + margin: 0 15px; + background-color: $gray-light; +} + diff --git a/frontend/app/components/Session_/session.css b/frontend/app/components/Session_/session.css new file mode 100644 index 000000000..16ae03e3f --- /dev/null +++ b/frontend/app/components/Session_/session.css @@ -0,0 +1,8 @@ +.session { + display: flex; + height: calc(100vh - 50px); + /* background-color: red; */ + &[data-fullscreen=true] { + height: calc(100vh); + } +} \ No newline at end of file diff --git a/frontend/app/components/Session_/session.stories.js b/frontend/app/components/Session_/session.stories.js new file mode 100644 index 000000000..3118f24f6 --- /dev/null +++ b/frontend/app/components/Session_/session.stories.js @@ -0,0 +1,298 @@ +import { storiesOf } from '@storybook/react'; +import { List } from 'immutable'; +import EventGroup from './EventsBlock/Event'; + +const groups = [ + { + "page": { + "key": "Location_257", + "time": 2751, + "type": "LOCATION", + "url": "/login", + "pageLoad": false, + "fcpTime": 6787, + "loadTime": 7872, + "domTime": 5821, + "referrer": "Search Engine" + }, + "events": [ + { + "sessionId": 2406625057772570, + "messageId": 76446, + "timestamp": 1586722257371, + "label": "Device Memory: 8.19GB", + "type": "CLICKRAGE", + "count": 3 + }, + { + "key": "Click_256", + "time": 13398, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_262", + "path": "", + "label": null + } + }, + { + "key": "Input_256", + "time": 13438, + "type": "INPUT", + "target": { + "key": "record_263", + "path": "", + "label": null + }, + "value": null + } + ] + }, + { + "page": { + "key": "Location_258", + "time": 15841, + "type": "LOCATION", + "url": "/1/sessions", + "pageLoad": false, + "fcpTime": null, + "loadTime": null, + "domTime": null, + "referrer": "" + }, + "events": [ + { + "key": "Click_257", + "time": 24408, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_264", + "path": "", + "label": null + } + } + ] + }, + { + "page": { + "key": "Location_259", + "time": 25019, + "type": "LOCATION", + "url": "/1/session/2303531983744788", + "pageLoad": false, + "fcpTime": null, + "loadTime": null, + "domTime": null, + "referrer": "" + }, + "events": [ + { + "key": "Click_258", + "time": 31134, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_265", + "path": "", + "label": null + } + }, + { + "key": "Click_259", + "time": 32022, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_266", + "path": "", + "label": null + } + }, + { + "key": "Click_260", + "time": 35951, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_267", + "path": "", + "label": null + } + }, + { + "key": "Click_261", + "time": 164029, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_268", + "path": "", + "label": null + } + }, + { + "key": "Click_262", + "time": 169739, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_269", + "path": "", + "label": null + } + }, + { + "key": "Click_263", + "time": 170524, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_270", + "path": "", + "label": null + } + }, + { + "key": "Click_264", + "time": 172580, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_271", + "path": "", + "label": null + } + }, + { + "key": "Click_265", + "time": 173102, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_272", + "path": "", + "label": null + } + }, + { + "key": "Click_266", + "time": 173698, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_273", + "path": "", + "label": null + } + }, + { + "key": "Click_267", + "time": 173867, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_274", + "path": "", + "label": null + } + }, + { + "key": "Click_268", + "time": 174599, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_275", + "path": "", + "label": null + } + }, + { + "key": "Click_269", + "time": 175148, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_276", + "path": "", + "label": null + } + }, + { + "key": "Click_270", + "time": 175779, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_277", + "path": "", + "label": null + } + }, + { + "key": "Click_271", + "time": 176658, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_278", + "path": "", + "label": null + } + }, + { + "key": "Click_272", + "time": 177267, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_279", + "path": "", + "label": null + } + }, + { + "key": "Click_273", + "time": 187025, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_280", + "path": "", + "label": null + } + }, + { + "key": "Click_274", + "time": 189787, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_281", + "path": "", + "label": null + } + }, + { + "key": "Click_275", + "time": 191326, + "type": "CLICK", + "targetContent": "", + "target": { + "key": "record_282", + "path": "", + "label": null + } + } + ] + } +] + +// storiesOf('Player', module) +// .add('Event Group', () => ( +// <EventGroup +// group={groups[0]} +// selectedEvents={[]} +// /> +// )) diff --git a/frontend/app/components/Session_/tabs.js b/frontend/app/components/Session_/tabs.js new file mode 100644 index 000000000..797bed273 --- /dev/null +++ b/frontend/app/components/Session_/tabs.js @@ -0,0 +1,51 @@ +import { + NONE, + CONSOLE, + NETWORK, + STACKEVENTS, + STORAGE, + PROFILER, + PERFORMANCE, + GRAPHQL, + FETCH, + EXCEPTIONS, + LONGTASKS, +} from 'Duck/components/player'; + +import Network from './Network'; +import Console from './Console/Console'; +import StackEvents from './StackEvents/StackEvents'; +import Storage from './Storage'; +import Profiler from './Profiler'; +import Performance from './Performance'; +import PlayerBlockHeader from './PlayerBlockHeader'; +import GraphQL from './GraphQL'; +import Fetch from './Fetch'; +import Exceptions from './Exceptions/Exceptions'; +import LongTasks from './LongTasks'; + + +const tabs = [ + { + key: CONSOLE, + Component: Console, + }, + { + key: NETWORK, + Component: Network, + }, + { + key: STORAGE, + Component: + } +] + +const tabsByKey = {}; +tabs.map() + + +export function switchTab(tabKey) { + tabKey +} + + diff --git a/frontend/app/components/Signup/Signup.js b/frontend/app/components/Signup/Signup.js new file mode 100644 index 000000000..0d3862853 --- /dev/null +++ b/frontend/app/components/Signup/Signup.js @@ -0,0 +1,75 @@ +import withPageTitle from 'HOCs/withPageTitle'; +import { Icon } from 'UI'; + +import stl from './signup.css'; +import cn from 'classnames'; +import SignupForm from './SignupForm'; + + +const BulletItem = ({ text }) => ( + <div className="flex items-center mb-4"> + <div className="mr-3 h-8 w-8 rounded-full bg-white shadow flex items-center justify-center"> + <Icon name="check" size="26"/> + </div> + <div>{text}</div> + </div> +) +@withPageTitle('Signup - OpenReplay') +export default class Signup extends React.Component { + render() { + return ( + <div className="flex" style={{ height: '100vh'}}> + <div className={cn("w-6/12", stl.left)}> + <div className="px-6 pt-10"> + <img src="/logo-white.svg" /> + </div> + <div className="color-white text-lg flex items-center px-20 pt-32"> + <div> + <div className="flex items-center text-3xl font-bold mb-6"> + OpenReplay Cloud <div className="ml-2"><Icon name="signup" size="28" color="white" /></div> + </div> + <div>OpenReplay Cloud is the hosted version of our open source package.</div> + <div>We’ll manage hosting, scaling and upgrades.</div> + + <div className="mt-8"> + <BulletItem text="First 1K sessions free every month." /> + <BulletItem text="Pay per use, cancel anytime" /> + <BulletItem text="Community, Slack & email support" /> + </div> + </div> + </div> + + <div className={cn(stl.bottom, 'absolute bottom-0 w-full py-16 px-20 color-white')}> + <div className="text-4xl mb-10">Want to self-host?</div> + + <div className="flex items-start"> + <div className="mr-4"> + <Icon name="cloud-fog2-fill" size="26" color="white" /> + </div> + <div className="text-left"> + <div className="text-xl font-bold">Private Cloud</div> + <div className="text-lg">Managed deployments, maximum scalability</div> + </div> + </div> + + <div className="border-b bg-white my-6 opacity-25" /> + <div className="flex items-start"> + <div className="mr-4"> + <Icon name="integrations/github" size="26" color="white" /> + </div> + <div className="text-left"> + <div className="text-xl font-bold">Open source</div> + <div className="text-lg">Deploy on your own infrastructure. Free forever.</div> + </div> + </div> + </div> + </div> + <div className="w-6/12 flex items-center justify-center"> + <div className=""> + <SignupForm /> + </div> + </div> + </div> + ); + } +} diff --git a/frontend/app/components/Signup/SignupForm/SignupForm.js b/frontend/app/components/Signup/SignupForm/SignupForm.js new file mode 100644 index 000000000..ffd5027e4 --- /dev/null +++ b/frontend/app/components/Signup/SignupForm/SignupForm.js @@ -0,0 +1,180 @@ +import React, { useState } from 'react' +import { Icon, Loader, Button, Link, Dropdown, CircularLoader } from 'UI' +import { forgotPassword, login } from 'App/routes' +import ReCAPTCHA from 'react-google-recaptcha' +import stl from './signup.css' +import cn from 'classnames' +import { signup, fetchTenants } from 'Duck/user'; +import { connect } from 'react-redux' + +const FORGOT_PASSWORD = forgotPassword() +const LOGIN_ROUTE = login() +const recaptchaRef = React.createRef() + +@connect( + state => ({ + tenants: state.getIn(['user', 'tenants']), + errors: state.getIn([ 'user', 'signupRequest', 'errors' ]), + loading: state.getIn([ 'user', 'signupRequest', 'loading' ]), + }), + { signup, fetchTenants }, +) +export default class SignupForm extends React.Component { + + state = { + tenantId: '', + fullname: '', + password: '', + email: '', + projectName: '', + }; + + componentDidMount() { + this.props.fetchTenants(); + } + + handleSubmit = (token) => { + const { tenantId, fullname, password, email, projectName, auth } = this.state; + this.props.signup({ tenantId, fullname, password, email, projectName, auth, 'g-recaptcha-response': token }) + } + + write = ({ target: { value, name } }) => this.setState({ [ name ]: value }) + writeOption = (e, { name, value }) => this.setState({ [ name ]: value }); + + onSubmit = (e) => { + e.preventDefault(); + if (window.ENV.CAPTCHA_ENABLED && recaptchaRef.current) { + recaptchaRef.current.execute(); + } else if (!window.ENV.CAPTCHA_ENABLED) { + this.handleSubmit(); + } + } + render() { + const { loading, errors, tenants } = this.props; + + return ( + <form onSubmit={ this.onSubmit }> + <div className="mb-8"> + <h2 className="text-center text-3xl mb-6">Get Started</h2> + <div className="text-center text-xl">Already having an account? <span className="link"><Link to={ LOGIN_ROUTE }>Sign In</Link></span></div> + </div> + <> + { window.ENV.CAPTCHA_ENABLED && ( + <ReCAPTCHA + ref={ recaptchaRef } + size="invisible" + sitekey={ window.ENV.CAPTCHA_SITE_KEY } + onChange={ token => this.handleSubmit(token) } + /> + )} + <div> + { tenants.length > 0 && ( + <div className="mb-6"> + <label>Existing Accounts</label> + <div className={ stl.inputWithIcon }> + <Dropdown + className="w-full" + placeholder="Select tenant" + selection + options={ tenants } + name="tenantId" + // value={ instance.currentPeriod } + onChange={ this.writeOption } + /> + </div> + </div> + )} + <div className="mb-6"> + <label>Email</label> + <div className={ stl.inputWithIcon }> + <input + autoFocus={true} + autoComplete="username" + type="email" + placeholder="E.g. email@yourcompany.com" + name="email" + onChange={ this.write } + className={ stl.email } + required="true" + /> + </div> + </div> + <div className="mb-6"> + <label className="mb-2">Create Password</label> + <div className={ stl.inputWithIcon }> + <input + type="password" + placeholder="Min 8 Characters" + minLength="8" + name="password" + onChange={ this.write } + className={ stl.password } + required="true" + /> + </div> + </div> + <div className="mb-6"> + <label>Your Name</label> + <div className={ stl.inputWithIcon }> + <input + type="text" + placeholder="E.g John Doe" + name="fullname" + onChange={ this.write } + className={ stl.email } + required="true" + /> + </div> + </div> + + <div className="mb-6"> + <label>Organization Name</label> + <div className={ stl.inputWithIcon }> + <input + type="text" + placeholder="E.g Uber" + name="organizationName" + onChange={ this.write } + className={ stl.email } + required="true" + /> + </div> + </div> + + <div className="mb-6"> + <div className="text-sm">By creating an account, you agree to our <a href="https://openreplay.com/terms.html" className="link">Terms of Service</a> and <a href="https://openreplay.com/privacy.html" className="link">Privacy Policy</a></div> + </div> + + </div> + </> + { errors && + <div className={ stl.errors }> + { errors.map(error => ( + <div className={stl.errorItem}> + <Icon name="info" color="red" size="20"/> + <span className="color-red ml-2">{ error }<br /></span> + </div> + )) } + </div> + } + <div className={ stl.formFooter }> + <Button type="submit" primary > + { loading ? + <CircularLoader loading={true} /> : + 'Signup' + } + </Button> + + {/* <div className={ cn(stl.links, 'text-lg') }> + <Link to={ LOGIN_ROUTE }>{'Back to Login'}</Link> + </div> */} + </div> + </form> + ) + } +} + +// export default connect(state => ({ +// errors: state.getIn([ 'user', 'signupRequest', 'errors' ]), +// loading: state.getIn([ 'user', 'signupRequest', 'loading' ]), +// }), { signup })(SignupForm) \ No newline at end of file diff --git a/frontend/app/components/Signup/SignupForm/index.js b/frontend/app/components/Signup/SignupForm/index.js new file mode 100644 index 000000000..de60c6e45 --- /dev/null +++ b/frontend/app/components/Signup/SignupForm/index.js @@ -0,0 +1 @@ +export { default } from './SignupForm' \ No newline at end of file diff --git a/frontend/app/components/Signup/SignupForm/signup.css b/frontend/app/components/Signup/SignupForm/signup.css new file mode 100644 index 000000000..c8d6a36e0 --- /dev/null +++ b/frontend/app/components/Signup/SignupForm/signup.css @@ -0,0 +1,143 @@ +@import "icons.css"; +.form { + /* position: absolute; */ + /* top: 50%; */ + /* margin-top: -300px; */ + /* width: 520px; */ + /* left: 50%; */ + /* margin-left: -260px; */ + + & form { + padding: 10px 0; + border: solid 2px $gray-light; + border-radius: 2px; + background-color: white; + } + & h2 { + text-align: center; + font-size: 20px; + color: #555555; + margin: 35px 0; + font-weight: 500; + } +} + +.formFooter { + text-align: center; + padding: 15px 0; +} + +.links { + display: flex; + align-items: center; + justify-content: center; + padding: 10px 0; + margin-top: 20px; + + & .divider { + width: 1px; + height: 12px; + background-color: $gray-medium; + margin: 0 5px; + } +} + +.logo { + background-image: svg-load('logo.svg'); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + height: 40px; + margin-bottom: 20px; +} + + +.email, .password { + display: block; + /* margin: 10px auto; */ + width: 100%; + height: 38px; + line-height: 45px; + border: $gray-light solid 1px; + border-radius: 3px; + font-size: 14px; + padding: 0 10px; + transition: all 0.2s; + + &::placeholder { + color: #AAA; + } + + &:focus { + border-color: $teal; + transition: all 0.2s; + } +} + +.errors { + border-radius: 5px; + width: 400px; + margin: auto; + /* border: 1px solid $red; */ + padding: 15px; + background-color: rgba(204, 0, 0, 0.1); + & .errorItem { + display: flex; + align-items: center; + justify-content: center; + } +} + +.submit { + display: block; + border-radius: 5px; + background: $teal; + width: 135px; + height: 45px; + margin: 20px auto; + color: $white; + font-size: 16px; + cursor: pointer; +} + +.inputWithIcon { + position: relative; + margin: 10px auto; + + /* & input { + padding-left: 45px; + } */ +} + +@define-mixin inputIcon $name { + position: absolute; + left: 15px; + top: calc(50% - 8px); + @mixin icon $name, $gray-medium, 15px; +} + +.inputIconUser { + @mixin inputIcon user-alt; +} + +.inputIconPassword { + @mixin inputIcon lock-alt; +} + + + +.left { + background: rgb(57,78,255); + background: linear-gradient(135deg, rgba(57,78,255,1) 0%, rgba(58,89,245,1) 21%, rgba(62,161,183,1) 69%, rgba(62,170,175,1) 100%); + position: relative; + & .bottom { + background-color: black; + } +} + +.formField { + margin-bottom: 20px; + > & label { + margin-bottom: 10px !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/Signup/signup.css b/frontend/app/components/Signup/signup.css new file mode 100644 index 000000000..a2020a8e8 --- /dev/null +++ b/frontend/app/components/Signup/signup.css @@ -0,0 +1,144 @@ +@import "icons.css"; +.form { + /* position: absolute; */ + /* top: 50%; */ + /* margin-top: -300px; */ + /* width: 520px; */ + /* left: 50%; */ + /* margin-left: -260px; */ + + & form { + padding: 10px 0; + border: solid 2px $gray-light; + border-radius: 2px; + background-color: white; + } + & h2 { + text-align: center; + font-size: 20px; + color: #555555; + margin: 35px 0; + font-weight: 500; + } +} + +.formFooter { + text-align: center; + padding: 15px 0; +} + +.links { + display: flex; + align-items: center; + justify-content: center; + padding: 10px 0; + margin-top: 20px; + + & .divider { + width: 1px; + height: 12px; + background-color: $gray-medium; + margin: 0 5px; + } +} + +.logo { + background-image: svg-load('logo.svg'); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + height: 40px; + margin-bottom: 20px; +} + + +.email, .password { + display: block; + margin: 10px auto; + width: 100%; + height: 45px; + line-height: 45px; + border: $gray-light solid 1px; + border-radius: 3px; + font-size: 14px; + padding: 0 10px; + transition: all 0.2s; + + &::placeholder { + color: #AAA; + } + + &:focus { + border-color: $teal; + transition: all 0.2s; + } +} + +.errors { + border-radius: 5px; + width: 400px; + margin: auto; + /* border: 1px solid $red; */ + padding: 15px; + background-color: rgba(204, 0, 0, 0.1); + & .errorItem { + display: flex; + align-items: center; + justify-content: center; + } +} + +.submit { + display: block; + border-radius: 5px; + background: $teal; + width: 135px; + height: 45px; + margin: 20px auto; + color: $white; + font-size: 16px; + cursor: pointer; +} + +.inputWithIcon { + position: relative; + width: 400px; + margin: 0 auto; + + & input { + padding-left: 45px; + } +} + +@define-mixin inputIcon $name { + position: absolute; + left: 15px; + top: calc(50% - 8px); + @mixin icon $name, $gray-medium, 15px; +} + +.inputIconUser { + @mixin inputIcon user-alt; +} + +.inputIconPassword { + @mixin inputIcon lock-alt; +} + + + +.left { + background: rgb(57,78,255); + background: linear-gradient(135deg, rgba(57,78,255,1) 0%, rgba(58,89,245,1) 21%, rgba(62,161,183,1) 69%, rgba(62,170,175,1) 100%); + position: relative; + & .bottom { + background-color: black; + } +} + +.formField { + margin-bottom: 20px; + > & label { + margin-bottom: 10px !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/UpdatePassword/UpdatePassword.js b/frontend/app/components/UpdatePassword/UpdatePassword.js new file mode 100644 index 000000000..57385b684 --- /dev/null +++ b/frontend/app/components/UpdatePassword/UpdatePassword.js @@ -0,0 +1,110 @@ +import { connect } from 'react-redux'; +import withPageTitle from 'HOCs/withPageTitle'; +import { Loader, Button, Message } from 'UI'; +import { updatePassword } from 'Duck/user'; +import styles from './updatePassword.css'; + +const ERROR_DOESNT_MATCH = "Passwords doesn't match"; +const MIN_LENGTH = 8; +const PASSWORD_POLICY = `Password should contain at least ${ MIN_LENGTH } symbols`; + +const checkDoesntMatch = (newPassword, newPasswordRepeat) => + newPasswordRepeat.length > 0 && newPasswordRepeat !== newPassword; + +@connect( + state => ({ + errors: state.getIn([ 'user', 'updatePasswordRequest', 'errors' ]), + loading: state.getIn([ 'user', 'updatePasswordRequest', 'loading' ]), + }), + { updatePassword }, +) +@withPageTitle("Password Change - OpenReplay") +export default class UpdatePassword extends React.Component { + state = { + oldPassword: '', + newPassword: '', + newPasswordRepeat: '', + }; + + handleSubmit = (event) => { + event.preventDefault(); + if (this.isSubmitDisabled()) return; + + const { oldPassword, newPassword } = this.state; + this.props.updatePassword({ oldPassword, newPassword }); + } + + write = ({ target: { value, name } }) => this.setState({ [ name ]: value }) + + isSubmitDisabled() { + const { oldPassword, newPassword, newPasswordRepeat } = this.state; + if (newPassword !== newPasswordRepeat || + newPassword.length < MIN_LENGTH || + oldPassword.length < MIN_LENGTH) return true; + return false; + } + + render() { + const { errors, loading } = this.props; + const { newPassword, newPasswordRepeat } = this.state; + const doesntMatch = checkDoesntMatch(newPassword, newPasswordRepeat); + + return ( + <div className={ styles.form }> + {/* <div className={ styles.betaTag }>{'BETA'}</div> */} + <div className={ styles.logo } /> + <form onSubmit={ this.handleSubmit }> + <h2>{ 'Password Change' }</h2> + <Loader loading={ loading }> + <div> + <div className={ styles.inputWithIcon }> + <i className={ styles.inputIconPassword } /> + <input + type="password" + placeholder="Old Password" + name="oldPassword" + onChange={ this.write } + className={ styles.password } + /> + </div> + <div className={ styles.inputWithIcon }> + <i className={ styles.inputIconPassword } /> + <input + type="password" + placeholder="New Password" + name="newPassword" + onChange={ this.write } + className={ styles.password } + /> + </div> + <div className={ styles.passwordPolicy } data-hidden={ newPassword.length > 7 }> + { PASSWORD_POLICY } + </div> + <div className={ styles.inputWithIcon }> + <i className={ styles.inputIconPassword } /> + <input + type="password" + placeholder="Repeat New Password" + name="newPasswordRepeat" + onChange={ this.write } + className={ styles.password } + /> + </div> + <Message error hidden={ !doesntMatch }> + { ERROR_DOESNT_MATCH } + </Message> + </div> + </Loader> + { errors && + <div className={ styles.errors }> + { errors.map(error => <span>{ error }<br /></span>) } + </div> + } + <div className={ styles.formFooter }> + <Button type="submit" primary >{ 'Update' }</Button> + </div> + </form> + </div> + ); + } +} diff --git a/frontend/app/components/UpdatePassword/updatePassword.css b/frontend/app/components/UpdatePassword/updatePassword.css new file mode 100644 index 000000000..8f79d3d79 --- /dev/null +++ b/frontend/app/components/UpdatePassword/updatePassword.css @@ -0,0 +1,127 @@ +@import "icons.css"; + +.form { + position: absolute; + top: 50%; + margin-top: -300px; + width: 520px; + left: 50%; + margin-left: -260px; + + & .passwordPolicy { + color: $gray-medium; + padding: 5px 0 10px; + font-size: 13px; + } + + & form { + padding: 10px 70px; + border: solid 2px $gray-light; + border-radius: 2px; + background-color: white; + } + & h2 { + text-align: center; + font-size: 20px; + color: #555555; + margin: 35px 0; + font-weight: 300; + } +} + +.formFooter { + text-align: center; + padding: 15px 0; +} + +.links { + display: flex; + align-items: center; + justify-content: center; + padding: 10px 0; + margin-top: 20px; + + & .divider { + width: 1px; + height: 12px; + background-color: $gray-medium; + margin: 0 5px; + } +} + +.logo { + background-image: svg-load('logo.svg'); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + height: 50px; + margin-bottom: 20px; +} + + +.email, .password { + display: block; + margin-top: 15px; + width: 100%; + height: 45px; + line-height: 45px; + border: $gray-light solid 1px; + border-radius: 3px; + font-size: 14px; + padding: 0 10px; + transition: all 0.2s; + + &::placeholder { + color: #AAA; + } + + &:focus { + border-color: $teal; + transition: all 0.2s; + } +} + +.errors { + border-radius: 5px; + width: 400px; + margin: auto; + border: 2px solid $red; + padding: 15px; + background-color: $white; +} + +.submit { + display: block; + border-radius: 5px; + background: $teal; + width: 135px; + height: 45px; + margin: 20px auto; + color: $white; + font-size: 16px; + cursor: pointer; +} + +.inputWithIcon { + position: relative; + + & input { + padding-left: 45px; + } +} + +@define-mixin inputIcon $name { + position: absolute; + left: 15px; + top: calc(50% - 8px); + @mixin icon $name, $gray-medium, 15px; +} + +.inputIconUser { + @mixin inputIcon user-alt; +} + +.inputIconPassword { + @mixin inputIcon lock-alt; +} + diff --git a/frontend/app/components/hocs/dnd.js b/frontend/app/components/hocs/dnd.js new file mode 100644 index 000000000..dd2a4b784 --- /dev/null +++ b/frontend/app/components/hocs/dnd.js @@ -0,0 +1,62 @@ +import HTML5Backend from 'react-dnd-html5-backend'; +import { findDOMNode } from 'react-dom'; +import { DragSource, DropTarget, DragDropContext } from 'react-dnd'; + +const cardSource = { + beginDrag(props) { + return { + id: props.key, + index: props.index, + prevIndex: props.index, + }; + }, +}; + +const cardTarget = { + // eslint-disable-next-line complexity + hover(props, monitor, component) { + const dragIndex = monitor.getItem().index; + const hoverIndex = props.index; + + if (dragIndex === hoverIndex) { + return; + } + /* eslint-disable react/no-find-dom-node */ + const hoverBoundingRect = findDOMNode(component).getBoundingClientRect(); + const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; + const clientOffset = monitor.getClientOffset(); + const hoverClientY = clientOffset.y - hoverBoundingRect.top; + + // Dragging downwards + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + + // Dragging upwards + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + + props.onDNDMove(dragIndex, hoverIndex); + monitor.getItem().index = hoverIndex; + }, + + drop(props, monitor) { + const dragIndex = monitor.getItem().prevIndex; + const dropIndex = props.index; + if (props.onDNDDrop) { + props.onDNDDrop(dragIndex, dropIndex); + } + }, +}; + +export const DNDContext = DragDropContext(HTML5Backend); + +export const DNDSource = name => DragSource(name, cardSource, (connect, monitor) => ({ + connectDragSource: connect.dragSource(), + isDragging: monitor.isDragging(), +})); + +export const DNDTarget = name => DropTarget(name, cardTarget, connect => ({ + connectDropTarget: connect.dropTarget(), +})); diff --git a/frontend/app/components/hocs/index.js b/frontend/app/components/hocs/index.js new file mode 100644 index 000000000..444ad0180 --- /dev/null +++ b/frontend/app/components/hocs/index.js @@ -0,0 +1,2 @@ +export { default as withRequest } from './withRequest'; +export { default as withToggle } from './withToggle'; \ No newline at end of file diff --git a/frontend/app/components/hocs/withCacheState.js b/frontend/app/components/hocs/withCacheState.js new file mode 100644 index 000000000..f921aaf7e --- /dev/null +++ b/frontend/app/components/hocs/withCacheState.js @@ -0,0 +1,70 @@ +export default (propNames) => BaseComponent => class extends React.PureComponent { + state = { + obj: this.getObjFromProps(), + changed: false, + } + + getObjFromProps() { + const obj = {} + propNames.forEach(propName => { + obj[ propName ] = this.props[ propName ] || null; + }); + return obj; + } + + componentDidUpdate(prevProps) { + if (propNames.some(propName => prevProps[ propName ] !== this.props[ propName ])){ + this.setState({ + obj: this.getObjFromProps(), + changed: false, + }) + } + } + + _onChange = ({ name, value, type, checked }) => { + if ([ 'radio', 'checkbox' ].includes(type)) { + this.edit(name, checked); + } else { + this.edit(name, value); + } + } + + onChange = ({ target }) => this._onChange(target) + + onChangeSemantic = (e, target) => this._onChange(target) + + edit = (name, value) => { + this.setState({ + obj: { + ...this.state.obj, + [ name ]: value, + }, + changed: true, + }); + } + + update = (name, updateFunction = a => a) => { + this.setState({ + obj: { + ...this.state.obj, + [ name ]: updateFunction(this.state.obj[ name ]), + }, + changed: true, + }); + } + + render() { + + return ( + <BaseComponent + { ...this.props } + onChange={ this.onChange } + onChangeSemantic={ this.onChangeSemantic } + edit={ this.edit } + update={ this.update } + changed={ this.state.changed } + { ...this.state.obj } + /> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/hocs/withEnumToggle.js b/frontend/app/components/hocs/withEnumToggle.js new file mode 100644 index 000000000..746cf7585 --- /dev/null +++ b/frontend/app/components/hocs/withEnumToggle.js @@ -0,0 +1,20 @@ +const withEnumToggle = (stateName = 'active', handlerName = 'setActive', initial) => BaseComponent => + class extends React.Component { + state = { + active: initial, + }; + + setActive = state => this.setState({ + active: state, + }) + + render() { + const newProps = { + [ handlerName ]: this.setActive, + [ stateName ]: this.state.active, + }; + return <BaseComponent { ...newProps } { ...this.props } />; + } + }; + +export default withEnumToggle; diff --git a/frontend/app/components/hocs/withLocationHandlers.js b/frontend/app/components/hocs/withLocationHandlers.js new file mode 100644 index 000000000..4fbf15360 --- /dev/null +++ b/frontend/app/components/hocs/withLocationHandlers.js @@ -0,0 +1,83 @@ +import { withRouter } from 'react-router-dom'; +import { + removeQueryParams, + addQueryParams, + setQueryParams, + parseQuery, +} from 'App/routes'; + +/* eslint-disable react/sort-comp */ + +const withLocationHandlers = propNames => BaseComponent => + @withRouter + class extends React.Component { + getQuery = names => parseQuery(this.props.location, names) + getParam = name => parseQuery(this.props.location)[ name ] + addQuery = (params) => { + const { location, history } = this.props; + history.push(addQueryParams(location, params)); + } + removeQuery = (names = [], replace=false) => { + const { location, history } = this.props; + + const namesArray = Array.isArray(names) ? names : [ names ]; + /* to avoid update stack overflow */ + const actualNames = Object.keys(this.getQuery(namesArray)); + + if (actualNames.length > 0) { + history[ replace ? 'replace' : 'push' ](removeQueryParams(location, actualNames)); + } + } + setQuery = (params, replace=false) => { + const { location, history } = this.props; + history[ replace ? 'replace' : 'push' ](setQueryParams(location, params)); + } + query = { + all: this.getQuery, + get: this.getParam, + add: this.addQuery, + remove: this.removeQuery, + set: this.setQuery, // TODO: use namespaces + } + + getHash = () => this.props.location.hash.substring(1) + setHash = (hash) => { + const { location, history } = this.props; + history.push({ ...location, hash: `#${ hash }` }); + } + removeHash = () => { + const { location, history } = this.props; + history.push({ ...location, hash: '' }); + } + hash = { + get: this.getHash, + set: this.setHash, + remove: this.removeHash, + } + + getQueryProps() { + if (Array.isArray(propNames)) return this.getQuery(propNames); + if (propNames !== null && typeof propNames === 'object') { + const values = Object.values(propNames); + const query = this.getQuery(values); + const queryProps = {}; + Object.keys(propNames).map((key) => { queryProps[ key ] = query[ propNames[ key ] ]; }); + return queryProps; + } + return {}; + } + + render() { + const queryProps = this.getQueryProps(); + return ( + <BaseComponent + query={ this.query } + hash={ this.hash } + { ...queryProps } + { ...this.props } + /> + ); + } + }; + +export default withLocationHandlers; diff --git a/frontend/app/components/hocs/withOverlay.js b/frontend/app/components/hocs/withOverlay.js new file mode 100644 index 000000000..fe348e861 --- /dev/null +++ b/frontend/app/components/hocs/withOverlay.js @@ -0,0 +1,87 @@ +import { findDOMNode } from 'react-dom'; + +let overlayedCount = 0; + +const ID = 'openreplay-overlay'; +const Z_BASE = 99990; + +const overlay = document.createElement("div"); +overlay.setAttribute('id', ID); + +// TODO: use className (class attribute) +overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; +overlay.style.position = 'fixed'; +overlay.style.left = 0; +overlay.style.right = 0; +overlay.style.bottom = 0; +overlay.style.top = 0; +overlay.style.zIndex = Z_BASE; + +const withOverlay = ( + overlayedName = 'overlayed', + clickHandlerName = 'onOverlayClick', + zIndex = 0, +) => BaseComponent => { + return class extends React.Component { + constructor(props) { + super(props); + this.baseRef = React.createRef(); + if (props[ overlayedName ]) { + overlayedCount++; + } + } + + componentDidMount() { + this.renderOverlay(); + this.setOverlayedStyles(); + } + + componentDidUpdate(prevProps) { + if (prevProps[ overlayedName ] !== this.props[ overlayedName ]) { + if (!this.props[ overlayedName ]) { + overlayedCount--; + } + if (this.props[ overlayedName ]) { + overlayedCount++; + } + this.renderOverlay(); + this.setOverlayedStyles(); + } + } + + clickHandler = () => { + const clickHandler = this.props[ clickHandlerName ]; + if (clickHandler) clickHandler(); + } + + renderOverlay() { + if (overlayedCount > 0) { + if (overlay.parentNode === null) { + document.body.appendChild(overlay); + } + if (this.props[ overlayedName ]) { + overlay.addEventListener('click', this.clickHandler); + } + } else if (overlay.parentNode !== null) { + overlay.parentNode.removeChild(overlay); + } + } + + setOverlayedStyles() { + const baseRoot = findDOMNode(this.baseRef.current); + const overlayed = this.props[ overlayedName ]; + const actualZIndex = Z_BASE + 1 + zIndex; + if (baseRoot) { + // TODO: care about styles rewriting case + baseRoot.style.position = 'relative'; + baseRoot.style.zIndex = overlayed ? actualZIndex : 'initial'; + } + } + + render() { + return <BaseComponent { ...this.props } ref={ this.baseRef } />; + } + }; +} + +export default withOverlay; diff --git a/frontend/app/components/hocs/withPageTitle.js b/frontend/app/components/hocs/withPageTitle.js new file mode 100644 index 000000000..965e3c139 --- /dev/null +++ b/frontend/app/components/hocs/withPageTitle.js @@ -0,0 +1,8 @@ +export default title => BaseComponent => class extends React.Component { + componentDidMount() { + document.title = title + } + render() { + return <BaseComponent { ...this.props }/> + } +} diff --git a/frontend/app/components/hocs/withRequest.js b/frontend/app/components/hocs/withRequest.js new file mode 100644 index 000000000..47d20e7fa --- /dev/null +++ b/frontend/app/components/hocs/withRequest.js @@ -0,0 +1,66 @@ +import APIClient from 'App/api_client'; + +export default ({ + initialData = null, + endpoint = '', + method = 'GET', + requestName = "request", + loadingName = "loading", + errorName = "requestError", + dataName = "data", + dataWrapper = data => data, + loadOnInitialize = false, + resetBeforeRequest = false, // Probably use handler? +}) => BaseComponent => class extends React.PureComponent { + constructor(props) { + super(props); + this.state = { + data: typeof initialData === 'function' ? initialData(props) : initialData, + loading: loadOnInitialize, + error: false, + }; + if (loadOnInitialize) { + this.request(); + } + } + + request = (params, edpParams) => { + this.setState({ + loading: true, + error: false, + data: resetBeforeRequest + ? (typeof initialData === 'function' ? initialData(this.props) : initialData) + : this.state.data, + }); + const edp = typeof endpoint === 'function' + ? endpoint(this.props, edpParams) + : endpoint; + return new APIClient()[ method.toLowerCase() ](edp, params) + .then(response => response.json()) + .then(({ errors, data }) => { + if (errors) { + return this.setError(); + } + this.setState({ + data: dataWrapper(data, this.state.data), + loading: false, + }); + }) + .catch(this.setError); + } + + setError = () => this.setState({ + loading: false, + error: true, + }) + + render() { + const ownProps = { + [ requestName ]: this.request, + [ loadingName ]: this.state.loading, + [ dataName ]: this.state.data, + [ errorName ]: this.state.error, + }; + return <BaseComponent { ...this.props } { ...ownProps } /> + } +} \ No newline at end of file diff --git a/frontend/app/components/hocs/withSiteIdRouter.js b/frontend/app/components/hocs/withSiteIdRouter.js new file mode 100644 index 000000000..1dd1a5f8b --- /dev/null +++ b/frontend/app/components/hocs/withSiteIdRouter.js @@ -0,0 +1,29 @@ +import { withRouter } from 'react-router-dom'; +import { connect } from 'react-redux'; +import { withSiteId } from 'App/routes'; +import { setSiteId } from 'Duck/user'; + +export default BaseComponent => +@withRouter +@connect((state, props) => ({ + urlSiteId: props.match.params.siteId, + siteId: state.getIn([ 'user', 'siteId' ]), +}), { + setSiteId, +}) +class extends React.PureComponent { + push = (location) => { + const { history, siteId } = this.props; + if (typeof location === 'string') { + history.push(withSiteId(location, siteId)); + } else if (typeof location === 'object'){ + history.push({ ...location, pathname: withSiteId(location.pathname, siteId) }); + } + } + + render() { + const { history, ...other } = this.props + + return <BaseComponent { ...other } history={ { ...history, push: this.push } } /> + } +} \ No newline at end of file diff --git a/frontend/app/components/hocs/withSiteIdUpdater.js b/frontend/app/components/hocs/withSiteIdUpdater.js new file mode 100644 index 000000000..67a7dbc60 --- /dev/null +++ b/frontend/app/components/hocs/withSiteIdUpdater.js @@ -0,0 +1,37 @@ +import { connect } from 'react-redux'; +import { withSiteId } from 'App/routes'; +import { setSiteId } from 'Duck/user'; + +export default BaseComponent => +@connect((state, props) => ({ + urlSiteId: props.match.params.siteId, + siteId: state.getIn([ 'user', 'siteId' ]), +}), { + setSiteId, +}) +class extends React.PureComponent { + state = { load: false } + constructor(props) { + super(props); + if (props.urlSiteId && props.urlSiteId !== props.siteId) { + props.setSiteId(props.urlSiteId); + } + } + componentDidUpdate(prevProps) { + const { urlSiteId, siteId, location: { pathname }, history } = this.props; + const shouldUrlUpdate = urlSiteId && urlSiteId !== siteId; + if (shouldUrlUpdate) { + const path = [ '', siteId ].concat(pathname.split('/').slice(2)).join('/'); + history.push(path); + } + const shouldBaseComponentReload = shouldUrlUpdate || siteId !== prevProps.siteId; + if (shouldBaseComponentReload) { + this.setState({ load: true }); + setTimeout(() => this.setState({ load: false }), 0); + } + } + + render() { + return this.state.load ? null : <BaseComponent { ...this.props } />; + } +} \ No newline at end of file diff --git a/frontend/app/components/hocs/withToggle.js b/frontend/app/components/hocs/withToggle.js new file mode 100644 index 000000000..441cd6078 --- /dev/null +++ b/frontend/app/components/hocs/withToggle.js @@ -0,0 +1,20 @@ +const withToggle = (stateName = 'open', handlerName = 'switchOpen', initial = false) => BaseComponent => + class extends React.Component { + state = { + toggle: initial, + }; + + onToggle = state => this.setState({ + toggle: typeof state === 'boolean' ? state : !this.state.toggle, + }) + + render() { + const newProps = { + [ handlerName ]: this.onToggle, + [ stateName ]: this.state.toggle, + }; + return <BaseComponent { ...newProps } { ...this.props } />; + } + }; + +export default withToggle; diff --git a/frontend/app/components/shared/AddWidgets.js b/frontend/app/components/shared/AddWidgets.js new file mode 100644 index 000000000..64aaef8ca --- /dev/null +++ b/frontend/app/components/shared/AddWidgets.js @@ -0,0 +1,90 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import withToggle from 'HOCs/withToggle'; +import { IconButton, SlideModal, NoContent } from 'UI'; +import { updateAppearance } from 'Duck/user'; +import { WIDGET_LIST } from 'Types/dashboard'; +import stl from './addWidgets.css'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; + +@connect(state => ({ + appearance: state.getIn([ 'user', 'account', 'appearance' ]), +}), { + updateAppearance, +}) +@withToggle() +export default class AddWidgets extends React.PureComponent { + makeAddHandler = widgetKey => () => { + const { appearance } = this.props; + const newAppearance = appearance.setIn([ 'dashboard', widgetKey ], true); + this.props.switchOpen(false); + this.props.updateAppearance(newAppearance) + } + + render() { + const { appearance, disabled } = this.props; + const avaliableWidgets = WIDGET_LIST.filter(({ key, type }) => !appearance.dashboard[ key ] && type === this.props.type ); + + return ( + <div className="relative"> + <OutsideClickDetectingDiv onClickOutside={() => this.props.switchOpen(false)}> + {this.props.open && + <div + className={cn(stl.menuWrapper, 'absolute border rounded z-10 bg-white w-auto')} + style={{ minWidth: '200px', top: '30px'}} + > + {avaliableWidgets.map(w => ( + <div + className={cn(stl.menuItem, 'whitespace-pre cursor-pointer')} + onClick={this.makeAddHandler(w.key)} + > + {w.name} + </div> + ))} + </div> + } + </OutsideClickDetectingDiv> + + <SlideModal + title="Add Widget" + size="middle" + isDisplayed={ false } + content={ this.props.open && + <NoContent + title="No Widgets Left" + size="small" + show={ avaliableWidgets.length === 0} + > + { avaliableWidgets.map(({ key, name, description, thumb }) => ( + <div className={ cn(stl.widgetCard) } key={ key } > + <div className="flex justify-between items-center flex-1"> + <div className="mr-10"> + <h4>{ name }</h4> + </div> + <IconButton + className="flex-shrink-0" + onClick={ this.makeAddHandler(key) } + circle + outline + icon="plus" + style={{ width: '24px', height: '24px'}} + /> + </div> + </div> + ))} + </NoContent> + } + onClose={ this.props.switchOpen } + /> + <IconButton + circle + size="small" + icon="plus" + outline + onClick={ this.props.switchOpen } + disabled={ disabled || avaliableWidgets.length === 0 } //TODO disabled after Custom fields filtering + /> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/ChromePluginMessage/ChromePluginMessage.js b/frontend/app/components/shared/ChromePluginMessage/ChromePluginMessage.js new file mode 100644 index 000000000..dddc10614 --- /dev/null +++ b/frontend/app/components/shared/ChromePluginMessage/ChromePluginMessage.js @@ -0,0 +1,18 @@ +import React from 'react' +import { Icon } from 'UI' +import { links } from 'App/constants' + +export default function ChromePluginMessage({ style }) { + return ( + <div + className="border rounded text-base mb-2 flex items-center p-2 bg-active-blue" + style={style} + > + <div className="flex items-center"> + <Icon name="info-circle" size="14" color="gray-darkest" /> + <div className="ml-2 mr-2 color-gray-darkest">Finding it difficult to add steps? Try our Chrome <a className="color-teal" target="_blank" href={links['chrome-plugin']}>Test Recorder</a></div> + <Icon name="external-link-alt" size="14" color="teal" /> + </div> + </div> + ) +} diff --git a/frontend/app/components/shared/ChromePluginMessage/index.js b/frontend/app/components/shared/ChromePluginMessage/index.js new file mode 100644 index 000000000..fcfa7298e --- /dev/null +++ b/frontend/app/components/shared/ChromePluginMessage/index.js @@ -0,0 +1 @@ +export { default } from './ChromePluginMessage'; \ No newline at end of file diff --git a/frontend/app/components/shared/Crisp/Crisp.js b/frontend/app/components/shared/Crisp/Crisp.js new file mode 100644 index 000000000..fc7b61bfb --- /dev/null +++ b/frontend/app/components/shared/Crisp/Crisp.js @@ -0,0 +1,31 @@ +import React from 'react'; + +class Crisp extends React.Component { + componentDidMount () { + if (!!window.$crisp) { + window.$crisp.push(['do', 'chat:show']); + } else { + window.$crisp = []; + window.CRISP_WEBSITE_ID = "adc74d6f-70c5-4947-bdf1-c359f3becfaf"; + + (function() { + var d = document; + var s = d.createElement("script"); + + s.src = "https://client.crisp.chat/l.js"; + s.async = 1; + d.getElementById("crisp-chat").appendChild(s); + })(); + } + } + + componentWillUnmount() { + window.$crisp.push(['do', 'chat:hide']); + } + + render () { + return null; + } +} + +export default Crisp; \ No newline at end of file diff --git a/frontend/app/components/shared/Crisp/index.js b/frontend/app/components/shared/Crisp/index.js new file mode 100644 index 000000000..caf3f17a9 --- /dev/null +++ b/frontend/app/components/shared/Crisp/index.js @@ -0,0 +1 @@ +export { default } from './Crisp' \ No newline at end of file diff --git a/frontend/app/components/shared/DateRange.js b/frontend/app/components/shared/DateRange.js new file mode 100644 index 000000000..83feae0d8 --- /dev/null +++ b/frontend/app/components/shared/DateRange.js @@ -0,0 +1,19 @@ +import { connect } from 'react-redux'; +import DateRangeDropdown from 'Shared/DateRangeDropdown'; + +function DateRange (props) { + const { startDate, endDate, rangeValue, className, onDateChange } = props; + + return ( + <DateRangeDropdown + button + onChange={ onDateChange } + rangeValue={ rangeValue } + startDate={ startDate } + endDate={ endDate } + className={ className } + /> + ); +} + +export default DateRange \ No newline at end of file diff --git a/frontend/app/components/shared/DateRangeDropdown/DateOptionLabel.js b/frontend/app/components/shared/DateRangeDropdown/DateOptionLabel.js new file mode 100644 index 000000000..3949a82ad --- /dev/null +++ b/frontend/app/components/shared/DateRangeDropdown/DateOptionLabel.js @@ -0,0 +1,9 @@ +import styles from './dateOptionLabel.css'; + +export default ({ range }) => ( + <div className={ styles.wrapper }> + <div>{ range && range.start.format('ll') }</div> + <div className={ styles.divider }>{ '-' }</div> + <div>{ range && range.end.format('ll') }</div> + </div> +); diff --git a/frontend/app/components/shared/DateRangeDropdown/DateRangeDropdown.js b/frontend/app/components/shared/DateRangeDropdown/DateRangeDropdown.js new file mode 100644 index 000000000..4165506d4 --- /dev/null +++ b/frontend/app/components/shared/DateRangeDropdown/DateRangeDropdown.js @@ -0,0 +1,122 @@ +import { Dropdown } from 'semantic-ui-react'; +import cn from 'classnames'; +import { + getDateRangeFromValue, + getDateRangeLabel, + dateRangeValues, + getDateRangeFromTs, + CUSTOM_RANGE, + DATE_RANGE_VALUES, +} from 'App/dateRange'; +import { Icon } from 'UI'; +import DateRangePopup from './DateRangePopup'; +import DateOptionLabel from './DateOptionLabel'; +import styles from './dateRangeDropdown.css'; + +const getDateRangeOptions = (customRange = getDateRangeFromValue(CUSTOM_RANGE)) => dateRangeValues.map(value => ({ + value, + text: <DateOptionLabel range={ value === CUSTOM_RANGE ? customRange : getDateRangeFromValue(value) } />, + content: getDateRangeLabel(value), +})); + +export default class DateRangeDropdown extends React.PureComponent { + state = { + showDateRangePopup: false, + range: null, + value: DATE_RANGE_VALUES.TODAY, + }; + + static getDerivedStateFromProps(props) { + const { rangeValue, startDate, endDate } = props; + if (rangeValue) { + const range = rangeValue === CUSTOM_RANGE + ? getDateRangeFromTs(startDate, endDate) + : getDateRangeFromValue(rangeValue); + return { + value: rangeValue, + range, + }; + } + return null; + } + + onCancelDateRange = () => this.setState({ showDateRangePopup: false }); + + onApplyDateRange = (range, value) => { + this.setState({ + showDateRangePopup: false, + range, + value, + }); + + this.props.onChange({ + startDate: range.start.unix() * 1000, + endDate: range.end.unix() * 1000, + rangeValue: value, + }); + } + + onItemClick = (event, { value }) => { + if (value !== CUSTOM_RANGE) { + const range = getDateRangeFromValue(value); + this.onApplyDateRange(range, value); + } else { + this.setState({ showDateRangePopup: true }); + } + } + + render() { + const { button = false, className, direction = 'right', customHidden=false, show30Minutes=false } = this.props; + const { showDateRangePopup, value, range } = this.state; + + let options = getDateRangeOptions(range); + + if (customHidden) { + options.pop(); + } + + if (!show30Minutes) { + options.shift() + } + + return ( + <div className={ cn(styles.dateRangeOptions, className) }> + <Dropdown + trigger={ button ? + <div className={ cn(styles.dropdownTrigger, 'flex items-center')}> + <span>{ value === CUSTOM_RANGE ? range.start.format('MMM Do YY, hh:mm A') + ' - ' + range.end.format('MMM Do YY, hh:mm A') : getDateRangeLabel(value) }</span> + <Icon name="chevron-down" color="gray-dark" size="14" className={styles.dropdownIcon} /> + </div> : null + } + selection={!button} + name="sessionDateRange" + direction={ direction } + className={ button ? "" : "customDropdown" } + // pointing="top left" + placeholder="Select..." + icon={ null } + > + <Dropdown.Menu> + { options.map(props => + <Dropdown.Item + {...props} + onClick={this.onItemClick} + active={props.value === value } + /> + ) } + </Dropdown.Menu> + </Dropdown> + { + showDateRangePopup && + <div className={ styles.dateRangePopup }> + <DateRangePopup + onApply={ this.onApplyDateRange } + onCancel={ this.onCancelDateRange } + selectedDateRange={ range } + /> + </div> + } + </div> + ); + } +} diff --git a/frontend/app/components/shared/DateRangeDropdown/DateRangePopup.js b/frontend/app/components/shared/DateRangeDropdown/DateRangePopup.js new file mode 100644 index 000000000..6bfe6a860 --- /dev/null +++ b/frontend/app/components/shared/DateRangeDropdown/DateRangePopup.js @@ -0,0 +1,116 @@ +import DateRangePicker from 'react-daterange-picker'; +import TimePicker from 'rc-time-picker'; +import { Button } from 'UI'; +import { getDateRangeFromValue, getDateRangeLabel, dateRangeValues, CUSTOM_RANGE, moment, DATE_RANGE_VALUES } from 'App/dateRange'; + +import styles from './dateRangePopup.css'; + +export default class DateRangePopup extends React.PureComponent { + state = { + range: this.props.selectedDateRange || moment.range(), + value: null, + } + + selectCustomRange = (range) => { + range.end.endOf('day'); + this.setState({ + range, + value: CUSTOM_RANGE, + }); + } + + setRangeTimeStart = value => { + if (value.isAfter(this.state.range.end)) { + return; + } + this.setState({ + range: moment.range( + value, + this.state.range.end, + ), + value: CUSTOM_RANGE, + }); + } + setRangeTimeEnd = value => { + if (value && value.isBefore(this.state.range.start)) { + return; + } + this.setState({ + range: moment.range( + this.state.range.start, + value, + ), + value: CUSTOM_RANGE, + }); + } + + selectValue = (value) => { + const range = getDateRangeFromValue(value); + this.setState({ range, value }); + } + + onApply = () => this.props.onApply(this.state.range, this.state.value) + + render() { + const { onCancel, onApply } = this.props; + const { range } = this.state; + + const rangeForDisplay = range.clone(); + rangeForDisplay.start.startOf('day'); + rangeForDisplay.end.startOf('day'); + + return ( + <div className={ styles.wrapper }> + <div className={ styles.body }> + <div className={ styles.preSelections }> + { dateRangeValues.filter(value => value !== CUSTOM_RANGE && value !== DATE_RANGE_VALUES.LAST_30_MINUTES).map(value => ( + <div + key={ value } + onClick={ () => this.selectValue(value) } + > + { getDateRangeLabel(value) } + </div> + )) + } + </div> + <DateRangePicker + name="dateRangePicker" + onSelect={ this.selectCustomRange } + numberOfCalendars={ 2 } + singleDateRange + selectionType="range" + maximumDate={ new Date() } + singleDateRange={true} + value={ rangeForDisplay } + /> + </div> + <div className="flex items-center justify-between py-2 px-3"> + <div> + <label>From: </label> + <span>{range.start.format("DD/MM")} </span> + <TimePicker + value={ range.start } + showSecond={ false } + allowEmpty={false} + onChange={ this.setRangeTimeStart } + className="mr-2 w-24" + /> + <label>To: </label> + <span>{range.end.format("DD/MM")} </span> + <TimePicker + value={ range.end } + showSecond={ false } + allowEmpty={false} + onChange={ this.setRangeTimeEnd } + className="w-24" + /> + </div> + <div> + <Button plain onClick={ onCancel } marginRight>{ 'Cancel' }</Button> + <Button primary onClick={ this.onApply } disabled={ !range }>{ 'Apply' }</Button> + </div> + </div> + </div> + ); + } +} diff --git a/frontend/app/components/shared/DateRangeDropdown/dateOptionLabel.css b/frontend/app/components/shared/DateRangeDropdown/dateOptionLabel.css new file mode 100644 index 000000000..9fed6cc5e --- /dev/null +++ b/frontend/app/components/shared/DateRangeDropdown/dateOptionLabel.css @@ -0,0 +1,9 @@ +.wrapper { + display: flex; + align-items: center; + font-size: 13px; + + & .divider { + margin: 0 2px; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/DateRangeDropdown/dateRangeDropdown.css b/frontend/app/components/shared/DateRangeDropdown/dateRangeDropdown.css new file mode 100644 index 000000000..868b973ce --- /dev/null +++ b/frontend/app/components/shared/DateRangeDropdown/dateRangeDropdown.css @@ -0,0 +1,65 @@ +.button { + padding: 0 8px; + border-radius: 3px; + color: $teal; + cursor: pointer; + display: flex !important; + align-items: center !important; + & span { + white-space: nowrap; + margin-right: 5px; + } +} + +.dropdownTrigger { + padding: 4px 6px; + &:hover { + background-color: $gray-light; + } +} +.dateRangeOptions { + position: relative; + + display: flex !important; + border-radius: 3px; + color: $gray-darkest; + font-weight: 500; + + + & .dateRangePopup { + top: 38px; + bottom: 0; + z-index: 999; + position: absolute; + background-color: white; + border: solid thin $gray-light; + border-radius: 3px; + min-height: fit-content; + min-width: 773px; + box-shadow: 0px 2px 10px 0 $gray-light; + } +} + +.dropdown { + display: flex !important; + padding: 4px 6px; + border-radius: 3px; + color: $gray-darkest; + font-weight: 500; + &:hover { + background-color: $gray-light; + } +} + +.dropdownTrigger { + padding: 4px 8px; + border-radius: 3px; + &:hover { + background-color: $gray-light; + } +} + +.dropdownIcon { + margin-top: 1px; + margin-left: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/shared/DateRangeDropdown/dateRangePopup.css b/frontend/app/components/shared/DateRangeDropdown/dateRangePopup.css new file mode 100644 index 000000000..a41fd1ef5 --- /dev/null +++ b/frontend/app/components/shared/DateRangeDropdown/dateRangePopup.css @@ -0,0 +1,22 @@ +.wrapper { + & .body { + display: flex; + border-bottom: solid thin $gray-light; + padding: 5px; + } +} + +.preSelections { + width: 130px; + background-color: white; + border-right: solid thin $gray-light; + & > div { + padding: 8px 10px; + width: 100%; + cursor: pointer; + &:hover { + background-color: $active-blue; + } + } +} + diff --git a/frontend/app/components/shared/DateRangeDropdown/index.js b/frontend/app/components/shared/DateRangeDropdown/index.js new file mode 100644 index 000000000..d6e6f2f87 --- /dev/null +++ b/frontend/app/components/shared/DateRangeDropdown/index.js @@ -0,0 +1 @@ +export { default } from './DateRangeDropdown'; diff --git a/frontend/app/components/shared/DocLink/DocLink.js b/frontend/app/components/shared/DocLink/DocLink.js new file mode 100644 index 000000000..052d648a1 --- /dev/null +++ b/frontend/app/components/shared/DocLink/DocLink.js @@ -0,0 +1,16 @@ +import React from 'react' +import { Button } from 'UI' + +export default function DocLink({ link, label }) { + const openLink = () => { + window.open(link, '_blank') + } + + return ( + <div> + <Button outline onClick={openLink}> + { label } + </Button> + </div> + ) +} diff --git a/frontend/app/components/shared/DocLink/index.js b/frontend/app/components/shared/DocLink/index.js new file mode 100644 index 000000000..c15bcd80e --- /dev/null +++ b/frontend/app/components/shared/DocLink/index.js @@ -0,0 +1 @@ +export { default } from './DocLink' \ No newline at end of file diff --git a/frontend/app/components/shared/EmailVerificationMessage/EmailVerificationMessage.js b/frontend/app/components/shared/EmailVerificationMessage/EmailVerificationMessage.js new file mode 100644 index 000000000..5e181e9ae --- /dev/null +++ b/frontend/app/components/shared/EmailVerificationMessage/EmailVerificationMessage.js @@ -0,0 +1,34 @@ +import React from 'react' +import { connect } from 'react-redux'; +import { Popup } from 'UI' +import { resendEmailVerification } from 'Duck/user' +import { toast } from 'react-toastify'; + +function EmailVerificationMessage(props) { + const { email } = props; + const send = () => { + props.resendEmailVerification(email).then(function() { + toast.success(`Verification email sent to ${email}`); + }) + } + return ( + <Popup + size="tiny" + inverted + position="top center" + trigger={ + <div + className="mt-3 px-3 rounded-2xl font-medium" + style={{ paddingTop: '3px', height: '28px', backgroundColor: 'rgba(255, 239, 239, 1)', border: 'solid thin rgba(221, 181, 181, 1)' }} + > + <span>Verify your registered email.</span> <a href="#" className="link" onClick={send}>Resend</a> + </div> + } + content={ + `We've sent a verification email to "${email}" please follow the instructions in it to use OpenReplay uninterruptedly.` + } + /> + ) +} + +export default connect(null, { resendEmailVerification })(EmailVerificationMessage) diff --git a/frontend/app/components/shared/EmailVerificationMessage/index.js b/frontend/app/components/shared/EmailVerificationMessage/index.js new file mode 100644 index 000000000..e9c8b2dfc --- /dev/null +++ b/frontend/app/components/shared/EmailVerificationMessage/index.js @@ -0,0 +1 @@ +export { default } from './EmailVerificationMessage' \ No newline at end of file diff --git a/frontend/app/components/shared/ErrorsBadge/ErrorsBadge.js b/frontend/app/components/shared/ErrorsBadge/ErrorsBadge.js new file mode 100644 index 000000000..073d252d8 --- /dev/null +++ b/frontend/app/components/shared/ErrorsBadge/ErrorsBadge.js @@ -0,0 +1,30 @@ +import React, { useEffect } from 'react' +import { fetchNewErrorsCount } from 'Duck/errors' +import { connect } from 'react-redux' +import stl from './errorsBadge.css' +import { + getDateRangeFromValue, + DATE_RANGE_VALUES, +} from 'App/dateRange'; + +const AUTOREFRESH_INTERVAL = 5 * 60 * 1000; +const weekRange = getDateRangeFromValue(DATE_RANGE_VALUES.LAST_7_DAYS); + +function ErrorsBadge({ errorsStats = {}, fetchNewErrorsCount }) { + useEffect(() => { + const params = { startTimestamp: weekRange.start.unix() * 1000, endTimestamp: weekRange.end.unix() * 1000 }; + fetchNewErrorsCount(params) + + setInterval(() => { + fetchNewErrorsCount(params); + }, AUTOREFRESH_INTERVAL); + }, []) + + return errorsStats.unresolvedAndUnviewed > 0 ? ( + <div>{<div className={stl.badge} /> }</div> + ) : '' +} + +export default connect(state => ({ + errorsStats: state.getIn([ 'errors', 'stats' ]), +}), { fetchNewErrorsCount })(ErrorsBadge) diff --git a/frontend/app/components/shared/ErrorsBadge/errorsBadge.css b/frontend/app/components/shared/ErrorsBadge/errorsBadge.css new file mode 100644 index 000000000..712c24c25 --- /dev/null +++ b/frontend/app/components/shared/ErrorsBadge/errorsBadge.css @@ -0,0 +1,9 @@ +.badge { + position: absolute; + height: 7px; + width: 7px; + border-radius: 50%; + background-color: $red; + right: 0px; + top: 12px; +} \ No newline at end of file diff --git a/frontend/app/components/shared/ErrorsBadge/index.js b/frontend/app/components/shared/ErrorsBadge/index.js new file mode 100644 index 000000000..31aad2730 --- /dev/null +++ b/frontend/app/components/shared/ErrorsBadge/index.js @@ -0,0 +1 @@ +export { default } from './ErrorsBadge'; \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/Attributes/ActiveLabel.js b/frontend/app/components/shared/EventFilter/Attributes/ActiveLabel.js new file mode 100644 index 000000000..eeed1ea4c --- /dev/null +++ b/frontend/app/components/shared/EventFilter/Attributes/ActiveLabel.js @@ -0,0 +1,10 @@ +import React from 'react'; +import stl from './activeLabel.css'; + +const ActiveLabel = ({ item, onRemove }) => { + return ( + <div className={ stl.wrapper } onClick={ () => onRemove(item) }>{ item.text }</div> + ); +}; + +export default ActiveLabel; diff --git a/frontend/app/components/shared/EventFilter/Attributes/AttributeItem.js b/frontend/app/components/shared/EventFilter/Attributes/AttributeItem.js new file mode 100644 index 000000000..51e16da7e --- /dev/null +++ b/frontend/app/components/shared/EventFilter/Attributes/AttributeItem.js @@ -0,0 +1,92 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { operatorOptions } from 'Types/filter'; +import { Icon } from 'UI'; +import { editAttribute, removeAttribute, applyFilter, fetchFilterOptions } from 'Duck/funnelFilters'; +import { debounce } from 'App/utils'; +import { KEYS } from 'Types/filter/customFilter'; +import stl from './attributeItem.css' +import AttributeValueField from './AttributeValueField'; +import OperatorDropdown from './OperatorDropdown'; +import CustomFilters from '../CustomFilters'; +import FilterSelectionButton from '../FilterSelectionButton'; + +const DEFAULT = null; + +@connect(state => ({ + loadingFilterOptions: state.getIn([ 'filters', 'fetchFilterOptions', 'loading' ]), + filterOptions: state.getIn([ 'filters', 'filterOptions' ]), +}), { + editAttribute, + removeAttribute, + applyFilter, + fetchFilterOptions +}) + +class AttributeItem extends React.PureComponent { + applyFilter = debounce(this.props.applyFilter, 1000) + fetchFilterOptionsDebounce = debounce(this.props.fetchFilterOptions, 500) + + onFilterChange = (e, { name, value }) => { + const { index } = this.props; + this.props.editAttribute(index, name, value); + this.applyFilter(); + } + + removeFilter = () => { + const { index } = this.props; + this.props.removeAttribute(index) + this.applyFilter(); + } + + handleSearchChange = (e, { searchQuery }) => { + const { filter } = this.props; + this.fetchFilterOptionsDebounce(filter, searchQuery); + } + + render() { + const { filter, options, index, loadingFilterOptions, filterOptions } = this.props; + const _operatorOptions = operatorOptions(filter); + + let filterLabel = filter.label; + if (filter.type === KEYS.METADATA) + filterLabel = filter.key; + + return ( + <div className={ stl.wrapper }> + <CustomFilters + index={ index } + filter={ filter } + buttonComponent={ <FilterSelectionButton label={ filterLabel } />} + showFilters={ true } + filterType="filter" + /> + { filter.type !== KEYS.DURATION && + <OperatorDropdown + options={ _operatorOptions } + onChange={ this.onFilterChange } + value={ filter.operator || DEFAULT } + /> + } + { + !filter.hasNoValue && + <AttributeValueField + filter={ filter } + options={ options } + onChange={ this.onFilterChange } + handleSearchChange={this.handleSearchChange} + loading={loadingFilterOptions} + /> + } + + <div className={ stl.actions }> + <button className={ stl.button } onClick={ this.removeFilter }> + <Icon name="close" size="16" /> + </button> + </div> + </div> + ); + } +} + +export default AttributeItem; diff --git a/frontend/app/components/shared/EventFilter/Attributes/AttributeValueField.js b/frontend/app/components/shared/EventFilter/Attributes/AttributeValueField.js new file mode 100644 index 000000000..176ae2c4a --- /dev/null +++ b/frontend/app/components/shared/EventFilter/Attributes/AttributeValueField.js @@ -0,0 +1,171 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import cn from 'classnames'; +import stl from './attributeItem.css' +import { Dropdown } from 'semantic-ui-react'; +import { LinkStyledInput, CircularLoader } from 'UI'; +import { KEYS } from 'Types/filter/customFilter'; +import Event, { TYPES } from 'Types/filter/event'; +import CustomFilter from 'Types/filter/customFilter'; +import { setActiveKey, addCustomFilter, removeCustomFilter, applyFilter } from 'Duck/funnelFilters'; +import DurationFilter from '../DurationFilter/DurationFilter'; +import AutoComplete from '../AutoComplete'; + +const DEFAULT = null; + +const getHeader = (type) => { + if (type === 'LOCATION') return 'Path'; + + return type; +} + +@connect(null, { + setActiveKey, + addCustomFilter, + removeCustomFilter, + applyFilter, +}) +class AttributeValueField extends React.PureComponent { + state = { + minDuration: this.props.filter.minDuration, + maxDuration: this.props.filter.maxDuration, + } + + onValueChange = (e, { name: key, value }) => { + this.props.addCustomFilter(key, value); + }; + + onDurationChange = (durationValues) => { + this.setState(durationValues); + } + + isAutoComplete = (type) => { + switch (type) { + case TYPES.METADATA: + case TYPES.CLICK: + case TYPES.CONSOLE: + case TYPES.GRAPHQL: + case TYPES.FETCH: + case TYPES.STATEACTION: + case TYPES.USERID: + case TYPES.USERANONYMOUSID: + case TYPES.REVID: + case TYPES.GRAPHQL: + case TYPES.CUSTOM: + case TYPES.LOCATION: + case TYPES.INPUT: + case 'metadata': + return true; + } + + return false; + } + + handleClose = (e) => { + const { filter, onChange } = this.props; + if (filter.key === KEYS.DURATION) { + const { maxDuration, minDuration, key } = filter; + if (maxDuration || minDuration) return; + if (maxDuration !== this.state.maxDuration || + minDuration !== this.state.minDuration) { + onChange(e, { name: 'value', value: [this.state.minDuration, this.state.maxDuration] }); + } + } + } + + renderField() { + const { filter, onChange } = this.props; + + if (filter.key === KEYS.DURATION) { + const { maxDuration, minDuration } = this.state; + return ( + <DurationFilter + onChange={ this.onDurationChange } + onEnterPress={ this.handleClose } + onBlur={this.handleClose} + minDuration={ minDuration } + maxDuration={ maxDuration } + /> + ); + } + + const { options = [], handleSearchChange, loading } = this.props; + return ( + <Dropdown + className={ cn(stl.filterDropdown) } + placeholder="Select" + name="value" + search + selection + value={ filter.value || DEFAULT } + options={ options } + multiple={options.length > 0 || options.size > 0} + onChange={ onChange } + onSearchChange={handleSearchChange} + icon={ null } + noResultsMessage={loading ? <div> + <CircularLoader loading={ loading } style={ { marginRight: '8px' } } /> + </div>: 'No results found.'} + /> + ) + } + + optionMapping = (values) => { + const { filter } = this.props; + if ([KEYS.USER_DEVICE, KEYS.USER_OS, KEYS.USER_BROWSER, KEYS.REFERRER].indexOf(filter.type) !== -1) + return values.map(item => ({ type: TYPES.METADATA, value: item })).map(CustomFilter); + else { + return values.map(Event); + } + } + + getParams = filter => { + const params = {}; + + if (filter.type === TYPES.METADATA) { + params.key = filter.key + } + + params.type = filter.type + if (filter.type === TYPES.ERROR && filter.source) { + params.source = filter.source + } + return params; + } + + render() { + const { filter, onChange } = this.props; + const _showAutoComplete = this.isAutoComplete(filter.type); + const _params = _showAutoComplete ? this.getParams(filter) : {}; + let _optionsEndpoint= '/events/search'; + + return ( + <React.Fragment> + { _showAutoComplete ? + <AutoComplete + name={ 'value' } + endpoint={ _optionsEndpoint } + value={ filter.value } + params={ _params } + optionMapping={this.optionMapping} + onSelect={ onChange } + headerText={ <h5 className={ stl.header }>{ getHeader(filter.type) }</h5> } + fullWidth={ (filter.type === TYPES.CONSOLE || filter.type === TYPES.LOCATION || filter.type === TYPES.CUSTOM) && filter.value } + /> + : this.renderField() + } + { filter.type === 'INPUT' && + <LinkStyledInput + displayLabel="Specify value" + placeholder="Specify value" + name="custom" + onChange={ onChange } + value={filter.custom} + /> + } + </React.Fragment> + ); + } +} + +export default AttributeValueField; diff --git a/frontend/app/components/shared/EventFilter/Attributes/Attributes.js b/frontend/app/components/shared/EventFilter/Attributes/Attributes.js new file mode 100644 index 000000000..61e80d380 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/Attributes/Attributes.js @@ -0,0 +1,72 @@ +import React from 'react'; +import { List } from 'immutable'; +import { connect } from 'react-redux'; +import { countries } from 'App/constants'; +import { KEYS } from 'Types/filter/customFilter'; +import { addAttribute } from 'Duck/funnelFilters'; +import AttributeItem from './AttributeItem'; +import ListHeader from '../ListHeader'; +import logger from 'App/logger'; + +const DEFAULT = null; +const DEFAULT_OPTION = { text: 'Any', value: DEFAULT }; +const toOptions = (values, mapper) => (values ? values + .map(({value}) => ({ + text: mapper ? mapper[ value ] : value, + value, + })) + .toJS() : [ DEFAULT_OPTION ]); + +const countryOptions = Object.keys(countries).map(i => ({ text: countries[i], value: i })); + +@connect(state => ({ + filters: state.getIn([ 'funnelFilters', 'appliedFilter', 'filters' ]), + filterValues: state.get('filterValues'), + filterOptions: state.getIn([ 'funnelFilters', 'filterOptions' ]), +}), { + addAttribute, +}) +class Attributes extends React.PureComponent { + getOptions = filter => { + const { filterValues, filterOptions } = this.props; + + if (filter.key === KEYS.USER_COUNTRY) { + logger.log('Filters: country') + return countryOptions; + } + + if (filter.key === KEYS.METADATA) { + logger.log('Filters: metadata ' + filter.key) + const options = filterValues.get(filter.key); + return options && options.size ? toOptions(options) : []; + } + + logger.log('Filters: general filters ' + filter.key) + const options = filterOptions.get(filter.key) + return options && options.size ? toOptions(options.filter(i => !!i)) : [] + } + render() { + const { filters } = this.props; + return ( + <> + { filters.size > 0 && + <div> + <div className="py-1"><ListHeader title="Filters" /></div> + { + filters.map((filter, index) => ( + <AttributeItem + key={index} + index={ index } + filter={ filter } + options={ this.getOptions(filter) } + /> + )) + } + </div> + } + </> + ); + } +} + +export default Attributes; diff --git a/frontend/app/components/shared/EventFilter/Attributes/OperatorDropdown.js b/frontend/app/components/shared/EventFilter/Attributes/OperatorDropdown.js new file mode 100644 index 000000000..4d2ba0d54 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/Attributes/OperatorDropdown.js @@ -0,0 +1,19 @@ +import React from 'react'; +import cn from 'classnames'; +import { Dropdown, Icon } from 'UI'; +import stl from './attributeItem.css' + +const OperatorDropdown = ({ options, value, onChange }) => { + return ( + <Dropdown + className={ cn(stl.operatorDropdown) } + options={ options } + name="operator" + value={ value } + onChange={ onChange } + icon={ <Icon className="ml-5" name="chevron-down" size="12" /> } + /> + ); +}; + +export default OperatorDropdown; diff --git a/frontend/app/components/shared/EventFilter/Attributes/activeLabel.css b/frontend/app/components/shared/EventFilter/Attributes/activeLabel.css new file mode 100644 index 000000000..283fed288 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/Attributes/activeLabel.css @@ -0,0 +1,9 @@ +.wrapper { + padding: 3px 8px; + background-color: $gray-lightest; + border-radius: 10px; + margin-right: 5px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05) inset; + font-size: 13px; + color: $gray-medium; +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/Attributes/attributeItem.css b/frontend/app/components/shared/EventFilter/Attributes/attributeItem.css new file mode 100644 index 000000000..3f4a229ed --- /dev/null +++ b/frontend/app/components/shared/EventFilter/Attributes/attributeItem.css @@ -0,0 +1,129 @@ +@import 'icons.css'; + +.wrapper { + display: flex; + align-items: center; + padding: 8px 15px; + background-color: white; + border-bottom: solid thin $gray-lightest; + &:last-child { + border-bottom: solid thin transparent; + } + + &:hover { + background-color: $active-blue; + & .actions { + opacity: 1; + transition: all 0.2s; + } + } + + & > div:not(:last-child) { + margin-right: 10px; + } + + & .label { + font-weight: 600; + min-width: 80px; + } + + & .filterDropdown { + padding: 0 5px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + font-weight: 400; + min-width: 280px !important; + max-width: 75% !important; + flex-wrap: wrap; + padding: 1.9px !important; + background-color: rgba(255, 255, 255, 0.8) !important; + padding-left: 5px !important; + + & a { + background-color: $gray-lightest !important; + box-shadow: none !important; + border-radius: 10px !important; + white-space: nowrap !important; + margin: 0 !important; + margin-right: 5px !important; + margin-bottom: 2px !important; + font-size: 13px !important; + font-weight: 400; + display: flex !important; + align-items: center !important; + padding: 3px 5px !important; + + & i::before { + display: none; + } + & i::after { + content: '' !important; + @mixin icon close, $gray-dark, 12px; + } + } + + & input { + padding: 6px !important; + margin: 0 !important; + color: $gray-medium !important; + } + + & .delete.icon { + padding: 0 !important; + display: none; + } + } +} + +.operatorDropdown { + font-weight: 400; + height: 28px; + min-width: 60px; + display: flex !important; + align-items: center; + justify-content: space-between; + padding: 0 8px !important; + font-size: 13px; + background-color: rgba(255, 255, 255, 0.8) !important; + border: solid thin rgba(34, 36, 38, 0.15) !important; + border-radius: 4px !important; + color: $gray-darkest !important; + font-size: 14px !important; + &.ui.basic.button { + box-shadow: 0 0 0 1px rgba(62, 170, 175,36,38,.35) inset, 0 0 0 0 rgba(62, 170, 175,.15) inset !important; + } +} + +.button { + width: 25px; + height: 25px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + margin-left: 10px; +} + +.actions { + margin-left: auto; + opacity: 0; + transition: all 0.4s; +} + +.inputValue { + height: 28px !important; + width: 180px; + color: $gray-medium !important; +} + +.header { + margin-bottom: 10px; + font-size: 13px; + color: #596764; + white-space: nowrap; + text-transform: uppercase; + font-weight: normal; + letter-spacing: 0.1em; + text-align: left; +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/Attributes/index.js b/frontend/app/components/shared/EventFilter/Attributes/index.js new file mode 100644 index 000000000..023362198 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/Attributes/index.js @@ -0,0 +1 @@ +export { default } from './Attributes'; diff --git a/frontend/app/components/shared/EventFilter/AutoComplete/AutoComplete.js b/frontend/app/components/shared/EventFilter/AutoComplete/AutoComplete.js new file mode 100644 index 000000000..922b7f650 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/AutoComplete/AutoComplete.js @@ -0,0 +1,169 @@ +import React from 'react'; +import APIClient from 'App/api_client'; +import cn from 'classnames'; +import { Input } from 'UI'; +import { debounce } from 'App/utils'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import stl from './autoComplete.css'; +import FilterItem from '../FilterItem'; + +const TYPE_TO_SEARCH_MSG = "Start typing to search..."; +const NO_RESULTS_MSG = "No results found."; +const SOME_ERROR_MSG = "Some error occured."; +const defaultValueToText = value => value; +const defaultOptionMapping = (values, valueToText) => values.map(value => ({ text: valueToText(value), value })); + +const hiddenStyle = { + whiteSpace: 'pre-wrap', + opacity: 0, position: 'fixed', left: '-3000px' +}; + +let pasted = false; +let changed = false; + +class AutoComplete extends React.PureComponent { + static defaultProps = { + method: 'GET', + params: {}, + } + + state = { + values: [], + noResultsMessage: TYPE_TO_SEARCH_MSG, + ddOpen: false, + query: this.props.value, + loading: false, + error: false + } + + componentWillReceiveProps(newProps) { + if (this.props.value !== newProps.value) { + this.setState({ query: newProps.value}); + } + } + + onClickOutside = () => { + this.setState({ ddOpen: false }); + } + + requestValues = (q) => { + const { params, endpoint, method } = this.props; + this.setState({ + loading: true, + error: false, + }); + return new APIClient()[ method.toLowerCase() ](endpoint, { ...params, q }) + .then(response => response.json()) + .then(({ errors, data }) => { + if (errors) { + this.setError(); + } else { + this.setState({ + ddOpen: true, + values: data, + loading: false, + noResultsMessage: NO_RESULTS_MSG, + }); + } + }) + .catch(this.setError); + } + + debouncedRequestValues = debounce(this.requestValues, 1000) + + setError = () => this.setState({ + loading: false, + error: true, + noResultsMessage: SOME_ERROR_MSG, + }) + + onInputChange = (e, { name, value }) => { + changed = true; + this.setState({ query: value, updated: true }) + const _value = value.trim(); + if (_value !== '' && _value !== ' ') { + this.debouncedRequestValues(_value) + } + } + + onBlur = ({ target: { value } }) => { + // to avoid sending unnecessary request on focus in/out without changing + if (!changed && !pasted) return; + + value = pasted ? this.hiddenInput.value : value; + const { onSelect, name } = this.props; + if (value !== this.props.value) { + const _value = value.trim(); + onSelect(null, {name, value: _value}); + } + + changed = false; + pasted = false; + } + + onItemClick = (e, item) => { + e.stopPropagation(); + e.preventDefault(); + const { onSelect, name } = this.props; + + this.setState({ query: item.value, ddOpen: false}) + onSelect(e, {name, ...item.toJS()}); + } + + render() { + const { ddOpen, query, loading, values } = this.state; + const { + // values = [], + optionMapping = defaultOptionMapping, + valueToText = defaultValueToText, + placeholder = 'Type to search...', + headerText = '', + fullWidth = false + } = this.props; + + const options = optionMapping(values, valueToText) + + return ( + <OutsideClickDetectingDiv + className={ cn("relative", { "flex-1" : fullWidth }) } + onClickOutside={this.onClickOutside} + > + <Input + className={ cn(stl.searchInput, { [ stl.fullWidth] : fullWidth }) } + onChange={ this.onInputChange } + onBlur={ this.onBlur } + onFocus={ () => this.setState({ddOpen: true})} + value={ query } + icon="search" + loading={ loading } + autoFocus={ true } + type="search" + placeholder={ placeholder } + onPaste={(e) => { + const text = e.clipboardData.getData('Text'); + this.hiddenInput.value = text; + pasted = true; // to use only the hidden input + } } + /> + <textarea style={hiddenStyle} ref={(ref) => this.hiddenInput = ref }></textarea> + { ddOpen && options.length > 0 && + <div className={ stl.menu }> + { headerText && headerText } + { + options.map(item => ( + <FilterItem + label={ item.value } + icon={ item.icon } + onClick={ (e) => this.onItemClick(e, item) } + /> + // <DropdownItem key={ item.value } value={ item.value } onSelect={ (e) => this.onItemClick(e, item) } /> + )) + } + </div> + } + </OutsideClickDetectingDiv> + ); + } +} + +export default AutoComplete; diff --git a/frontend/app/components/shared/EventFilter/AutoComplete/DropdownItem.js b/frontend/app/components/shared/EventFilter/AutoComplete/DropdownItem.js new file mode 100644 index 000000000..a8275a14d --- /dev/null +++ b/frontend/app/components/shared/EventFilter/AutoComplete/DropdownItem.js @@ -0,0 +1,10 @@ +import React from 'react'; +import stl from './dropdownItem.css'; + +const DropdownItem = ({ value, onSelect }) => { + return ( + <div className={ stl.wrapper } onClick={ onSelect } >{ value }</div> + ); +}; + +export default DropdownItem; diff --git a/frontend/app/components/shared/EventFilter/AutoComplete/autoComplete.css b/frontend/app/components/shared/EventFilter/AutoComplete/autoComplete.css new file mode 100644 index 000000000..c2c827bfe --- /dev/null +++ b/frontend/app/components/shared/EventFilter/AutoComplete/autoComplete.css @@ -0,0 +1,30 @@ +.menu { + border-radius: 0 0 3px 3px; + box-shadow: 0 2px 10px 0 $gray-light; + padding: 20px; + background-color: white; + max-height: 350px; + overflow-y: auto; + position: absolute; + top: 28px; + left: 0; + width: 500px; + z-index: 99; +} + +.searchInput { + & input { + font-size: 13px !important; + padding: 5px !important; + color: $gray-darkest !important; + font-size: 14px !important; + background-color: rgba(255, 255, 255, 0.8) !important; + } + height: 28px !important; + width: 280px; + color: $gray-darkest !important; +} + +.fullWidth { + width: 100% !important; +} diff --git a/frontend/app/components/shared/EventFilter/AutoComplete/dropdownItem.css b/frontend/app/components/shared/EventFilter/AutoComplete/dropdownItem.css new file mode 100644 index 000000000..f5646a470 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/AutoComplete/dropdownItem.css @@ -0,0 +1,11 @@ +.wrapper { + padding: 8px; + border-bottom: solid thin rgba(0, 0, 0, 0.05); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + &:hover { + background-color: $active-blue; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/AutoComplete/index.js b/frontend/app/components/shared/EventFilter/AutoComplete/index.js new file mode 100644 index 000000000..fa63241a4 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/AutoComplete/index.js @@ -0,0 +1 @@ +export { default } from './AutoComplete'; \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/CustomFilters/CustomFilters.js b/frontend/app/components/shared/EventFilter/CustomFilters/CustomFilters.js new file mode 100644 index 000000000..81e4ed0a6 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/CustomFilters/CustomFilters.js @@ -0,0 +1,26 @@ +import React, { useCallback, useState } from 'react'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import FilterModal from '../FilterModal'; + +export default React.memo(function CustomFilters({ + index, + buttonComponent, + filterType, +}) { + const [ displayed, setDisplayed ] = useState(false); + const close = useCallback(() => setDisplayed(false), []); + const toggle = useCallback(() => setDisplayed(d => !d), []); + + return ( + <OutsideClickDetectingDiv className="relative" onClickOutside={ close }> + <div role="button" onClick={ toggle }>{ buttonComponent || 'Add Step' }</div> + <FilterModal + index={ index } + close={ close } + displayed={ displayed } + filterType={ filterType } + /> + + </OutsideClickDetectingDiv> + ); +}) \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/CustomFilters/index.js b/frontend/app/components/shared/EventFilter/CustomFilters/index.js new file mode 100644 index 000000000..29dfa472a --- /dev/null +++ b/frontend/app/components/shared/EventFilter/CustomFilters/index.js @@ -0,0 +1 @@ +export { default } from './CustomFilters'; \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/DurationFilter/DurationFilter.js b/frontend/app/components/shared/EventFilter/DurationFilter/DurationFilter.js new file mode 100644 index 000000000..87e9a22b8 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/DurationFilter/DurationFilter.js @@ -0,0 +1,65 @@ +import { Input, Label } from 'semantic-ui-react'; +import styles from './durationFilter.css'; + +const fromMs = value => value ? `${ value / 1000 / 60 }` : '' +const toMs = value => value !== '' ? value * 1000 * 60 : null +export default class DurationFilter extends React.PureComponent { + state = { focused: false } + onChange = (e, { name, value }) => { + const { onChange } = this.props; + if (typeof onChange === 'function') { + onChange({ + [ name ]: toMs(value), + }); + } + } + + onKeyPress = e => { + const { onEnterPress } = this.props; + if (e.key === 'Enter' && typeof onEnterPress === 'function') { + onEnterPress(e); + } + } + + render() { + const { + minDuration, + maxDuration, + } = this.props; + + return ( + <div className={ styles.wrapper }> + <Input + labelPosition="left" + type="number" + placeholder="0 min" + name="minDuration" + value={ fromMs(minDuration) } + onChange={ this.onChange } + className="customInput" + onKeyPress={ this.onKeyPress } + onFocus={() => this.setState({ focused: true })} + onBlur={this.props.onBlur} + > + <Label basic className={ styles.label }>{ 'Min' }</Label> + <input min="1" /> + </Input> + <Input + labelPosition="left" + type="number" + placeholder="∞ min" + name="maxDuration" + value={ fromMs(maxDuration) } + onChange={ this.onChange } + className="customInput" + onKeyPress={ this.onKeyPress } + onFocus={() => this.setState({ focused: true })} + onBlur={this.props.onBlur} + > + <Label basic className={ styles.label }>{ 'Max' }</Label> + <input min="1" /> + </Input> + </div> + ); + } +} diff --git a/frontend/app/components/shared/EventFilter/DurationFilter/durationFilter.css b/frontend/app/components/shared/EventFilter/DurationFilter/durationFilter.css new file mode 100644 index 000000000..c7a272458 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/DurationFilter/durationFilter.css @@ -0,0 +1,24 @@ +.wrapper { + display: flex; + justify-content: space-between; + + & input { + max-width: 85px !important; + font-size: 13px !important; + font-weight: 400 !important; + color: $gray-medium !important; + } + + & > div { + &:first-child { + margin-right: 10px; + } + } +} + +.label { + font-size: 13px !important; + font-weight: 400 !important; + color: $gray-medium !important; +} + diff --git a/frontend/app/components/shared/EventFilter/EventDropdownItem.js b/frontend/app/components/shared/EventFilter/EventDropdownItem.js new file mode 100644 index 000000000..8d6d58f0a --- /dev/null +++ b/frontend/app/components/shared/EventFilter/EventDropdownItem.js @@ -0,0 +1,32 @@ +import { TYPES } from 'Types/filter/event'; +import cn from 'classnames'; +import { Icon } from 'UI'; +import cls from './eventDropdownItem.css'; + + +const getText = (event) => { + if (event.type === TYPES.METADATA) { + return `${ event.key }: ${ event.value }`; + } + if (event.target) { + return event.target.label || event.value; + } + return event.value; // both should be? +}; + +export default function EventDropdownItem({ event }) { + return ( + <div className={ cn("flex items-center", cls.eventDropdownItem) }> + <Icon name={ event.icon } size="14" marginRight="10" /> + <div + className={ cn(cls.values,{ + [ cls.inputType ]: event.type === TYPES.INPUT, + [ cls.clickType ]: event.type === TYPES.CLICK, + [ cls.consoleType ]: event.type === TYPES.CONSOLE, + })} + > + { getText(event) } + </div> + </div> + ); +} diff --git a/frontend/app/components/shared/EventFilter/EventEditor.js b/frontend/app/components/shared/EventFilter/EventEditor.js new file mode 100644 index 000000000..94ffb8692 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/EventEditor.js @@ -0,0 +1,106 @@ +import { connect } from 'react-redux'; +import { DNDSource, DNDTarget } from 'Components/hocs/dnd'; +import Event, { TYPES } from 'Types/filter/event'; +import { operatorOptions } from 'Types/filter'; +import { editEvent, removeEvent, clearEvents, applyFilter } from 'Duck/funnelFilters'; +import { Icon } from 'UI'; +import stl from './eventEditor.css'; +import { debounce } from 'App/utils'; +import AttributeValueField from './Attributes/AttributeValueField'; +import OperatorDropdown from './Attributes/OperatorDropdown'; +import CustomFilters from './CustomFilters'; +import FilterSelectionButton from './FilterSelectionButton'; + +const getPlaceholder = ({ type }) => { + if (type === TYPES.INPUT) return "E.g. First Name"; + if (type === TYPES.LOCATION) return "Specify URL / Path"; + if (type === TYPES.CONSOLE) return "Specify Error Message"; + if (type === TYPES.CUSTOM) return "Specify Custom Event Name"; + return ''; +}; + +const getLabel = ({ type }) => { + if (type === TYPES.INPUT) return "Specify Value"; + return getPlaceholder({ type }); +}; + +@DNDTarget('event') +@DNDSource('event') +@connect(state => ({ + isLastEvent: state.getIn([ 'filters', 'appliedFilter', 'events' ]).size === 1, + funnel: state.getIn(['funnels', 'instance']), +}), { editEvent, removeEvent, clearEvents, applyFilter }) +export default class EventEditor extends React.PureComponent { + applyFilter = debounce(this.props.applyFilter, 1000) + + onChange = (e, { name, value }) => { + const { index, funnel } = this.props; + this.props.editEvent(index, { [name]: value }, funnel.funnelId); + this.applyFilter(); + } + + onTargetChange = (e, {target}) => { + const { index, event } = this.props; + this.props.editEvent(index, {target}); + this.applyFilter(); + } + + onCheckboxChange = ({ target: { name, checked }}) => { + this.props.editEvent(this.props.index, name, checked); + } + + remove = () => { + const { funnel } = this.props; + this.props.removeEvent(this.props.index, funnel.funnelId); + this.applyFilter() + }; + + render() { + const { + event, + index, + isDragging, + connectDragSource, + connectDropTarget, + } = this.props; + + const _operatorOptions = operatorOptions(event); + + const dndBtn = connectDragSource( + <button className={ stl.button }><Icon name="drag" size="16" /></button> + ); + + return connectDropTarget( + <div className={ stl.wrapper } style={ isDragging ? { opacity: 0.5 } : null } > + <div className={ stl.leftSection }> + <div className={ stl.index }>{ index + 1 }</div> + + <CustomFilters + index={ index } + filter={ event } + buttonComponent={ <FilterSelectionButton label={ (event.source && event.source !== 'js_exception') ? event.source : event.label } />} + filterType="event" + /> + + <OperatorDropdown + options={ _operatorOptions } + onChange={ this.onChange } + value={ event.operator || DEFAULT } + /> + + <AttributeValueField + filter={ event } + onChange={ this.onChange } + onTargetChange={ this.onTargetChange } + /> + </div> + <div className={ stl.actions }> + { dndBtn } + <button className={ stl.button } onClick={ this.remove }> + <Icon name="close" size="16" /> + </button> + </div> + </div> + ); + } +} diff --git a/frontend/app/components/shared/EventFilter/EventFilter.js b/frontend/app/components/shared/EventFilter/EventFilter.js new file mode 100644 index 000000000..9a852398e --- /dev/null +++ b/frontend/app/components/shared/EventFilter/EventFilter.js @@ -0,0 +1,133 @@ +import { connect } from 'react-redux'; +import { DNDContext } from 'Components/hocs/dnd'; +import { + addEvent, applyFilter, moveEvent, clearEvents, + addCustomFilter, addAttribute, setSearchQuery, setActiveFlow, setFilterOption +} from 'Duck/funnelFilters'; +import { updateFunnelFilters, refresh as refreshFunnel } from 'Duck/funnels'; +import { fetchList as fetchEventList } from 'Duck/events'; +import { debounce } from 'App/utils'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import EventEditor from './EventEditor'; +import ListHeader from '../../BugFinder/ListHeader'; +import { IconButton } from 'UI'; +import stl from './eventFilter.css'; +import Attributes from './Attributes'; +import CustomFilters from './CustomFilters'; + +@connect(state => ({ + funnel: state.getIn([ 'funnels', 'instance' ]), + events: state.getIn([ 'funnelFilters', 'appliedFilter', 'events' ]), + filters: state.getIn([ 'funnelFilters', 'appliedFilter', 'filters' ]), + appliedFilter: state.getIn([ 'funnelFilters', 'appliedFilter' ]), + searchQuery: state.getIn([ 'funnelFilters', 'searchQuery' ]), + appliedFilterKeys: state.getIn([ 'funnelFilters', 'appliedFilter', 'filters' ]) + .map(({type}) => type).toJS(), + searchedEvents: state.getIn([ 'events', 'list' ]), + loading: state.getIn([ 'funnels', 'updateRequest', 'loading' ]) +}), { + applyFilter, + addEvent, + moveEvent, + fetchEventList, + clearEvents, + addCustomFilter, + addAttribute, + setSearchQuery, + setActiveFlow, + setFilterOption, + updateFunnelFilters, + refreshFunnel +}) +@DNDContext +export default class EventFilter extends React.PureComponent { + state = { search: '', showFilterModal: false, showPlacehoder: true, showSaveModal: false } + fetchEventList = debounce(this.props.fetchEventList, 500) + inputRef = React.createRef() + + onBlur = () => { + const { searchQuery } = this.props; + this.setState({ showPlacehoder: searchQuery === '' }); + } + + onFocus = () => { + this.setState({ showPlacehoder: false, showFilterModal: true }); + } + + onSearchChange = (e, { value }) => { + this.props.setSearchQuery(value) + if (value !== '') this.fetchEventList({ q: value }); + } + + closeModal = () => { + this.setState({ showPlacehoder: true, showFilterModal: false }) + } + + clearEvents = () => { + this.props.clearEvents(); + this.props.setActiveFlow(null) + } + + saveFunnel = () => { + const { funnel, filters, events } = this.props; + const _filters = { ...funnel.toData().filter }; + this.props.updateFunnelFilters(funnel.funnelId, { ..._filters, filters: filters.toJS(), events: events.toJS() }).then(function() { + this.props.refreshFunnel(funnel.funnelId); + }.bind(this)) + } + + render() { + const { + events, + loading, + onHide + } = this.props; + + return ( + <OutsideClickDetectingDiv className={ stl.wrapper } onClickOutside={ this.closeModal } > + <div className="bg-white rounded border-gray-light mt-2"> + { events.size > 0 && + <> + <div className="py-1"><ListHeader title="Events" /></div> + { events.map((event, i) => ( + <EventEditor + index={ i } + key={ event._key } + event={ event } + onDNDMove={ this.props.moveEvent } + /> + )) } + </> + } + <Attributes /> + <hr className="divider-light m-0 h-0"/> + + <div className="bg-white flex items-center py-2" style={{ borderBottomLeftRadius: '3px', borderBottomRightRadius: '3px'}}> + <div className="mr-auto ml-2"> + <CustomFilters + buttonComponent={ + <div> + <IconButton icon="plus" label="ADD STEP" primaryText /> + </div> + } + showFilters={ true } + /> + </div> + <div className="flex items-center"> + <div> + <IconButton plain label="HIDE" onClick={ onHide } /> + </div> + <IconButton + loading={loading} + primaryText + className="mr-2" + label="UPDATE FUNNEL" + onClick={this.saveFunnel} + /> + </div> + </div> + </div> + </OutsideClickDetectingDiv> + ); + } +} diff --git a/frontend/app/components/shared/EventFilter/FilterItem.js b/frontend/app/components/shared/EventFilter/FilterItem.js new file mode 100644 index 000000000..423ab47fb --- /dev/null +++ b/frontend/app/components/shared/EventFilter/FilterItem.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { Icon } from 'UI'; +import stl from './filterItem.css'; +import cn from 'classnames'; + +const FilterItem = ({ className = '', icon, label, onClick }) => { + return ( + <div className={ cn(stl.filterItem, className) } onClick={ onClick }> + <Icon name={ icon } size="16" marginRight="8" /> + <span className={ stl.label }>{ label }</span> + </div> + ); +}; + +export default FilterItem; diff --git a/frontend/app/components/shared/EventFilter/FilterModal/FilterModal.js b/frontend/app/components/shared/EventFilter/FilterModal/FilterModal.js new file mode 100644 index 000000000..f76c28065 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/FilterModal/FilterModal.js @@ -0,0 +1,138 @@ +import React from 'react'; +import cn from 'classnames'; +import { connect } from 'react-redux'; +import { getRE } from 'App/utils'; +import { defaultFilters } from 'Types/filter'; +import { KEYS } from 'Types/filter/customFilter'; +import { + applyFilter, setActiveKey, addEvent, + removeEvent, setFilterOptions, + addAttribute, removeAttribute +} from 'Duck/funnelFilters'; +import { debounce } from 'App/utils'; +import FilterItem from '../FilterItem'; +import logger from 'App/logger'; + +import stl from './filterModal.css'; + +const customFilterAutoCompleteKeys = ['METADATA', KEYS.CLICK, KEYS.USER_BROWSER, KEYS.USER_OS, KEYS.USER_DEVICE, KEYS.REFERRER] + +@connect(state => ({ + filter: state.getIn([ 'funnelFilters', 'appliedFilter' ]), + customFilters: state.getIn([ 'funnelFilters', 'customFilters' ]), + variables: state.getIn([ 'customFields', 'list' ]), + sources: state.getIn([ 'customFields', 'sources' ]), + funnel: state.getIn(['funnels', 'instance']), +}), { + applyFilter, + setActiveKey, + addEvent, + removeEvent, + addAttribute, + removeAttribute, + setFilterOptions +}) +export default class FilterModal extends React.PureComponent { + state = { query: '' } + applyFilter = debounce(this.props.applyFilter, 300); + + onFilterClick = (filter, apply) => { + const { funnel } = this.props; + const key = filter.key || filter.type; + this.addFilter(filter); + if (apply || filter.hasNoValue) { + this.applyFilter(null, funnel.funnelId); + } + } + + renderFilterItem(type, filter) { + return ( + <FilterItem + className="capitalize" + label={ filter.label || filter.key } + icon={ filter.icon } + onClick={ () => this.onFilterClick(filter) } + /> + ); + } + + addFilter = (filter) => { + const { index, filterType, filter: { filters } } = this.props; + this.props.close(); + + if (filter.isFilter || filter.type === 'METADATA') { + logger.log('Adding Filter', filter) + const _index = filterType === 'filter' ? index : undefined; // should add new one if coming from events + const _in = filters.findIndex(e => e.type === 'USERID'); + this.props.addAttribute(filter, _in >= 0 ? _in : _index); + } else { + logger.log('Adding Event', filter) + const _index = filterType === 'event' ? index : undefined; // should add new one if coming from fitlers + this.props.addEvent(filter, false, _index); + } + + if (filterType === 'event' && filter.isFilter) { // selected a filter from events + this.props.removeEvent(index); + } + + if (filterType === 'filter' && !filter.isFilter) { // selected an event from filters + this.props.removeAttribute(index); + } + }; + + renderList(type, list) { + const blocks = []; + for (let j = 0; j < list.length; j++) { + blocks.push( + <div key={`${ j }-block`} className="mr-5" > + { list[ j ] && this.renderFilterItem(type, list[ j ]) } + </div> + ); + } + return blocks; + } + + test = (value = '') => getRE(this.props.searchQuery, 'i').test(value); + + render() { + const { + displayed, + customFilters, + filter, + } = this.props; + const { query } = this.state; + const reg = getRE(query, 'i'); + const _appliedFilterKeys = filter.filters.map(({type}) => type).toJS(); + const filteredList = defaultFilters.map(cat => { + let _keys = []; + if (query.length === 0 && cat.type === 'custom') { // default show limited custom fields + _keys = cat.keys.slice(0, 9).filter(({key}) => reg.test(key)) + } else { + _keys = cat.keys.filter(({key}) => reg.test(key)); + } + return { + ...cat, + keys: _keys + .filter(({key, filterKey}) => !_appliedFilterKeys.includes(filterKey) && !customFilters.has(filterKey || key) && !filter.get(filterKey || key)) + } + }).filter(cat => cat.keys.length > 0); + + + return (!displayed ? null : + <div className={ stl.modal }> + <div className={ stl.filterListStatic }> + { + filteredList.map(category => ( + <div className={ cn(stl.filterGroup, 'mr-6 mb-6') } key={category.category}> + <h5 className={ stl.header }>{ category.category }</h5> + <div className={ stl.list }> + { this.renderList(category.type, category.keys) } + </div> + </div> + )) + } + </div> + </div> + ); + } +} diff --git a/frontend/app/components/shared/EventFilter/FilterModal/filterModal.css b/frontend/app/components/shared/EventFilter/FilterModal/filterModal.css new file mode 100644 index 000000000..7637bca00 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/FilterModal/filterModal.css @@ -0,0 +1,90 @@ +.modal { + position: absolute; + left: 0; + background-color: white; + min-width: 705px; + max-width: calc(100vw - 500px); + border-radius: 3px; + border: solid thin $gray-light; + box-shadow: 0 2px 10px 0 $gray-light; + z-index: 99; + padding: 20px; +} + +.hint { + color: $gray-light; + font-size: 12px; + padding-bottom: 5px; +} + +h5.title { + margin: 10px 0 3px; +} + +.filterListDynamic { + max-height: 350px; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 2px; + } + + &::-webkit-scrollbar-thumb { + background: transparent; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &:hover { + &::-webkit-scrollbar-track { + background: #f3f3f3; + } + &::-webkit-scrollbar-thumb { + background: $gray-medium; + } + } + + + & .header { + margin-bottom: 10px; + font-size: 13px; + color: #596764; + white-space: nowrap; + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.1em; + text-align: left; + } + + & .list { + margin-left: -8px; + } +} + +.filterListStatic { + display: flex; + flex-wrap: wrap; + flex-direction: column; + max-height: 33rem; + min-height: 20px; + color: $gray-medium; + + & .header { + margin-bottom: 10px; + font-size: 13px; + color: #596764; + white-space: nowrap; + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.1em; + text-align: left; + } + + & .list { + margin-left: -8px; + } + + & .filterGroup { + width: 205px; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/FilterModal/index.js b/frontend/app/components/shared/EventFilter/FilterModal/index.js new file mode 100644 index 000000000..0b69a5e64 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/FilterModal/index.js @@ -0,0 +1 @@ +export { default } from './FilterModal' \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/FilterSelectionButton.js b/frontend/app/components/shared/EventFilter/FilterSelectionButton.js new file mode 100644 index 000000000..7779f0ebd --- /dev/null +++ b/frontend/app/components/shared/EventFilter/FilterSelectionButton.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { Icon } from 'UI'; +import stl from './filterSelectionButton.css'; + +const FilterSelectionButton = ({ label }) => { + return ( + <div className={ stl.wrapper }> + <span className="capitalize">{ label } </span> + <Icon name="chevron-down"/> + </div> + ); +}; + +export default FilterSelectionButton; diff --git a/frontend/app/components/shared/EventFilter/ListHeader.js b/frontend/app/components/shared/EventFilter/ListHeader.js new file mode 100644 index 000000000..0c7801ce8 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/ListHeader.js @@ -0,0 +1,10 @@ +import React from 'react'; +import stl from './listHeader.css'; + +const ListHeader = ({ title }) => { + return ( + <div className={ stl.header }>{ title }</div> + ); +}; + +export default ListHeader; diff --git a/frontend/app/components/shared/EventFilter/RandomPlaceholder.js b/frontend/app/components/shared/EventFilter/RandomPlaceholder.js new file mode 100644 index 000000000..d2534bd63 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/RandomPlaceholder.js @@ -0,0 +1,99 @@ +import React from 'react'; +import { RandomElement } from 'UI'; +import stl from './randomPlaceholder.css'; +import Event, { TYPES } from 'Types/filter/event'; +import CustomFilter, { KEYS } from 'Types/filter/customFilter'; +import { defaultFilters } from 'Types/filter'; + +const getLabel = (type) => { + if (type === KEYS.MISSING_RESOURCE) return 'Missing Resource'; + if (type === KEYS.SLOW_SESSION) return 'Slow Sessions'; + if (type === KEYS.USER_COUNTRY) return 'Country'; + if (type === KEYS.USER_BROWSER) return 'Browser'; + if (type === KEYS.USERID) return 'User Id'; +} + +const getObject = (type, key) => { + switch(type) { + case TYPES.CLICK: + case TYPES.INPUT: + case TYPES.ERROR: + case TYPES.LOCATION: + return Event({ type, key: type }); + case KEYS.JOURNEY: + return [ + Event({ type: TYPES.LOCATION, key: TYPES.LOCATION }), + Event({ type: TYPES.LOCATION, key: TYPES.LOCATION }), + Event({ type: TYPES.CLICK, key: TYPES.CLICK }) + ] + + case KEYS.USER_BROWSER: + return CustomFilter({type, key: type, isFilter: true, label: getLabel(type), value: ['Chrome'] }); + case TYPES.METADATA: + return CustomFilter({type, key, isFilter: true, label: key }); + case TYPES.USERID: + return CustomFilter({type, key, isFilter: true, label: key }); + case KEYS.USER_COUNTRY: + return CustomFilter({type, key: type, isFilter: true, value: ['FR'], label: getLabel(type) }); + case KEYS.SLOW_SESSION: + case KEYS.MISSING_RESOURCE: + return CustomFilter({type, key: type, hasNoValue: true, isFilter: true, label: getLabel(type) }); + } +} + +const getList = (onClick, appliedFilterKeys) => { + let list = [ + { + key: KEYS.CLICK, + element: <div className={ stl.placeholder }>Find sessions with <span onClick={(e) => onClick(e, getObject(TYPES.CLICK))}>Click</span></div> + }, + { + key: KEYS.INPUT, + element: <div className={ stl.placeholder }>Find sessions with <span onClick={(e) => onClick(e, getObject(TYPES.INPUT))}>Input</span></div> + }, + { + key: KEYS.ERROR, + element: <div className={ stl.placeholder }>Find sessions with <span onClick={(e) => onClick(e, getObject(TYPES.ERROR))}>Errors</span></div> + }, + { + key: KEYS.LOCATION, + element: <div className={ stl.placeholder }>Find sessions with <span onClick={(e) => onClick(e, getObject(TYPES.LOCATION))}>URL</span></div> + }, + { + key: TYPES.USERID, + element: <div className={ stl.placeholder }>Find sessions with <span onClick={(e) => onClick(e, getObject(TYPES.USERID))}>User ID</span></div> + }, + + // { + // key: KEYS.MISSING_RESOURCE, + // element: <div className={ stl.placeholder }>Find sessions with <span onClick={(e) => onClick(e, getObject(KEYS.MISSING_RESOURCE))}>Missing Images</span></div> + // }, + // { + // key: KEYS.SLOW_SESSION, + // element: <div className={ stl.placeholder }>Find <span onClick={(e) => onClick(e, getObject(KEYS.SLOW_SESSION))}>Slow</span> sessions</div> + // }, + + { + key: KEYS.JOURNEY, + element: <div className={ stl.placeholder }>Find sessions in a <span onClick={(e) => onClick(e, getObject(KEYS.JOURNEY))}>Journey</span></div> + }, + { + key: KEYS.USER_COUNTRY, + element: <div className={ stl.placeholder }>Find sessions from <span onClick={(e) => onClick(e, getObject(KEYS.USER_COUNTRY))}>France</span></div> + }, + { + key: KEYS.USER_BROWSER, + element: <div className={ stl.placeholder }>Find sessions on <span onClick={(e) => onClick(e, getObject(KEYS.USER_BROWSER))}>Chrome</span></div> + }, + ] + + return list.filter(({key}) => !appliedFilterKeys.includes(key)) +} + +const RandomPlaceholder = ({ onClick, appliedFilterKeys }) => { + return ( + <RandomElement list={ getList(onClick, appliedFilterKeys) } /> + ); +}; + +export default RandomPlaceholder; diff --git a/frontend/app/components/shared/EventFilter/TypeBadge.js b/frontend/app/components/shared/EventFilter/TypeBadge.js new file mode 100644 index 000000000..810c93da7 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/TypeBadge.js @@ -0,0 +1,45 @@ +import cn from 'classnames'; +import { TYPES } from 'Types/filter/event'; +import { SENTRY, DATADOC } from 'Types/session/stackEvent'; +import { LEVEL } from 'Types/session/log'; // TODO: no types mess +import { Icon } from 'UI'; + +import styles from './typeBadge.css'; + +function getText(type, source) { + if (type === TYPES.CLICK) return 'Click'; + if (type === TYPES.LOCATION) return 'URL'; + if (type === TYPES.INPUT) return 'Input'; + if (type === TYPES.CONSOLE) return 'Console'; + if (type === TYPES.GRAPHQL) return 'GraphQL'; + if (type === TYPES.ERROR) return 'Error'; + if (type === TYPES.STATEACTION) return 'Store Action'; + if (type === TYPES.FETCH) return 'Fetch'; + if (type === TYPES.REVID) return 'Rev ID'; + if (type === TYPES.METADATA) return 'Metadata'; + if (type === TYPES.CUSTOM) { + if (!source) return 'Custom'; + return ( + <React.Fragment > + <Icon name={ `integrations/${ source }` } size="12" inline className={ cn(styles.icon, "mr-5") } /> + { 'Custom' } + </React.Fragment> + ); + } + return '?'; +} + +const TypeBadge = ({ event: { type, level, source } }) => ( + <div + className={ cn(styles.badge, { + [ styles.red ]: level === LEVEL.ERROR || level === LEVEL.EXCEPTION, + [ styles.yellow ]: level === LEVEL.WARN, + }) } + > + { getText(type, source) } + </div> +); + +TypeBadge.displayName = 'TypeBadge'; + +export default TypeBadge; diff --git a/frontend/app/components/shared/EventFilter/eventDropdownItem.css b/frontend/app/components/shared/EventFilter/eventDropdownItem.css new file mode 100644 index 000000000..a6f7dc4d1 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/eventDropdownItem.css @@ -0,0 +1,26 @@ +.eventDropdownItem { + padding: 8px 0; + padding-left: 18px; + border-bottom: solid thin $gray-light; + + &:last-child { + border-bottom: solid thin transparent; + } + + & .values { + max-width: 400px; + overflow: hidden; + text-overflow: ellipsis; + + &.inputType, + &.clickType { + color: $gray-darkest !important; + font-size: 14px; + } + + &.consoleType { + font-family: 'menlo', 'monaco', 'consolas', monospace; + font-size: 12px; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/eventEditor.css b/frontend/app/components/shared/EventFilter/eventEditor.css new file mode 100644 index 000000000..cd004795b --- /dev/null +++ b/frontend/app/components/shared/EventFilter/eventEditor.css @@ -0,0 +1,70 @@ +@import 'mixins.css'; +@import 'icons.css'; + +.wrapper { + width: 100%; + display: flex; + padding: 8px 15px; + background-color: white; + border-bottom: solid thin $gray-lightest; + transition: all 0.4s; + + &:last-child { + border-bottom: solid thin transparent; + } + + &:hover { + background-color: $active-blue; + transition: all 0.2s; + + & .actions { + opacity: 1; + transition: all 0.2s; + } + } + + & .leftSection, + & .actions { + display: flex; + align-items: center; + } + + & .leftSection { + flex: 1; + & > div { + margin-right: 10px; + flex-shrink: 0; + } + } +} + +.index { + background: $white; + width: 24px; + height: 24px; + border-radius: 12px; + margin-right: 10px; + color: $gray-medium; + font-weight: 300; + font-size: 12px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset; +} + +.button { + width: 25px; + height: 25px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + margin-left: 10px; +} + +.actions { + opacity: 0; + transition: all 0.4s; +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/eventFilter.css b/frontend/app/components/shared/EventFilter/eventFilter.css new file mode 100644 index 000000000..22b7485cd --- /dev/null +++ b/frontend/app/components/shared/EventFilter/eventFilter.css @@ -0,0 +1,59 @@ +.searchField { + box-shadow: none !important; + & input { + box-shadow: none !important; + border-radius: 3 !important; + border: solid thin $gray-light !important; + height: 46px !important; + font-size: 16px; + } +} + +.wrapper { + box-shadow: none !important; + position: relative; + + & .clearStepsButton { + position: absolute; + bottom: 10px; + right: 10x; + } +} + +.randomElement { + position: absolute; + left: 0; + top: 0; + right: 0; + z-index: 8; + padding: 15px; + padding-left: 40px; +} + +.dropdownMenu { + max-width: 100%; + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; + + &[data-hidden=true] { + display: none !important; + } +} + + +.header { + padding: 5px 10px; + letter-spacing: 1.5px; + background-color: $gray-lightest; + color: $gray-medium; + font-size: 12px; + text-transform: uppercase; +} + +.dateRange { + color: red; + z-index: 8; + position: absolute; + right: 9px; + top: 9px; +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/filterItem.css b/frontend/app/components/shared/EventFilter/filterItem.css new file mode 100644 index 000000000..2840f2119 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/filterItem.css @@ -0,0 +1,20 @@ +.filterItem { + display: flex; + align-items: center; + padding: 8px; + cursor: pointer; + border-radius: 3px; + transition: all 0.4s; + margin-bottom: 5px; + max-width: 100%; + & .label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + &:hover { + background-color: $gray-lightest; + transition: all 0.2s; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/filterModal.css b/frontend/app/components/shared/EventFilter/filterModal.css new file mode 100644 index 000000000..2c1ab00f0 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/filterModal.css @@ -0,0 +1,90 @@ +.modal { + position: absolute; + left: 0; + background-color: white; + min-width: 705px; + max-width: calc(100vw - 500px); + border-radius: 3px; + border: solid thin $gray-light; + box-shadow: 0 2px 10px 0 $gray-light; + z-index: 99; + padding: 20px; +} + +.hint { + color: $gray-light; + font-size: 12px; + padding-bottom: 5px; +} + +h5.title { + margin: 10px 0 3px; +} + +.filterListDynamic { + max-height: 350px; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 2px; + } + + &::-webkit-scrollbar-thumb { + background: transparent; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &:hover { + &::-webkit-scrollbar-track { + background: #f3f3f3; + } + &::-webkit-scrollbar-thumb { + background: $gray-medium; + } + } + + + & .header { + margin-bottom: 10px; + font-size: 13px; + color: #596764; + white-space: nowrap; + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.1em; + text-align: left; + } + + & .list { + margin-left: -8px; + } +} + +.filterListStatic { + display: flex; + flex-wrap: wrap; + flex-direction: column; + max-height: 30rem; + min-height: 20px; + color: $gray-medium; + + & .header { + margin-bottom: 10px; + font-size: 13px; + color: #596764; + white-space: nowrap; + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.1em; + text-align: left; + } + + & .list { + margin-left: -8px; + } + + & .filterGroup { + width: 205px; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/filterSelectionButton.css b/frontend/app/components/shared/EventFilter/filterSelectionButton.css new file mode 100644 index 000000000..2412cbca4 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/filterSelectionButton.css @@ -0,0 +1,23 @@ +.wrapper { + display: flex; + align-items: center; + justify-content: space-between; + height: 28px; + border: solid thin rgba(34, 36, 38, 0.15) !important; + border-radius: 4px; + padding: 0 10px; + width: 150px; + color: $gray-darkest; + cursor: pointer; + background-color: rgba(255, 255, 255, 0.8) !important; + &:hover { + background-color: white; + } + & span { + margin-right: 5px; + max-width: 140px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/index.js b/frontend/app/components/shared/EventFilter/index.js new file mode 100644 index 000000000..8298d268d --- /dev/null +++ b/frontend/app/components/shared/EventFilter/index.js @@ -0,0 +1 @@ +export { default } from './EventFilter'; diff --git a/frontend/app/components/shared/EventFilter/listHeader.css b/frontend/app/components/shared/EventFilter/listHeader.css new file mode 100644 index 000000000..35b3b6001 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/listHeader.css @@ -0,0 +1,7 @@ +.header { + padding: 3px 10px; + letter-spacing: 1.5px; + color: $gray-medium; + font-size: 12px; + text-transform: uppercase; +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/randomPlaceholder.css b/frontend/app/components/shared/EventFilter/randomPlaceholder.css new file mode 100644 index 000000000..c0958d2aa --- /dev/null +++ b/frontend/app/components/shared/EventFilter/randomPlaceholder.css @@ -0,0 +1,17 @@ +.placeholder { + color: $gray-medium; + font-weight: 300; + font-size: 16px; + user-select: none; + + & span { + font-weight: 400; + color: $teal; + cursor: pointer; + border-bottom: dashed thin $teal; + + &:hover { + color: $teal-dark; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/EventFilter/typeBadge.css b/frontend/app/components/shared/EventFilter/typeBadge.css new file mode 100644 index 000000000..2ff7005e4 --- /dev/null +++ b/frontend/app/components/shared/EventFilter/typeBadge.css @@ -0,0 +1,23 @@ +.badge { + font-size: 11px; + border-radius: 3px; + background-color: white; + border: solid thin $gray-light; + padding: 2px 0; + text-align: center; + width: 66px; + margin-right: 10px; + user-select: none; + + &.red { + background-color: rgba(204, 0, 0, 0.05); + } + + &.yellow { + background-color: rgba(245, 166, 35, 0.05); + } +} + +.icon { + vertical-align: text-top; +} \ No newline at end of file diff --git a/frontend/app/components/shared/FilterDropdown/FilterDropdown.js b/frontend/app/components/shared/FilterDropdown/FilterDropdown.js new file mode 100644 index 000000000..8bf6e5faa --- /dev/null +++ b/frontend/app/components/shared/FilterDropdown/FilterDropdown.js @@ -0,0 +1,143 @@ +import React, { useState } from 'react' +import { Icon } from 'UI' +import { withRequest } from 'HOCs'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import WidgetAutoComplete from 'Shared/WidgetAutoComplete'; +import { getRE } from 'App/utils'; +import cn from 'classnames'; +import stl from './filterDropdown.css'; +import { countries } from 'App/constants'; +import { regionLabels } from 'Types/integrations/cloudwatchConfig'; + +const PLATFORM = 'platform'; +const COUNTRY = 'country'; +const LOCATION = 'location'; + +const platformOptions = [ + { 'key': PLATFORM, text: 'Desktop', value: 1}, + { 'key': PLATFORM, text: 'Tablet', value: 2 }, + { 'key': PLATFORM, text: 'Tablet Landscape', value: 3 }, + { 'key': PLATFORM, text: 'Mobile', value: 4 }, + { 'key': PLATFORM, text: 'Mobile Landscape', value: 5 } +]; + +const countryOptions = Object.keys(countries).map(c => ({key: COUNTRY, text: countries[c], value: c})); +const locationOptions = Object.keys(regionLabels).map(k => ({ key: LOCATION, text: regionLabels[k], value: k})); + +const _filterKeys = [ + { key: 'userId', name: 'User ID', icon: 'user-alt', placeholder: 'Search for User ID' }, + { key: 'userAnonymousId', name: 'User Anonymous ID', icon: 'filters/userid', placeholder: 'Search for User Anonymous ID' }, + { key: 'revId', name: 'Rev ID', icon: 'filters/border-outer', placeholder: 'Search for Rev ID' }, + { key: COUNTRY, name: 'Country', icon: 'map-marker-alt', placeholder: 'Search for Country' }, + { key: 'device', name: 'Device', icon: 'device', placeholder: 'Search for Device' }, + { key: 'os', name: 'OS', icon: 'os', placeholder: 'Search for OS' }, + { key: 'browser', name: 'Browser', icon: 'window', placeholder: 'Search for Browser' }, + { key: 'location', name: 'Location', icon: 'window', placeholder: 'Search for Location' }, + { key: PLATFORM, name: 'Platform', icon: 'desktop', placeholder: 'Search for Platform' }, +] + +const FilterDropdown = props => { + const { filterKeyMaps = [], metaOptions, allowedFilters } = props; + let filterKeys = metaOptions.concat(_filterKeys) + if (allowedFilters && allowedFilters.length > 0) { + filterKeys = filterKeys.filter(f => allowedFilters.includes(f.key)) + } + const [showDropdown, setShowDropdown] = useState(false) + const [filterKey, setFilterKey] = useState(false) + const [localOptions, setLocalOptions] = useState([]); + const activeFilter = filterKeys.find(f => f.key === filterKey); + const shouldFetchOptions = filterKey && filterKey !== PLATFORM && filterKey !== COUNTRY && filterKey !== LOCATION; + + const onSelect = (params) => { + props.onSelect(params) + setFilterKey(undefined); + setShowDropdown(false); + } + + const onFilterKeySelect = key => { + setFilterKey(key); + setShowDropdown(false); + if (!shouldFetchOptions) { + setLocalOptions(getLocalOptions(key)) + } + } + + const onClickOutside = () => { + setShowDropdown(false); + setFilterKey(undefined); + } + + const getLocalOptions = filterKey => { + if (filterKey === PLATFORM) { return platformOptions } + if (filterKey === COUNTRY) { return countryOptions } + if (filterKey === LOCATION) { return locationOptions } + return []; + } + + const fetchOptions = options => { + if (!shouldFetchOptions) { + const re = getRE(options.q, 'i') + const opts = getLocalOptions(options.key).filter(f => re.test(f.text)); + return setLocalOptions(opts); + } + + props.fetchOptions(options); + } + + return ( + <OutsideClickDetectingDiv + onClickOutside={onClickOutside} + > + <div className="relative"> + {!filterKey && ( + <div + className={cn(stl.btn, 'rounded flex items-center p-2 color-teal cursor-pointer hover:bg-teal')} + onClick={() => setShowDropdown(true)} + id="filter-options" + > + <Icon name="plus" size={10} color="teal" /> + <span className="ml-1 text-sm tracking-wider font-medium">FILTER</span> + </div> + )} + {showDropdown && ( + <div className="absolute mt-2 bg-white rounded border p-3 z-20" id="filter-dropdown" style={{ width: '200px'}}> + <div className="font-medium mb-2 tracking-widest color-gray-dark">SELECT FILTER</div> + {filterKeys.filter(f => !filterKeyMaps.includes(f.key)).map(f => ( + <div + key={f.key} + onClick={() => onFilterKeySelect(f.key)} + className={cn(stl.filterItem, 'py-3 -mx-3 px-3 flex items-center cursor-pointer')} + > + <Icon name={f.icon} size="16" /> + <span className="ml-3 capitalize">{f.name}</span> + </div> + ))} + </div> + )} + {filterKey && ( + <WidgetAutoComplete + className="ml-2" + autoFocus={true} + loading={props.optionsLoading} + fetchOptions={options => fetchOptions({...options, key: filterKey })} + options={shouldFetchOptions ? props.options.filter(f => f.key === filterKey) : localOptions} + onSelect={onSelect} + placeholder={activeFilter && activeFilter.placeholder} + itemStyle={{ minWidth: '200px'}} + /> + )} + </div> + </OutsideClickDetectingDiv> + ) +} + +export default withRequest({ + dataName: "options", + initialData: [], + dataWrapper: data => data, + resetBeforeRequest: true, + loadingName: 'optionsLoading', + requestName: "fetchOptions", + endpoint: '/dashboard/metadata/search', + method: 'GET' +})(FilterDropdown) diff --git a/frontend/app/components/shared/FilterDropdown/filterDropdown.css b/frontend/app/components/shared/FilterDropdown/filterDropdown.css new file mode 100644 index 000000000..976a0d233 --- /dev/null +++ b/frontend/app/components/shared/FilterDropdown/filterDropdown.css @@ -0,0 +1,13 @@ +.btn { + height: 29px; + padding: 0 10px; + &:hover { + background-color: $gray-light; + } +} + +.filterItem { + &:hover { + background-color: $gray-light; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/FilterDropdown/index.js b/frontend/app/components/shared/FilterDropdown/index.js new file mode 100644 index 000000000..1d321f932 --- /dev/null +++ b/frontend/app/components/shared/FilterDropdown/index.js @@ -0,0 +1 @@ +export { default } from './FilterDropdown'; \ No newline at end of file diff --git a/frontend/app/components/shared/ImageViewer/ImageViewer.js b/frontend/app/components/shared/ImageViewer/ImageViewer.js new file mode 100644 index 000000000..111913771 --- /dev/null +++ b/frontend/app/components/shared/ImageViewer/ImageViewer.js @@ -0,0 +1,30 @@ +import React, { useState } from 'react' +import { Button } from 'UI'; + +export default function ImageViewer( + { source, activeIndex, onClose } +) { + const [currentIndex, setCurrentIndex] = useState(activeIndex) + const onPrevClick = () => { + setCurrentIndex(currentIndex - 1); + } + const onNextClick = () => { + setCurrentIndex(currentIndex + 1); + } + return ( + <div className="absolute bg-gray-light inset-0 z-50"> + <div className="flex justify-between absolute bottom-0 left-0 right-0 p-3 border-t bg-white"> + <Button primary plain onClick={onPrevClick} disabled={currentIndex === 0}> + Prev + </Button> + <Button primary plain onClick={onClose}> + CLOSE + </Button> + <Button primary plain onClick={onNextClick} disabled={currentIndex === source.length - 1}> + Next + </Button> + </div> + <img src={source[currentIndex]} className="border p-3"/> + </div> + ) +} diff --git a/frontend/app/components/shared/ImageViewer/index.js b/frontend/app/components/shared/ImageViewer/index.js new file mode 100644 index 000000000..86ec5cbec --- /dev/null +++ b/frontend/app/components/shared/ImageViewer/index.js @@ -0,0 +1 @@ +export { default } from './ImageViewer'; \ No newline at end of file diff --git a/frontend/app/components/shared/MetricsFilters/FilterItem/FilterItem.js b/frontend/app/components/shared/MetricsFilters/FilterItem/FilterItem.js new file mode 100644 index 000000000..aa235f2fe --- /dev/null +++ b/frontend/app/components/shared/MetricsFilters/FilterItem/FilterItem.js @@ -0,0 +1,97 @@ +import React, { useState } from 'react'; +import { Icon, Dropdown, Button } from 'UI'; +import { LAST_24_HOURS, LAST_30_MINUTES, LAST_7_DAYS, LAST_30_DAYS, CUSTOM_RANGE } from 'Types/app/period'; +import stl from './filterItem.css'; +import cn from 'classnames'; +import { setPeriod } from 'Duck/dashboard'; +import { connect } from 'react-redux'; +import { debounce } from 'App/utils'; +import DateRangeDropdown from 'Shared/DateRangeDropdown/DateRangeDropdown'; +import FilterDropdown from 'Shared/FilterDropdown'; + +export const PERIOD_OPTIONS = [ + { text: 'Past 30 Min', value: LAST_30_MINUTES }, + { text: 'Past 24 Hours', value: LAST_24_HOURS }, + { text: 'Past 7 Days', value: LAST_7_DAYS }, + { text: 'Past 30 Days', value: LAST_30_DAYS }, + { text: 'Choose Date', value: CUSTOM_RANGE }, +]; + +const FilterItem = props => { + const { period, filters, compare = false, metaOptions, allowedFilters = [] } = props; + const filterKeyMaps = filters.map(f => f.key).toJS(); + const [rangeName, setRangeName] = useState(period.rangeName) + const [startDate, setStartDate] = useState(null) + const [endDate, setEndDate] = useState(null) + const setPeriod = debounce(props.setPeriod, 500) + + const appliedFilters = allowedFilters.length > 0 ? + filters.filter(f => allowedFilters.includes(f.key) ) : + filters; + + const onDateChange = (e) => { + setPeriod(compare, { rangeName: e.rangeValue, start: e.startDate, end: e.endDate }); + setRangeName(e.rangeValue) + setStartDate(e.startDate) + setEndDate(e.endDate) + } + + return ( + <div className={cn(stl.wrapper, 'flex items-center')}> + <div className={cn(stl.circle, 'flex-shrink-0', { [stl.compare] : compare})} /> + <div className="flex-shrink-0"> + <DateRangeDropdown + button + onChange={ onDateChange } + rangeValue={ rangeName } + startDate={ startDate } + endDate={ endDate } + /> + </div> + <div className="ml-2" /> + + <div className="flex items-center flex-wrap"> + {appliedFilters.map(f => ( + <div className="bg-white rounded-full p-1 px-3 mr-2"> + <div className="flex items-center"> + <span className="mr-2 color-gray-darkest">{f.text || f.value}</span> + <Icon className="cursor-pointer" size="18" name="close" onClick={() => props.removeFilter(f)} /> + </div> + </div> + ))} + <FilterDropdown + onSelect={props.onSelect} + filterKeyMaps={filterKeyMaps} + metaOptions={metaOptions} + allowedFilters={allowedFilters} + /> + </div> + <div className="ml-auto"> + <div className="flex items-center"> + {filters.size > 0 && ( + <Button size="small" plain hover onClick={props.resetFilters}> + <span className="cursor-pointer color-gray-dark text-sm font-medium">CLEAR</span> + </Button> + )} + { compare && + <Button + size="small" + plain + onClick={props.removeCompare} + > + <Icon className="ml-3 cursor-pointer" name="trash" size="14" /> + </Button> + } + </div> + </div> + </div> + ) +} + +export default connect((state, props) => { + const comparing = props && props.compare; + return { + period: state.getIn([ 'dashboard', comparing ? 'periodCompare' : 'period' ]), + metaOptions: state.getIn([ 'dashboard', 'metaOptions' ]) + } +}, { setPeriod })(FilterItem) \ No newline at end of file diff --git a/frontend/app/components/shared/MetricsFilters/FilterItem/filterItem.css b/frontend/app/components/shared/MetricsFilters/FilterItem/filterItem.css new file mode 100644 index 000000000..3a6bb1008 --- /dev/null +++ b/frontend/app/components/shared/MetricsFilters/FilterItem/filterItem.css @@ -0,0 +1,29 @@ +.wrapper { + min-height: 38px; +} + +.dropdown { + display: 'flex' !important; + align-items: 'center'; + padding: 5px 8px; + border-radius: 3px; + transition: all 0.3s; + font-weight: 500; + + &:hover { + background-color: #DDDDDD; + transition: all 0.2s; + } +} + +.circle { + width: 15px; + height: 15px; + background-color: $tealx; + border-radius: 50%; + margin-right: 10px; + + &.compare { + background-color: $teal; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/MetricsFilters/FilterItem/index.js b/frontend/app/components/shared/MetricsFilters/FilterItem/index.js new file mode 100644 index 000000000..7442505f6 --- /dev/null +++ b/frontend/app/components/shared/MetricsFilters/FilterItem/index.js @@ -0,0 +1 @@ +export { default } from './FilterItem'; diff --git a/frontend/app/components/shared/MetricsFilters/MetricsFilters.js b/frontend/app/components/shared/MetricsFilters/MetricsFilters.js new file mode 100644 index 000000000..e07017e83 --- /dev/null +++ b/frontend/app/components/shared/MetricsFilters/MetricsFilters.js @@ -0,0 +1,61 @@ +import React, { useState } from 'react' +import { Button, Label, Icon, Dropdown } from 'UI'; +import stl from './filters.css'; +import { LAST_24_HOURS, LAST_30_MINUTES, LAST_7_DAYS, LAST_30_DAYS, CUSTOM_RANGE } from 'Types/app/period'; +import FilterItem from './FilterItem'; +import { setComparing, setFilters, clearFilters, removeFilter } from 'Duck/dashboard'; +import { connect } from 'react-redux'; + +export const PERIOD_OPTIONS = [ + { text: 'Past 30 Min', value: LAST_30_MINUTES }, + { text: 'Past 24 Hours', value: LAST_24_HOURS }, + { text: 'Past 7 Days', value: LAST_7_DAYS }, + { text: 'Past 30 Days', value: LAST_30_DAYS }, + { text: 'Choose Date', value: CUSTOM_RANGE }, +]; + +const MetricsFilters = props => { + const { rangeName, comparing, filters, filtersCompare, allowedFilters } = props; + + return ( + <div className="w-full"> + <FilterItem + allowedFilters={allowedFilters} + rangeName={rangeName} + filters={filters} + onSelect={filter => props.setFilters('default', filter)} + removeFilter={filter => props.removeFilter('default', filter.key)} + resetFilters={() => props.clearFilters('default')} + /> + <hr className={stl.divider} /> + {!comparing && ( + <div> + <Button hover plain size="small" onClick={() => props.setComparing(true)} id="compare-button"> + <span className="text-sm font-medium tracking-wider">COMPARE</span> + </Button> + </div> + )} + {comparing && ( + <React.Fragment> + <FilterItem + compare + rangeName={rangeName} + filters={filtersCompare} + // onPeriodChange={onPeriodChange} + onSelect={filter => props.setFilters('compare', filter)} + removeFilter={filter => props.removeFilter('compare', filter.key)} + removeCompare={() => props.setComparing(false)} + resetFilters={() => props.clearFilters('compare')} + allowedFilters={allowedFilters} + /> + </React.Fragment> + )} + </div> + ) +} + +export default connect(state => ({ + comparing: state.getIn([ 'dashboard', 'comparing' ]), + filters: state.getIn([ 'dashboard', 'filters' ]), + filtersCompare: state.getIn([ 'dashboard', 'filtersCompare' ]), +}), { setComparing, setFilters, clearFilters, removeFilter })(MetricsFilters) diff --git a/frontend/app/components/shared/MetricsFilters/filters.css b/frontend/app/components/shared/MetricsFilters/filters.css new file mode 100644 index 000000000..9c0bda3a4 --- /dev/null +++ b/frontend/app/components/shared/MetricsFilters/filters.css @@ -0,0 +1,32 @@ +.dropdown { + display: 'flex' !important; + align-items: 'center'; + padding: 5px 8px; + border-radius: 3px; + transition: all 0.3s; + font-weight: 500; + + &:hover { + background-color: #DDDDDD; + transition: all 0.2s; + } +} + +.dateInput { + display: flex; + align-items: center; + padding: 4px; + font-weight: 500; + font-size: 14px; + color: $gray-darkest; + + &:hover { + background-color: lightgray; + border-radius: 3px; + } +} + +.divider { + margin: 10px 0; + border-top: solid thin $gray-light; +} \ No newline at end of file diff --git a/frontend/app/components/shared/MetricsFilters/index.js b/frontend/app/components/shared/MetricsFilters/index.js new file mode 100644 index 000000000..2765a826e --- /dev/null +++ b/frontend/app/components/shared/MetricsFilters/index.js @@ -0,0 +1 @@ +export { default as MetricsFilters } from './MetricsFilters'; diff --git a/frontend/app/components/shared/NewBadge/NewBadge.js b/frontend/app/components/shared/NewBadge/NewBadge.js new file mode 100644 index 000000000..bf388b276 --- /dev/null +++ b/frontend/app/components/shared/NewBadge/NewBadge.js @@ -0,0 +1,10 @@ +import React from 'react' +import stl from './newBadge.css' + +function NewBadge() { + return ( + <div className={stl.newBadge}>New</div> + ) +} + +export default NewBadge diff --git a/frontend/app/components/shared/NewBadge/index.js b/frontend/app/components/shared/NewBadge/index.js new file mode 100644 index 000000000..cce614d2c --- /dev/null +++ b/frontend/app/components/shared/NewBadge/index.js @@ -0,0 +1 @@ +export { default } from './NewBadge' \ No newline at end of file diff --git a/frontend/app/components/shared/NewBadge/newBadge.css b/frontend/app/components/shared/NewBadge/newBadge.css new file mode 100644 index 000000000..60a8f6eab --- /dev/null +++ b/frontend/app/components/shared/NewBadge/newBadge.css @@ -0,0 +1,13 @@ +.newBadge { + height: 14px; + width: 34px; + letter-spacing: 2px; + background-image: linear-gradient(40deg, #6051FF 0%, #FF693B 100%); + border-radius: 3px; + font-size: 9px; + line-height: 15px; + color: white; + text-align: center; + right: -22px; + top: 10px; +} \ No newline at end of file diff --git a/frontend/app/components/shared/NoSessionsMessage/NoSessionsMessage.js b/frontend/app/components/shared/NoSessionsMessage/NoSessionsMessage.js new file mode 100644 index 000000000..d8b266529 --- /dev/null +++ b/frontend/app/components/shared/NoSessionsMessage/NoSessionsMessage.js @@ -0,0 +1,41 @@ +import React from 'react' +import { Icon, Button } from 'UI' +import { connect } from 'react-redux' +import { onboarding as onboardingRoute } from 'App/routes' +import { withRouter } from 'react-router-dom'; +import * as routes from '../../../routes'; +const withSiteId = routes.withSiteId; + +const NoSessionsMessage= (props) => { + const { site, sites, match: { params: { siteId } } } = props; + const activeSite = sites.find(s => s.id == siteId); + const showNoSessions = !!activeSite && !activeSite.recorded; + console.log('site', activeSite); + return ( + <> + {showNoSessions && ( + <div> + <div + className="rounded text-sm flex items-center p-2 justify-between mb-4" + style={{ backgroundColor: 'rgba(255, 239, 239, 1)', border: 'solid thin rgba(221, 181, 181, 1)'}} + > + <div className="flex items-center w-full"> + <div className="flex-shrink-0 w-8 flex justify-center"> + <Icon name="info-circle" size="14" color="gray-darkest" /> + </div> + <div className="ml-2color-gray-darkest mr-auto"> + It takes a few minutes for first recordings to appear. <strong>All set but they are still not showing up?</strong> Check our <a>troubleshooting</a> section. + </div> + <Button outline size="smallest" onClick={() => props.history.push(withSiteId(onboardingRoute('installing'), siteId))}>Go to project setup</Button> + </div> + </div> + </div> + )} + </> + ) +} + +export default connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), + sites: state.getIn([ 'site', 'list' ]) +}))(withRouter(NoSessionsMessage)) \ No newline at end of file diff --git a/frontend/app/components/shared/NoSessionsMessage/index.js b/frontend/app/components/shared/NoSessionsMessage/index.js new file mode 100644 index 000000000..f116ee840 --- /dev/null +++ b/frontend/app/components/shared/NoSessionsMessage/index.js @@ -0,0 +1 @@ +export { default } from './NoSessionsMessage' \ No newline at end of file diff --git a/frontend/app/components/shared/OutsideClickDetectingDiv/OutsideClickDetectingDiv.js b/frontend/app/components/shared/OutsideClickDetectingDiv/OutsideClickDetectingDiv.js new file mode 100644 index 000000000..954566480 --- /dev/null +++ b/frontend/app/components/shared/OutsideClickDetectingDiv/OutsideClickDetectingDiv.js @@ -0,0 +1,50 @@ +import { findDOMNode } from 'react-dom'; +import React, { useRef, useLayoutEffect } from "react"; + +let refs = []; +let callbacks = []; + +function addOutsideClickListener(ref, callback) { + refs.push(ref); + callbacks.push(callback); +} + +function removeOutsideClickListener(ref) { + const index = refs.indexOf(ref); + if (index === -1) return; + refs.splice(index, 1); + callbacks.splice(index, 1); +} + +function handleClickOutside(e) { + refs.forEach((ref, i) => { + if (ref.current !== null) { + const node = findDOMNode(ref.current); + if (node && !node.contains(e.target)) { + callbacks[i](e); + } + } + }) +} + +document.addEventListener('click', handleClickOutside); + + +export default React.memo(function OutsideClickDetectingDiv({ onClickOutside, children, ...props}) { + const ref = useRef(null); + useLayoutEffect(() => { + function handleClickOutside(event) { + if (ref.current && !ref.current.contains(event.target)) { + onClickOutside(event); + } + } + + addOutsideClickListener(ref, handleClickOutside); + return () => removeOutsideClickListener(ref); + }, [ ref ]); + + return <div ref={ref} {...props}>{children}</div>; +}); + + + diff --git a/frontend/app/components/shared/OutsideClickDetectingDiv/index.js b/frontend/app/components/shared/OutsideClickDetectingDiv/index.js new file mode 100644 index 000000000..3a2520cf6 --- /dev/null +++ b/frontend/app/components/shared/OutsideClickDetectingDiv/index.js @@ -0,0 +1 @@ +export { default } from './OutsideClickDetectingDiv'; \ No newline at end of file diff --git a/frontend/app/components/shared/ResultTimings/Bar.js b/frontend/app/components/shared/ResultTimings/Bar.js new file mode 100644 index 000000000..6028f74d2 --- /dev/null +++ b/frontend/app/components/shared/ResultTimings/Bar.js @@ -0,0 +1,12 @@ +import React from 'react' + +function Bar({ start, end, color = '#CCCCCC' }) { + return ( + <div + style={{ left: start + '%', right: end + '%', backgroundColor: color }} + className="bg-red absolute top-0 left-0 h-4" + /> + ) +} + +export default Bar diff --git a/frontend/app/components/shared/ResultTimings/Barwrapper.js b/frontend/app/components/shared/ResultTimings/Barwrapper.js new file mode 100644 index 000000000..27acf5ed5 --- /dev/null +++ b/frontend/app/components/shared/ResultTimings/Barwrapper.js @@ -0,0 +1,20 @@ +import React from 'react' + +function Barwrapper({ title, duration, children }) { + let _duration = Math.floor(parseInt(duration)); + _duration = _duration < 1 ? ' < 1' : _duration; + + return ( + <div> + <div className="flex items-center mb-2 my-2"> + <div className="w-3/12">{title}</div> + <div className="w-6/12 relative h-4"> + {children} + </div> + <div className="w-3/12 text-right">{_duration + ' ms'}</div> + </div> + </div> + ) +} + +export default Barwrapper diff --git a/frontend/app/components/shared/ResultTimings/ResultTimings.js b/frontend/app/components/shared/ResultTimings/ResultTimings.js new file mode 100644 index 000000000..2cd82ee1e --- /dev/null +++ b/frontend/app/components/shared/ResultTimings/ResultTimings.js @@ -0,0 +1,78 @@ +import React from 'react'; +import Bar from './Bar'; +import { List } from 'immutable'; +import { percentOf } from 'App/utils'; +import SectionWrapper from './SectionWrapper'; +import Barwrapper from './Barwrapper'; +import { NoContent } from 'UI'; + +function ResultTimings({ duration, timing }) { + const { blocked, connect, dns, queued, receive, send, ssl, wait } = timing; + const _dns = Math.max(dns, 0); + const _ssl = Math.max(ssl, 0); + const _connect = Math.max(connect, 0); + const _blocked = Math.max(blocked, 0); + const total = parseInt(_blocked + _connect + _dns + queued + receive + send + wait); + + const blockedStart = queued; + const dnsStart = blockedStart + blocked; + const connectStart = dnsStart + _dns; + const sslStart = connectStart + _connect - _ssl; + const sendStart = connectStart + _connect; + const waitSrart = sendStart + send; + const receiveStart = waitSrart + wait; + return ( + <NoContent + title="No Data!" + icon="exclamation-circle" + show={ List.isList(timing)} + size="small" + > + <div className="bg-white flex flex-col rounded m-3"> + <SectionWrapper title="Resource Scheduling"> + <Barwrapper title="Queuing" duration={queued}> + <Bar start={percentOf(0, total)} end={percentOf((total - queued), total)} /> + </Barwrapper> + </SectionWrapper> + <SectionWrapper title="Connection Start"> + <Barwrapper title="Stalled" duration={blocked}> + <Bar start={percentOf(blockedStart, total)} end={percentOf((total - (queued + blocked)), total)} /> + </Barwrapper> + {dns >= 0 && ( + <Barwrapper title="DNS Lookup" duration={_dns}> + <Bar start={percentOf(dnsStart, total)} end={percentOf((total - (dnsStart + _dns)), total)} color="green"/> + </Barwrapper> + )} + {connect >= 0 && ( + <Barwrapper title="Initial Connection" duration={_connect}> + <Bar start={percentOf(connectStart, total)} end={percentOf((total - (connectStart + _connect)), total)} color="orange" /> + </Barwrapper> + )} + {ssl >= 0 && ( + <Barwrapper title="SSL" duration={_ssl}> + <Bar start={percentOf(sslStart, total)} end={percentOf((total - (sslStart + _ssl)), total)} color="violet" /> + </Barwrapper> + )} + </SectionWrapper> + + <SectionWrapper title="Request/Response"> + <Barwrapper title="Request Sent" duration={send}> + <Bar start={percentOf(sendStart, total)} end={percentOf((total - (sendStart + send)), total)} /> + </Barwrapper> + <Barwrapper title="Waiting (TTFB)" duration={wait}> + <Bar start={percentOf(waitSrart, total)} end={percentOf((total - (waitSrart + wait)), total)} color="#00C852" /> + </Barwrapper> + <Barwrapper title="Download" duration={receive}> + <Bar start={percentOf(receiveStart, total)} end={percentOf((total - (receiveStart + receive)), total)} color="#01A8F4" /> + </Barwrapper> + </SectionWrapper> + <div className="flex my-3"> + <div className="font-medium">Total</div> + <div className="font-medium ml-auto">{total} ms</div> + </div> + </div> + </NoContent> + ) +} + +export default ResultTimings diff --git a/frontend/app/components/shared/ResultTimings/SectionWrapper.js b/frontend/app/components/shared/ResultTimings/SectionWrapper.js new file mode 100644 index 000000000..86afc9035 --- /dev/null +++ b/frontend/app/components/shared/ResultTimings/SectionWrapper.js @@ -0,0 +1,17 @@ +import React from 'react' + +function SectionWrapper({ title, children }) { + return ( + <div className="mb-3"> + <div className="flex my-2"> + <div className="mr-auto color-gray-medium uppercase">{title}</div> + <div className="color-gray-medium">DURATION</div> + </div> + <div> + { children } + </div> + </div> + ) +} + +export default SectionWrapper diff --git a/frontend/app/components/shared/ResultTimings/index.js b/frontend/app/components/shared/ResultTimings/index.js new file mode 100644 index 000000000..3923a7382 --- /dev/null +++ b/frontend/app/components/shared/ResultTimings/index.js @@ -0,0 +1 @@ +export { default } from './ResultTimings'; diff --git a/frontend/app/components/shared/Results/CodeLoader.js b/frontend/app/components/shared/Results/CodeLoader.js new file mode 100644 index 000000000..491612baa --- /dev/null +++ b/frontend/app/components/shared/Results/CodeLoader.js @@ -0,0 +1,68 @@ +import copy from 'copy-to-clipboard'; +import { Loader, CodeEditor } from 'UI'; +import styles from './codeLoader.css'; + +export default class CodeLoader extends React.PureComponent { + static defaultProps = { onOpenResults: Function } + + state = { + code: null, + errors: null, + loading: false, + } + + componentDidMount() { + this.loadCode(); + } + + componentWillReceiveProps(newProps) { + if (newProps.url !== this.props.url) { + this.loadCode(newProps); + } + } + + copyHandler = () => { + this.setState({ copied: true }); + const { code } = this.state; + copy(code); + setTimeout(() => { + this.setState({ copied: false }); + }, 2000); + }; + + loadCode(props = this.props) { + const { url } = props; + if (url) { + this.setState({ loading: true }); + window.fetch(url) + .then(responce => responce.text()) + .then(code => this.setState({ errors: null, code, loading: false })) + .catch(errors => this.setState({ errors, loading: false })); + } else { + this.setState({ errors: true }) + } + } + + render() { + const { + code, loading, errors, copied, + } = this.state; + + if (errors) return "Some error occured..."; + + return ( + <div className={ styles.wrapper }> + <Loader loading={ loading }> + <div> + <button className={ styles.codeCopy } onClick={ this.copyHandler }>{ copied ? 'copied' : 'copy' }</button> + <CodeEditor + lineNumbers + className={ styles.codeLoader } + value={ code } + /> + </div> + </Loader> + </div> + ); + } +} diff --git a/frontend/app/components/shared/Results/ConsoleTab.js b/frontend/app/components/shared/Results/ConsoleTab.js new file mode 100644 index 000000000..fa9bbb2d6 --- /dev/null +++ b/frontend/app/components/shared/Results/ConsoleTab.js @@ -0,0 +1,22 @@ +import ConsoleContent from '../../Session_/Console/ConsoleContent'; +import styles from './consoleTab.css'; + +const HEEADER_HEIGHT = 550; + +export default class ConsoleTab extends React.Component { + vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0) - HEEADER_HEIGHT; + + constructor(props) { + super(props); + this.state = { blocks: null, errors: props.errors }; + } + + render() { + const { className, logs } = this.props; + return ( + <div className={ `${ className } ${ styles.consoleTab }` }> + <ConsoleContent isResult logs={logs} additionalHeight={this.vh} /> + </div> + ); + } +} diff --git a/frontend/app/components/shared/Results/LogTab.js b/frontend/app/components/shared/Results/LogTab.js new file mode 100644 index 000000000..402cb08bb --- /dev/null +++ b/frontend/app/components/shared/Results/LogTab.js @@ -0,0 +1,59 @@ +import { Loader } from 'UI'; +import styles from './logTab.css'; + +const REQUEST = '[REQUEST]'; +const RESPONSE = '[RESPONSE]'; + +const parse = text => text.split('\n').map((bText) => { + if (bText.indexOf(REQUEST) !== -1) { + return ( + <div> + <span className={ styles.request }>{'REQUEST: '}</span> + { bText.slice(REQUEST.length) } + </div> + ); + } + if (bText.indexOf(RESPONSE) !== -1) { + return ( + <div> + <span className={ styles.responce }>{'RESPONSE: '}</span> + { bText.slice(RESPONSE.length) } + </div> + ); + } + return bText; +}); + +export default class LogTab extends React.PureComponent { + state = { + blocks: null, + errors: null, + }; + + componentWillMount() { + fetch(this.props.src) + .then(responce => responce.text()) + .then(parse) + .then(blocks => this.setState({ errors: null, blocks })) + .catch(errors => this.setState({ errors, blocks: null })); + } + + scrollToSelected = (wrapper) => { + const { selectedIndex } = this.props; + if (!selectedIndex || !wrapper) return; + wrapper.scrollTop = wrapper.children[ selectedIndex ].offsetTop; + } + + render() { + const { blocks, errors } = this.state; + const { selectedIndex, className } = this.props; + if (errors) return 'Connection error'; + if (!blocks) return <Loader />; + return ( + <div className={ `${ className } ${ styles.logTab }` } ref={ this.scrollToSelected }> + { blocks.map((block, i) => + <div className={ styles.block } data-selected={ selectedIndex === i }> { block } </div>)} + </div> + ); + } +} diff --git a/frontend/app/components/shared/Results/MetricsTab/MetricsTab.js b/frontend/app/components/shared/Results/MetricsTab/MetricsTab.js new file mode 100644 index 000000000..6ef7ad308 --- /dev/null +++ b/frontend/app/components/shared/Results/MetricsTab/MetricsTab.js @@ -0,0 +1,110 @@ +import React, { useEffect } from 'react' +import { Icon, NoContent, QuestionMarkHint } from 'UI' +import cn from 'classnames' +import { withRequest } from 'HOCs' +import stl from './metricsTab.css' + +const IconRed = () => <div className="h-2 w-2 bg-red mr-2" /> +const IconOrange = () => <div className="mr-2" style={{ borderWidth: "0 5px 7px 5px", borderColor: "transparent transparent #007bff transparent" }} /> +const IconGreen = () => <div className="h-2 w-2 bg-green mr-2 rounded-full" /> + +const Card = ({ metric : { title, displayValue, score, description } }) => ( + <div className="border rounded text-center p-6 flex flex-col justify-center"> + <div className="text-lg mb-3 flex justify-center"> + <span className="mr-2">{title}</span> + <QuestionMarkHint + onHover + content={description} + position="top center" + className="mr-8" + /> + </div> + <div className="flex items-center justify-center"> + {score < 0.5 && <IconRed /> } + {score <= 0.9 && score >= 0.5 && <IconOrange /> } + {score > 0.9 && <IconGreen /> } + <div className="text-2xl font-medium">{displayValue}</div> + </div> + </div> +) + +function MetricsTab({ run, className, fetchMetrics }) { + const downloadFile = () => { + window.open(run.lighthouseHtmlFile); + } + + useEffect(() => { + // fetchMetrics(); + }, []) + + return ( + <div className={className}> + <div className="flex items-center -mx-4"> + <div className="flex items-center w-8/12 justify-between px-24 mx-4 bg-gray-lightest rounded h-10"> + <div className="font-medium">Score</div> + <div className="flex items-center"> + <IconRed /> + <div>{'< 0.5'}</div> + </div> + <div className="flex items-center"> + <IconOrange /> + <div>{'0.5 - 0.9'}</div> + </div> + <div className="flex items-center"> + <IconGreen /> + <div>{'> 0.9'}</div> + </div> + </div> + <div + className={cn('my-3 cursor-pointer py-2 w-4/12 mx-4 h-10 flex justify-center rounded bg-teal-light', stl.downloadButton)} + onClick={downloadFile} + > + <Icon name="download" size="16" color="teal" /> + <span className="ml-2 color-teal font-medium">Lighthouse Report</span> + </div> + </div> + <NoContent + title="No data available." + size="small" + show={ !run.auditsPerformance && !run.auditsAd } + > + <div className="mt-4"> + <h2 className="text-xl mb-2">Performance</h2> + <div className="grid grid-cols-3 gap-4 mt-4"> + { run.auditsPerformance && Object.keys(run.auditsPerformance).map(i => { + const metric = run.auditsPerformance[i]; + if (!metric) return; + + return ( + <Card metric={metric} title={metric.title} value={metric.displayValue} score={metric.score} hint={metric.description} /> + ) + })} + </div> + </div> + + <div className="mt-6"> + <h2 className="text-xl mb-2">Ads</h2> + <div className="grid grid-cols-3 gap-4 mt-4"> + { run.auditsAd && Object.keys(run.auditsAd).map(i => { + const metric = run.auditsAd[i]; + if (!metric) return; + + return ( + <Card metric={metric} title={metric.title} value={metric.displayValue} score={metric.score} hint={metric.description} /> + ) + })} + </div> + </div> + </NoContent> + </div> + ) +} + +export default withRequest({ + dataName: "metrics", + initialData: false, + dataWrapper: data => data.state, + requestName: "fetchMetrics", + endpoint: '/integrations/elasticsearch/test', + method: 'POST', +})(MetricsTab) diff --git a/frontend/app/components/shared/Results/MetricsTab/index.js b/frontend/app/components/shared/Results/MetricsTab/index.js new file mode 100644 index 000000000..ecceb7440 --- /dev/null +++ b/frontend/app/components/shared/Results/MetricsTab/index.js @@ -0,0 +1 @@ +export { default } from './MetricsTab'; \ No newline at end of file diff --git a/frontend/app/components/shared/Results/MetricsTab/metricsTab.css b/frontend/app/components/shared/Results/MetricsTab/metricsTab.css new file mode 100644 index 000000000..50a8141c2 --- /dev/null +++ b/frontend/app/components/shared/Results/MetricsTab/metricsTab.css @@ -0,0 +1,3 @@ +.downloadButton { + background-color: #E5EDFF; +} \ No newline at end of file diff --git a/frontend/app/components/shared/Results/NetworkTab/NetworkTab.js b/frontend/app/components/shared/Results/NetworkTab/NetworkTab.js new file mode 100644 index 000000000..fe2ea0ac3 --- /dev/null +++ b/frontend/app/components/shared/Results/NetworkTab/NetworkTab.js @@ -0,0 +1,96 @@ +import React, { useState } from 'react' +import { SlideModal, Label, Icon } from 'UI'; +import { connect } from 'react-redux' +import cn from 'classnames'; +import NetworkContent from '../../../Session_/Network/NetworkContent' +import FetchDetails from '../../../Session_/Fetch/FetchDetails'; +import stl from './networkTab.css'; + +const HEEADER_HEIGHT = 590; + +function NetworkTab(props) { + const { run, className } = props; + const requests = run.resources; + const [current, setCurrent] = useState(null); + const [currentIndex, setCurrentIndex] = useState(0); + const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0) - HEEADER_HEIGHT; + + const downloadHarFile = () => { + window.open(run.harfile); + } + + const nextClickHander = () => { + const requests = run.resources; + if (currentIndex === requests.length - 1) return; + const newIndex = currentIndex + 1; + setCurrent(requests[newIndex]); + setCurrentIndex(newIndex); + } + + const prevClickHander = () => { + const requests = run.resources; + + if (currentIndex === 0) return; + const newIndex = currentIndex - 1; + setCurrent(requests[newIndex]); + setCurrentIndex(newIndex); + } + + return ( + <div className={ className }> + <SlideModal + size="middle" + title={ + <div className="flex justify-between"> + <h1>Fetch Request</h1> + <div className="flex items-center"> + <span className="mr-2 color-gray-medium uppercase text-base">Status</span> + <Label + data-red={current && current.status >= 400} + data-green={current && current.status < 400} + > + <div className="uppercase w-16 justify-center code-font text-lg">{current && current.status}</div> + </Label> + </div> + </div> + } + isDisplayed={ current != null } + content={ current && + <FetchDetails + isResult + resource={ current } + nextClick={nextClickHander} + prevClick={prevClickHander} + first={currentIndex === 0} + last={currentIndex === requests.length - 1} + /> + } + onClose={ () => setCurrent(null) } + /> + <div + className={cn('my-3 cursor-pointer py-2 flex justify-center w-full rounded', stl.downloadButton)} + onClick={downloadHarFile} + > + <Icon name="download" size="16" color="teal" /> + <span className="ml-2 color-teal font-medium">HAR Reports</span> + </div> + <NetworkContent + isResult + resources={requests} + onRowClick={ (e, index) => { setCurrent(e); setCurrentIndex(index)} } + additionalHeight={vh} + fetchPresented = { run.fetchPresented } + + loadTime = { run.loadTime } + domBuildingTime = { run.domBuildingTime } + resourcesSize = { run.resourcesSize } + transferredSize = { run.transferredSize } + domContentLoadedTime = { run.domContentLoadedTime } + /> + </div> + ) +} + +export default connect(state => ({ + requests: state.getIn([ 'tests', 'sampleRun', 'resources']) +}))(NetworkTab) diff --git a/frontend/app/components/shared/Results/NetworkTab/index.js b/frontend/app/components/shared/Results/NetworkTab/index.js new file mode 100644 index 000000000..a9b110ae6 --- /dev/null +++ b/frontend/app/components/shared/Results/NetworkTab/index.js @@ -0,0 +1 @@ +export { default } from './NetworkTab'; \ No newline at end of file diff --git a/frontend/app/components/shared/Results/NetworkTab/networkTab.css b/frontend/app/components/shared/Results/NetworkTab/networkTab.css new file mode 100644 index 000000000..50a8141c2 --- /dev/null +++ b/frontend/app/components/shared/Results/NetworkTab/networkTab.css @@ -0,0 +1,3 @@ +.downloadButton { + background-color: #E5EDFF; +} \ No newline at end of file diff --git a/frontend/app/components/shared/Results/TimelineTab.js b/frontend/app/components/shared/Results/TimelineTab.js new file mode 100644 index 000000000..410380e92 --- /dev/null +++ b/frontend/app/components/shared/Results/TimelineTab.js @@ -0,0 +1,101 @@ +import { useState } from 'react'; +import { Popup, Icon, Label } from 'UI'; +import typeToIcon from './typeToIcon'; +import cn from 'classnames'; +import styles from './timelineTab.css'; +import ImageViewer from '../ImageViewer/ImageViewer'; + +const formatExecutionTime = ({ milliseconds }) => (milliseconds >= 1000 + ? `${ Math.round(milliseconds / 1000) } s` + : `${ milliseconds } ms`); + +const formatStartTime = (time, firstStepTime) => + time.diff(firstStepTime).toFormat('mm:ss'); + +const renderStep = (step, makeGotoLogHandler, startedAt, onThumbClick, index) => ( + <div className={ cn(styles.step, 'flex items-center', { 'failed' : step.status === 'failed' }) }> + <div className={ cn(styles.iconWrapper) }> + <Icon name={ typeToIcon(step.label) } size="20" color="gray-dark" /> + </div> + <div className={ styles.description }> + <div className="text-sm color-gray-medium"> + @ { formatStartTime(step.startedAt, startedAt) } + </div> + + <div className={ styles.line }> + <div className="text-lg">{ step.title }</div> + </div> + + { step.info && + <div + className={ styles.info } + > + {step.info} + </div> + } + { step.input && ( + <Label data-red={ step.input === 'failed' }><div className="uppercase w-16 justify-center">{step.input}</div></Label> + )} + </div> + <div className={ cn('ml-auto text-right flex items-center') }> + <img + src={step.screenshotUrl} + className="w-20 h-12 border cursor-pointer" + onClick={() => onThumbClick(index)} + /> + <div className="mx-10"></div> + <div className="w-16">{ formatExecutionTime(step.duration) }</div> + </div> + </div> +); + +const TimelineTab = ({ + steps, startedAt, makeGotoLogHandler, className, +}) => { + const [stepIndex, setStepIndex] = useState(null) + + const onThumbClick = (index) => { + setStepIndex(index); + } + + return ( + <> + { stepIndex != null && ( + <ImageViewer + source={steps.map(i => i.screenshotUrl).toJS()} + activeIndex={stepIndex} + onClose={() => setStepIndex(null)} + /> + )} + <div className={ className }> + <div className="flex justify-between py-4 border-b"> + <div className="font-medium">User Events</div> + <div className="font-medium">Duration</div> + </div> + <div className="relative"> + { steps.map((step, index) => ( + <div className={ styles.stepWrapper } key={ step.order }> + <div className={styles.verticleLine }/> + { renderStep(step, makeGotoLogHandler, startedAt, onThumbClick, index) } + { + step.steps && step.steps.size > 0 && + <div className={ styles.subSteps }> + { + step.steps.map((subStep, j) => ( + <div key={ subStep.order }> + { renderStep(subStep, j, makeGotoLogHandler, startedAt, null, index) } + </div> + )) + } + </div> + } + <div className={styles.bottomBorder} /> + </div> + ))} + </div> + </div> + </> + ); +} + +export default TimelineTab; \ No newline at end of file diff --git a/frontend/app/components/shared/Results/Title.js b/frontend/app/components/shared/Results/Title.js new file mode 100644 index 000000000..56a1658ed --- /dev/null +++ b/frontend/app/components/shared/Results/Title.js @@ -0,0 +1,15 @@ +import { BackLink } from 'UI'; +import styles from './title.css'; + +const Title = ({ goBack }) => (!!goBack ? + <div className={ styles.title }> + <BackLink onClick={ goBack } /> + { "Last Results" } + </div> + : + "Results" +); + +Title.displayName = "Title"; + +export default Title; diff --git a/frontend/app/components/shared/Results/VideoTab.js b/frontend/app/components/shared/Results/VideoTab.js new file mode 100644 index 000000000..87aa6b246 --- /dev/null +++ b/frontend/app/components/shared/Results/VideoTab.js @@ -0,0 +1,11 @@ +import styles from './videoTab.css'; + +export default ({ src, className }) => ( + <div className={ className }> + <video src={ src } className={ styles.video } controls> + {'Sorry, your browser doesn\'t support embedded videos, but don\'t worry, you can '} + <a href={ src }>{'download it'}</a> + {'and watch it with your favorite video player!'} + </video> + </div> +); diff --git a/frontend/app/components/shared/Results/codeLoader.css b/frontend/app/components/shared/Results/codeLoader.css new file mode 100644 index 000000000..c8e1d2dac --- /dev/null +++ b/frontend/app/components/shared/Results/codeLoader.css @@ -0,0 +1,31 @@ +.wrapper { + position: relative; +} +.codeCopy { + position: absolute; + z-index: 50; + top: 10px; + right: 15px; + background: rgba(0, 0, 0, 0.2); + color: white !important; + padding: 6px 20px; + cursor: pointer; + border-radius: 3px; + color: $gray-medium; + min-width: 90px; + transition: all 0.3s; + + &:hover { + background: rgba(0, 0, 0, 0.4); + transition: all 0.2s; + } +} + +.codeLoader { + width: 100%; + height: calc(100vh - 215px); + + & :global(.CodeMirror) { + height: 100%; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/Results/consoleTab.css b/frontend/app/components/shared/Results/consoleTab.css new file mode 100644 index 000000000..2305b0900 --- /dev/null +++ b/frontend/app/components/shared/Results/consoleTab.css @@ -0,0 +1,3 @@ +.block { + padding: 5px; +} \ No newline at end of file diff --git a/frontend/app/components/shared/Results/index.js b/frontend/app/components/shared/Results/index.js new file mode 100644 index 000000000..665d1683f --- /dev/null +++ b/frontend/app/components/shared/Results/index.js @@ -0,0 +1 @@ +export { default } from './Results'; diff --git a/frontend/app/components/shared/Results/logTab.css b/frontend/app/components/shared/Results/logTab.css new file mode 100644 index 000000000..b7bc978b1 --- /dev/null +++ b/frontend/app/components/shared/Results/logTab.css @@ -0,0 +1,21 @@ + +.logTab { + position: relative; /* for the js offsetTop work */ +} + +.request { + color: $orange; +} + +.responce { + color: $blue; +} + +.block { + padding: 10px; + text-align: justify; + &[data-selected=true] { + background: $gray-light + } + +} \ No newline at end of file diff --git a/frontend/app/components/shared/Results/results.css b/frontend/app/components/shared/Results/results.css new file mode 100644 index 000000000..7419751d2 --- /dev/null +++ b/frontend/app/components/shared/Results/results.css @@ -0,0 +1,102 @@ +@import "icons.css"; + +.wrapper { + display: flex; + flex-direction: column; + padding: 0 15px 0px 15px; + height: calc(100vh - 60px); + background-color: $gray-lightest; +} + +.runInfo { + background: white; + padding: 10px; + margin-bottom: 20px; + border-radius: 3px; + box-shadow: 0px 1px 3px 0 $gray-light; + + & .topBlock, + & .bottomBlock { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: space-between; + } + + & .topBlock { + padding: 0px 10px; + margin-bottom: 10px; + align-items: flex-start; + & > div { + flex-shrink: 0; + &:nth-child(2) { + flex-shrink: 1; + padding: 0 10px; + } + } + } + + & .bottomBlock { + background-color: white; + border-radius: 15px; + height: 30px; + padding: 0 10px; + box-shadow: 0px 1px 3px 0 $gray-light; + & .testDetails, & .clientDetails { + display: flex; + align-items: center; + } + } + + & .asssetsButtonContent { + display: flex; + align-items: center; + } + + + & .downloadIcon { + @mixin icon download, $teal, 10px; + cursor: pointer; + margin-right: 10px; + } + +} + +.scheduleIcon { + @mixin icon history, $teal; + width: 12px; + height: 12px; + margin-right: 5px; +} + +.tabLabel { + cursor: pointer; + border-bottom: 2px solid transparent; + text-align: center; + padding: 10px 0; + width: 108px; + display: inline-block; + transition: all 0.2s; + text-transform: uppercase; + + &:hover{ + border-color: $teal; + transition: all 0.2s; + color: $teal-dark; + } + + &[data-active=true] { + border-color: $teal; + color: $teal-dark; + } +} + +.tab { + flex: 1; + overflow-y: auto; + background-color: white !important; + margin: 0 -15px; + padding: 0 15px; + padding-top: 10px; +} + diff --git a/frontend/app/components/shared/Results/timelineTab.css b/frontend/app/components/shared/Results/timelineTab.css new file mode 100644 index 000000000..3f7b7473f --- /dev/null +++ b/frontend/app/components/shared/Results/timelineTab.css @@ -0,0 +1,141 @@ +@import "icons.css"; + +.stepWrapper { + overflow: hidden; + font-size: 13px; + position: relative; + transition: all 0.4s; + + & .step { + min-height: 40px; + padding: 20px 0; + + &.failed .iconWrapper { + background-color: #FFF2F2 !important; + } + } + + &:last-child::after { + display: none; + } + + & .bottomBorder { + height: 1px; + border-bottom: dashed thin $gray-light; + position: absolute; + bottom: 0; + left: 50px; + right: 0; + } +} + +.subSteps { + padding-left: 50px; + & .step { + background-color: $gray-lightest; + padding: 5px 0; + padding-left: 5px; + border-bottom: solid thin $gray-light; + + & .description { + width: 423px; + } + } +} + +.iconWrapper { + width: 40px; + height: 40px; + background: $gray-lightest; + border: 1px solid $gray-light; + border-radius: 20px; + display: flex; + align-items: center; + justify-content: center; + position: relative; +} + +.description { + width: 70%; + padding: 0 12px; + & .line { + white-space: nowrap; + align-items: center; + margin-right: 5px; + text-transform: capitalize; + } + & .info { + max-width: 80%; + display: block; + border-radius: 3px; + padding: 3px; + color: $gray-dark; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + background-color: #FFF2F2; + font-family: 'menlo', 'monaco', 'consolas', monospace; + margin: 5px 0; + } + + & .input { + line-height: 17px; + background-color: #CC0000; + color: white; + padding: 2px 8px; + text-transform: uppercase; + border-radius: 3px; + width: fit-content; + font-size: 12px; + display: flex; + align-items: center; + } +} + +.screenshotButton { + padding: 5px; + margin-top: 12px; + cursor: pointer; + @mixin icon camera, $gray-dark, 18px; + &:hover{ + @mixin icon camera, $gray-medium, 18px; + } +} +.screenshot img { + width: 300px; + height: auto; +} + +.stepWrapper:first-child { + & .verticleLine:before { + display: none !important; + } +} + +.stepWrapper:last-child { + & .verticleLine:after { + display: none !important; + } +} + +.verticleLine { + &:before, &:after { + content: ""; + width: 1px; + position: absolute; + background-color: $gray-light; + left: 20px; + } + + &:before { + top: 0; + bottom: 50%; + } + + &:after { + top: 50%; + bottom: 0; + + } + +} \ No newline at end of file diff --git a/frontend/app/components/shared/Results/title.css b/frontend/app/components/shared/Results/title.css new file mode 100644 index 000000000..8cc702d8a --- /dev/null +++ b/frontend/app/components/shared/Results/title.css @@ -0,0 +1,3 @@ +.title { + display: flex; +} \ No newline at end of file diff --git a/frontend/app/components/shared/Results/typeToIcon.js b/frontend/app/components/shared/Results/typeToIcon.js new file mode 100644 index 000000000..c6ab47093 --- /dev/null +++ b/frontend/app/components/shared/Results/typeToIcon.js @@ -0,0 +1,81 @@ +export default (label) => { + switch (label) { + case 'Start Session': + return 'play'; // start + case 'End Session': + return 'pause'; //end + case 'Get Status': + case 'Get Sessions List': + case 'Get Session Capabilites': + return 'eye'; // session + case 'Get Session Timeouts': + case 'Implicitly Wait': + case 'Set Session Timeouts': + return 'stopwatch'; + case 'Get Current URL': + case 'Open URL': + return 'event/link'; + case 'Go Back': + case 'Go Forward': + case 'Refresh': + return 'window'; //navigation + case 'Get Title': + case 'Get Current Window Handle': + case 'Switch to Window': + case 'Close Window': + case 'Get Window Handles': + case 'Switch to Frame': + case 'Switch to Parent Frame': + case 'Get Window Rect': + case 'Set Window Rect': + return 'desktop'; // window-general + case 'Maximize Window': + case 'Minimize Window': + case 'Fullscreen Window': + return 'event/resize'; //window-interactions + case 'Get Active Element': + case 'Find Element': + case 'Find Elements': + case 'Find Child Element': + case 'Find Child Elements': + case 'Is Element Selected?': + case 'Get Element Attribute': + case 'Get Element Property': + case 'Get Element Value of CSS Property': + case 'Get Element Text': + case 'Get Element Tag Name': + case 'Get Element Rect': + case 'Is Element Enabled?': + case 'Is Element Displayed?': + case 'Element Equals': + case 'Clear Element': + return 'search'; // element + case 'Click Element': + case 'Submit': + return 'event/click'; + case 'Send Keys to Element': + return 'event/input'; + case 'Execute': + case 'Get Page Source': + case 'Execute Script': + case 'Execute Async Script': + return 'code'; + case 'Get All Cookies': + case 'Get Named Cookie': + case 'Add Cookie': + case 'Delete All Cookies': + case 'Delete Named Cookie': + return 'cookies'; + case 'Dismiss Alert': + case 'Accept Alert': + case 'Get Alert Text': + case 'Send Keys to Alert': + case 'Set Alert Credentials': + return 'console/warning'; + case 'Take Screenshot': + case 'Take Element Screenshot': + return 'camera'; + default: + return 'ellipsis-v'; + } +}; diff --git a/frontend/app/components/shared/Results/videoTab.css b/frontend/app/components/shared/Results/videoTab.css new file mode 100644 index 000000000..e4866dc55 --- /dev/null +++ b/frontend/app/components/shared/Results/videoTab.css @@ -0,0 +1,4 @@ +.video { + height: calc(100vh - 266px); + width: 100%; +} \ No newline at end of file diff --git a/frontend/app/components/shared/ScheduleUpdater/ScheduleUpdater.js b/frontend/app/components/shared/ScheduleUpdater/ScheduleUpdater.js new file mode 100644 index 000000000..966648894 --- /dev/null +++ b/frontend/app/components/shared/ScheduleUpdater/ScheduleUpdater.js @@ -0,0 +1,123 @@ +import { connect } from 'react-redux'; +import { Modal, Button, Form, Dropdown, Icon } from 'UI'; +import { save as saveSchedule, edit as editSchedule } from 'Duck/schedules'; +import styles from './scheduleUpdater.css'; + +const HOURS = [ ...Array(24).keys() ].map(i => ({ value: i, text: `${ i > 9 ? '' : '0' }${ i }:00` })); + +const DAYS = [ + { + value: -1, + text: 'Everyday', + }, + { + value: 0, + text: 'Sunday', + }, + { + value: 1, + text: 'Monday', + }, + { + value: 2, + text: 'Tuesday', + }, + { + value: 3, + text: 'Wednesday', + }, + { + value: 4, + text: 'Thursday', + }, + { + value: 5, + text: 'Friday', + }, + { + value: 6, + text: 'Saturday', + }, + +]; + +@connect(state => ({ + loading: state.getIn([ 'schedules', 'saveRequest', 'loading' ]), + schedule: state.getIn([ 'schedules', 'instance' ]), +}), { saveSchedule, editSchedule }) +export default class ScheduleUpdater extends React.PureComponent { + onSave = () => { + const { onClose, schedule } = this.props; + this.props.saveSchedule(schedule) + .then(onClose); + } + + onSelectChanged = (event, { name, value }) => this.props.editSchedule({ [ name ]: value }); + write = ({ target: { name, value } }) => this.props.editSchedule({ [ name ]: value }); + + render() { + const { + onClose, + loading, + schedule, + isDisplayed = schedule.exists(), + } = this.props; + const { hour, day, name } = schedule; + + const isNew = !schedule.exists(); + + return ( + <Modal size="tiny" open={ isDisplayed }> + <Modal.Header className={ styles.modalHeader }> + <div>{'Schedule Test:'}</div> + <Icon + role="button" + tabIndex="-1" + color="gray-dark" + size="18" + name="close" + onClick={ onClose } + /> + </Modal.Header> + <Modal.Content> + <Form disabled={ loading }> + <Form.Field> + <label>{'Test Name:'}</label> + <input + className={ styles.name } + name="name" + value={ name } + onChange={ this.write } + /> + </Form.Field> + <Form.Field> + <label>{'Occurence:'}</label> + <div className={ styles.scheduleControls }> + <Dropdown + name="day" + selection + options={ DAYS } + onChange={ this.onSelectChanged } + className="customLightDropdown" + value={ day } + /> + <Dropdown + name="hour" + selection + options={ HOURS } + onChange={ this.onSelectChanged } + className="customLightDropdown" + value={ hour } + /> + </div> + </Form.Field> + </Form> + </Modal.Content> + <Modal.Actions> + <Button onClick={ onClose } basic>{ 'Cancel' }</Button> + <Button onClick={ this.onSave } primary loading={ loading }>{ isNew ? 'Add' : 'Schedule' }</Button> + </Modal.Actions> + </Modal> + ); + } +} diff --git a/frontend/app/components/shared/ScheduleUpdater/index.js b/frontend/app/components/shared/ScheduleUpdater/index.js new file mode 100644 index 000000000..c06f24f19 --- /dev/null +++ b/frontend/app/components/shared/ScheduleUpdater/index.js @@ -0,0 +1 @@ +export { default } from './ScheduleUpdater'; diff --git a/frontend/app/components/shared/ScheduleUpdater/scheduleUpdater.css b/frontend/app/components/shared/ScheduleUpdater/scheduleUpdater.css new file mode 100644 index 000000000..be71c5427 --- /dev/null +++ b/frontend/app/components/shared/ScheduleUpdater/scheduleUpdater.css @@ -0,0 +1,42 @@ +.modalHeader { + display: flex !important; + align-items: center; + justify-content: space-between; +} + + +.title, .nameTitle, .scheduleTitle { + font-family: 'Arial-BoldMT', 'Arial Bold', 'Arial'; + font-weight: 700; +} +.title { + font-size: 14px; +} +.nameTitle, .scheduleTitle { + margin-top: 20px; + margin-bottom: 10px; +} + +.name { + display:block; + text-decoration: none; + border-color: transparent; + background: $gray-lightest; + padding: 9px; + border-radius: 3px; + width: 100%; + + &:focus { + border-color: $teal !important; + } +} + +.schedule { + padding-bottom: 30px; +} + +.scheduleControls { + display: flex; + align-items: center; + justify-content: space-between; +} \ No newline at end of file diff --git a/frontend/app/components/shared/SessionItem/SessionItem.js b/frontend/app/components/shared/SessionItem/SessionItem.js new file mode 100644 index 000000000..f93aeefcf --- /dev/null +++ b/frontend/app/components/shared/SessionItem/SessionItem.js @@ -0,0 +1,124 @@ +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { + Link, + Icon, + OsIcon, + BrowserIcon, + CountryFlag, + Avatar, + TextEllipsis +} from 'UI'; +import { deviceTypeIcon } from 'App/iconNames'; +import { toggleFavorite } from 'Duck/sessions'; +import { session as sessionRoute } from 'App/routes'; +import { durationFormatted, formatTimeOrDate } from 'App/date'; +import stl from './sessionItem.css'; + +const Label = ({ label = '', color = 'color-gray-medium'}) => ( + <div className={ cn('font-light text-sm', color)}>{label}</div> +) +@connect(state => ({ + timezone: state.getIn(['sessions', 'timezone']) +}), { toggleFavorite }) +export default class SessionItem extends React.PureComponent { + state = { favouriting: false }; + + toggleFavorite = () => { + this.setState({ favouriting: true }); + this.props.toggleFavorite(this.props.session).then(() => { + this.setState({ favouriting: false }); + }); + } + + // eslint-disable-next-line complexity + render() { + const { + session: { + sessionId, + userBrowser, + userOs, + userId, + userAnonymousId, + userDisplayName, + userCountry, + startedAt, + duration, + eventsCount, + errorsCount, + pagesCount, + viewed, + favorite, + userDeviceType, + userUuid, + userNumericHash, + }, + timezone, + onUserClick, + hasUserFilter = false, + disableUser = false + } = this.props; + const formattedDuration = durationFormatted(duration); + const hasUserId = userId || userAnonymousId; + + return ( + <div className={ stl.sessionItem } id="session-item" > + <div className={ cn('flex items-center mr-auto')}> + <div className="flex items-center mr-6" style={{ width: '200px' }}> + <Avatar seed={ userNumericHash } /> + <div className="flex flex-col ml-3 overflow-hidden"> + <div + className={cn({'color-teal cursor-pointer': !disableUser && hasUserId, 'color-gray-medium' : disableUser || !hasUserId})} + onClick={() => (!disableUser && !hasUserFilter && hasUserId) && onUserClick(userId, userAnonymousId)} + > + <TextEllipsis text={ userDisplayName } noHint /> + </div> + <Label label={ formatTimeOrDate(startedAt, timezone) } /> + </div> + </div> + <div className={ cn(stl.iconStack, 'flex-1') }> + <div className={ stl.icons }> + <CountryFlag country={ userCountry } className="mr-6" /> + <BrowserIcon browser={ userBrowser } size="16" className="mr-6" /> + <OsIcon os={ userOs } size="16" className="mr-6" /> + <Icon name={ deviceTypeIcon(userDeviceType) } size="16" className="mr-6" /> + </div> + </div> + <div className="flex flex-col items-center px-4" style={{ width: '150px'}}> + <div className="text-xl">{ formattedDuration }</div> + <Label label="Duration" /> + </div> + + <div className="flex flex-col items-center px-4"> + <div className={ stl.count }>{ eventsCount }</div> + <Label label={ eventsCount === 0 || eventsCount > 1 ? 'Events' : 'Event' } /> + </div> + + </div> + + <div className="flex items-center"> + <div className="flex flex-col items-center px-4"> + <div className={ cn(stl.count, { "color-gray-medium": errorsCount === 0 }) } >{ errorsCount }</div> + <Label label="Errors" color={errorsCount > 0 ? '' : 'color-gray-medium'} /> + </div> + + <div className={ cn(stl.iconDetails, 'px-4') }> + <div + className={ stl.favoriteWrapper } + onClick={ this.toggleFavorite } + data-favourite={ favorite } + > + <Icon name={ favorite ? 'star-solid' : 'star' } size="20" /> + </div> + </div> + + <div className={ stl.playLink } id="play-button" data-viewed={ viewed }> + <Link to={ sessionRoute(sessionId) }> + <Icon name={ viewed ? 'play-fill' : 'play-circle-light' } size="30" color="teal" /> + </Link> + </div> + </div> + </div> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/SessionItem/index.js b/frontend/app/components/shared/SessionItem/index.js new file mode 100644 index 000000000..1ef29930b --- /dev/null +++ b/frontend/app/components/shared/SessionItem/index.js @@ -0,0 +1 @@ +export { default } from './SessionItem'; \ No newline at end of file diff --git a/frontend/app/components/shared/SessionItem/sessionItem.css b/frontend/app/components/shared/SessionItem/sessionItem.css new file mode 100644 index 000000000..853e70bea --- /dev/null +++ b/frontend/app/components/shared/SessionItem/sessionItem.css @@ -0,0 +1,128 @@ + +@import 'icons.css'; +@import 'mixins.css'; + +@keyframes fade { + 0% { opacity: 1} + 50% { opacity: 0} + 100% { opacity: 1} +} + +.sessionItem { + user-select: none; + @mixin defaultHover; + border-radius: 3px; + padding: 10px 10px; + padding-right: 15px; + margin-bottom: 15px; + background-color: white; + display: flex; + align-items: center; + border: solid thin #EEEEEE; + + &:hover { + & .playLink { + transition: all 0.4s; + opacity: 1; + } + + & .favoriteWrapper { + transition: all 0.4s; + opacity: 1; + } + } + + & .iconStack { + min-width: 200px; + display: flex; + & .icons { + display: flex; + flex-flow: row; + margin-bottom: 5px; + align-items: center; + } + } + + & .left { + & > div { + &[data-collapsed=true] { + height: 0; + overflow: hidden; + } + justify-content: center; + font-size: 12px; + color: $gray-medium; + font-weight: 300; + } + + & .fid { + & span { + margin-bottom: 2px; + } + & .fidLabel { + width: 100px; + overflow: hidden; + text-overflow: ellipsis; + } + } + + & .iconDetails { + flex: 2; + display: flex; + flex-flow: row; + justify-content: flex-start; + align-items: center; + } + } + + & .count { + font-size: 18px; + font-weight: 400; + } +} + +.favoriteWrapper { + cursor: pointer; + display: flex; + align-items: center; + opacity: 0; + margin: 0 15px; + + &[data-favourite=true] { + opacity: 1; + & svg { + fill: $teal; + } + } +} + +.playLink { + display: flex; + align-items: center; + transition: all 0.2s; + /* opacity: 0; */ + &[data-viewed=true] { + opacity: 1; + } + & > a { + display: flex; + align-items: center; + } +} + +.liveTag { + height: 26px; + width: 56px; + border-radius: 3px; + background-color: #42AE5E; + display: flex; + align-items: center; + justify-content: center; + color: white; + text-transform: uppercase; + font-size: 10px; + letter-spacing: 1px; + & svg { + animation: fade 1s infinite; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/SessionStack/SessionStack.js b/frontend/app/components/shared/SessionStack/SessionStack.js new file mode 100644 index 000000000..550ddb668 --- /dev/null +++ b/frontend/app/components/shared/SessionStack/SessionStack.js @@ -0,0 +1,42 @@ +import React from 'react' +import stl from './sessionStack.css' +import cn from 'classnames'; +import { Icon } from 'UI' +import { names } from 'Types/watchdog' +import { applySavedFilter, setActiveFlow } from 'Duck/filters'; +import { connect } from 'react-redux'; +import { setActiveTab } from 'Duck/sessions'; + +const IconLabel = ({ icon, label}) => ( + <div className="w-9/12 flex items-center justify-end"> + <Icon name={icon} size="20" color={label > 0 ? 'gray' : 'gray-medium'} /> + <div className={cn('ml-2 text-xl', label > 0 ? 'color-gray' : 'color-gray-medium')}>{label}</div> + </div> +) + +function SessionStack({ flow = {}, applySavedFilter, setActiveTab, setActiveFlow }) { + const onAllClick = (flow) => { + setActiveFlow(flow) + applySavedFilter(flow.filter) + setActiveTab({ type: 'all', name: 'All'}) + } + return ( + <div className={stl.wrapper}> + <div + className="text-xl mb-6 capitalize color-teal cursor-pointer" + onClick={() => onAllClick(flow)}> + {flow.name} + </div> + <div className="flex items-center"> + <div className="w-2/12 text-xl"><span className="text-3xl">{flow.count}</span> Sessions</div> + <div className="w-6/12 flex items-center ml-auto"> + {flow.watchdogs.map(({type, count}) => ( + <IconLabel key={type} icon={names[type].icon} label={count} /> + ))} + </div> + </div> + </div> + ) +} + +export default connect(null, { applySavedFilter, setActiveTab, setActiveFlow })(SessionStack) diff --git a/frontend/app/components/shared/SessionStack/index.js b/frontend/app/components/shared/SessionStack/index.js new file mode 100644 index 000000000..db3464728 --- /dev/null +++ b/frontend/app/components/shared/SessionStack/index.js @@ -0,0 +1 @@ +export { default } from './SessionStack'; \ No newline at end of file diff --git a/frontend/app/components/shared/SessionStack/sessionStack.css b/frontend/app/components/shared/SessionStack/sessionStack.css new file mode 100644 index 000000000..30b2a6eef --- /dev/null +++ b/frontend/app/components/shared/SessionStack/sessionStack.css @@ -0,0 +1,18 @@ + +@import 'mixins.css'; + +.wrapper { + background: #fff; + border: solid thin $gray-light; + border-radius: 3px; + @mixin defaultHover; + box-shadow: + /* The top layer shadow */ + /* 0 1px 1px rgba(0,0,0,0.15), */ + /* The second layer */ + 4px 4px 1px 1px white, + /* The second layer shadow */ + 4px 4px 0px 1px rgba(0,0,0,0.4); + /* Padding for demo purposes */ + padding: 16px; +} \ No newline at end of file diff --git a/frontend/app/components/shared/SharePopup/SharePopup.js b/frontend/app/components/shared/SharePopup/SharePopup.js new file mode 100644 index 000000000..845229034 --- /dev/null +++ b/frontend/app/components/shared/SharePopup/SharePopup.js @@ -0,0 +1,116 @@ +import { connect } from 'react-redux'; +import { toast } from 'react-toastify'; +import withRequest from 'HOCs/withRequest'; +import { Popup, Dropdown, Icon, IconButton } from 'UI'; +import { pause } from 'Player'; +import styles from './sharePopup.css'; + +@connect(state => ({ + channels: state.getIn([ 'slack', 'list' ]), + tenantId: state.getIn([ 'user', 'client', 'tenantId' ]), +})) +@withRequest({ + endpoint: ({ id, entity }, integrationId) => + `/integrations/slack/notify/${ integrationId }/${entity}/${ id }`, + method: "POST", +}) +export default class SharePopup extends React.PureComponent { + state = { + comment: '', + isOpen: false, + channelId: this.props.channels.getIn([ 0, 'id' ]), + } + + editMessage = e => this.setState({ comment: e.target.value }) + share = () => this.props.request({ comment: this.state.comment }, this.state.channelId) + .then(this.handleSuccess) + + handleOpen = () => { + this.setState({ isOpen: true }); + pause(); + setTimeout(function() { + document.getElementById('message').focus(); + }, 100) + } + + handleClose = () => { + this.setState({ isOpen: false, comment: '' }); + } + + handleSuccess = () => { + toast.success('Your comment is shared.'); + this.handleClose(); + } + + changeChannel = (e, { value }) => this.setState({ channelId: value }) + + render() { + const { trigger, loading, channels, tenantId } = this.props; + const { comment, isOpen, channelId } = this.state; + + const options = channels.map(({ id, name }) => ({ value: id, text: name })).toJS(); + return ( + <Popup + open={ isOpen } + onOpen={ this.handleOpen } + onClose={ this.handleClose } + trigger={ trigger } + content={ + <div className={ styles.wrapper }> + <div className={ styles.header }> + <div className={ styles.title }>{ 'Comment' }</div> + </div> + { options.length === 0 ? + <div className={ styles.body }> + <a + href={ `https://slack.com/oauth/authorize?client_id=252578014882.345694377157&scope=incoming-webhook&state=${ tenantId }` } + target="_blank" + > + <IconButton className="my-auto mt-2 mb-2" icon="integrations/slack" label="Integrate Slack" /> + </a> + </div> + : + <div> + <div className={ styles.body }> + <textarea + name="message" + id="message" + cols="30" + rows="6" + resize="none" + onChange={ this.editMessage } + value={ comment } + placeholder="Type here..." + className="p-4" + /> + </div> + <div className={ styles.footer }> + <Dropdown + selection + options={ options } + value={ channelId } + onChange={ this.changeChannel } + className="mr-4" + /> + <div> + <button + className={ styles.shareButton } + onClick={ this.share } + > + <Icon name="integrations/slack" size="18" marginRight="10" /> + { loading ? 'Sharing...' : 'Share' } + </button> + </div> + </div> + </div> + } + </div> + } + on="click" + position="top center" + className={ styles.popup } + hideOnScroll + /> + ); + } +} diff --git a/frontend/app/components/shared/SharePopup/index.js b/frontend/app/components/shared/SharePopup/index.js new file mode 100644 index 000000000..6eb4fe8a8 --- /dev/null +++ b/frontend/app/components/shared/SharePopup/index.js @@ -0,0 +1 @@ +export { default } from './SharePopup'; \ No newline at end of file diff --git a/frontend/app/components/shared/SharePopup/sharePopup.css b/frontend/app/components/shared/SharePopup/sharePopup.css new file mode 100644 index 000000000..adbc29ff8 --- /dev/null +++ b/frontend/app/components/shared/SharePopup/sharePopup.css @@ -0,0 +1,93 @@ + +@import 'icons.css'; + +.popup { + border-radius: 3px; + box-shadow: 0px 1px 3px 0 $gray-light; +} + +.wrapper { + background-color: white; + width: 350px; +} + +.header { + display: flex; + align-items: center; + padding-bottom: 10px; +} + +.title { + margin-right: auto; + font-weight: bold; +} + +.closeButton { + @mixin icon close, $gray-light; + width: 20px; + height: 20px; + cursor: pointer; +} + +.body { + & textarea { + border: solid thin $gray-light; + border-radius: 3px; + resize: none; + } +} + +.footer { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 0; +} + +textarea { + width: 100%; + background-color: $gray-lightest; + border: none; + padding: 10px; +} + +.shreButtons { + display: flex; + align-items: center; + margin-right: auto; +} + +.icon { + margin: 0 8px; + &:first-child { + margin-left: 0; + } +} + +$iconsize: 30px; +.slack { + @mixin icon social/slack, $teal; + width: $iconsize; + height: $iconsize; +} + +.trello { + @mixin icon social/trello, $teal; + width: $iconsize; + height: $iconsize; +} + +.shareButton { + display: flex; + align-items: center; + box-shadow: 0px 1px 3px 0 $gray-light; + border: solid thin transparent; + padding: 10px 15px; + border-radius: 3px; + cursor: pointer; + color: $teal; + &:hover { + background-color: $active-blue; + border-color: $active-blue-border; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/SiteDropdown/SiteDropdown.js b/frontend/app/components/shared/SiteDropdown/SiteDropdown.js new file mode 100644 index 000000000..b83178512 --- /dev/null +++ b/frontend/app/components/shared/SiteDropdown/SiteDropdown.js @@ -0,0 +1,21 @@ +import { connect } from 'react-redux'; +import { Select } from 'UI'; + +const SiteDropdown = ({ contextName="", sites, onChange, value }) => { + const options = sites.map(site => ({ value: site.id, text: site.host })).toJS(); + return ( + <Select + name={ `${ contextName }_site` } + placeholder="Select Site" + options={ options } + value={ value } + onChange={ onChange } + /> + ); +} + +SiteDropdown.displayName = "SiteDropdown"; + +export default connect(state => ({ + sites: state.getIn([ 'user', 'client', 'sites' ]), +}))(SiteDropdown); \ No newline at end of file diff --git a/frontend/app/components/shared/SiteDropdown/index.js b/frontend/app/components/shared/SiteDropdown/index.js new file mode 100644 index 000000000..09178f5cf --- /dev/null +++ b/frontend/app/components/shared/SiteDropdown/index.js @@ -0,0 +1 @@ +export { default } from './SiteDropdown'; \ No newline at end of file diff --git a/frontend/app/components/shared/ToggleContent/ToggleContent.js b/frontend/app/components/shared/ToggleContent/ToggleContent.js new file mode 100644 index 000000000..36400f9e7 --- /dev/null +++ b/frontend/app/components/shared/ToggleContent/ToggleContent.js @@ -0,0 +1,24 @@ +import React, { useState } from 'react' +import { Slider } from 'UI' + +function ToggleContent({ label = '', first, second }) { + const [switched, setSwitched] = useState(true) + return ( + <div> + <div className="flex items-center cursor-pointer mb-4"> + <div className="mr-2" onClick={() => setSwitched(!switched)}>{ label }</div> + <Slider + name="sessionsLive" + onChange={ () => setSwitched(!switched) } + checked={ !switched } + style={{ lineHeight: '23px' }} + /> + </div> + <div> + { switched ? first : second } + </div> + </div> + ) +} + +export default ToggleContent diff --git a/frontend/app/components/shared/ToggleContent/index.js b/frontend/app/components/shared/ToggleContent/index.js new file mode 100644 index 000000000..7882ec314 --- /dev/null +++ b/frontend/app/components/shared/ToggleContent/index.js @@ -0,0 +1 @@ +export { default } from './ToggleContent' \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/CopyButton/CopyButton.js b/frontend/app/components/shared/TrackingCodeModal/CopyButton/CopyButton.js new file mode 100644 index 000000000..d080b1a02 --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/CopyButton/CopyButton.js @@ -0,0 +1,25 @@ +import React from 'react' +import { useState } from 'react'; +import copy from 'copy-to-clipboard'; + +function CopyButton({ content, className }) { + const [copied, setCopied] = useState(false) + + const copyHandler = () => { + setCopied(true); + copy(content); + setTimeout(() => { + setCopied(false); + }, 1000); + }; + return ( + <button + className={ className } + onClick={ copyHandler } + > + { copied ? 'copied' : 'copy' } + </button> + ) +} + +export default CopyButton diff --git a/frontend/app/components/shared/TrackingCodeModal/CopyButton/index.js b/frontend/app/components/shared/TrackingCodeModal/CopyButton/index.js new file mode 100644 index 000000000..a230b4ecc --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/CopyButton/index.js @@ -0,0 +1 @@ +export { default } from './CopyButton' \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/InstallDocs/InstallDocs.js b/frontend/app/components/shared/TrackingCodeModal/InstallDocs/InstallDocs.js new file mode 100644 index 000000000..6e1bb78f3 --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/InstallDocs/InstallDocs.js @@ -0,0 +1,61 @@ +import React from 'react' +import { Controlled as CodeMirror } from 'react-codemirror2' +import stl from './installDocs.css' +import cn from 'classnames' +import CopyButton from '../CopyButton'; + +const installationCommand = 'npm i @openreplay/tracker --save' +const usageCode = `import Tracker from '@openreplay/tracker'; +const tracker = new Tracker({ + projectID: PROJECT_ID +}); +tracker.start();` + +function InstallDocs({ site }) { + const _usageCode = usageCode.replace('PROJECT_ID', site.projectKeKey) + return ( + <div> + <div className="mb-3"> + <div className="font-semibold mb-2">1. Installation</div> + <div className={ cn(stl.snippetWrapper, 'bg-gray-light-shade rounded p-3') }> + <CopyButton content={installationCommand} className={cn(stl.codeCopy, 'mt-2 mr-2')} /> + <CodeMirror + value={ installationCommand } + className={ stl.snippet } + options={{ + autoCursor: false, + height: 40, + // mode: 'javascript', + theme: 'docs', + readOnly: true, + showCursorWhenSelecting: false, + scroll: false + }} + /> + </div> + </div> + <div> + <div className="font-semibold mb-2">2. Usage</div> + <div className={ cn(stl.snippetWrapper, 'bg-gray-light-shade rounded p-3') }> + <CopyButton content={_usageCode} className={cn(stl.codeCopy, 'mt-2 mr-2')} /> + <CodeMirror + value={ _usageCode } + className={ stl.snippet } + options={{ + autoCursor: false, + height: 40, + mode: 'javascript', + theme: 'docs', + readOnly: true, + showCursorWhenSelecting: false, + scroll: false + }} + /> + </div> + </div> + <div className="mt-6">See <a href="https://docs.openreplay.com/javascript-sdk" className="color-teal underline" target="_blank">Documentation</a> for the list of available options.</div> + </div> + ) +} + +export default InstallDocs \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/InstallDocs/index.js b/frontend/app/components/shared/TrackingCodeModal/InstallDocs/index.js new file mode 100644 index 000000000..854a075b6 --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/InstallDocs/index.js @@ -0,0 +1 @@ +export { default } from './InstallDocs'; \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/InstallDocs/installDocs.css b/frontend/app/components/shared/TrackingCodeModal/InstallDocs/installDocs.css new file mode 100644 index 000000000..54a935e7b --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/InstallDocs/installDocs.css @@ -0,0 +1,29 @@ +@import 'zindex.css'; + +.snippetWrapper { + position: relative; + & .codeCopy { + position: absolute; + right: 10px; + top: 10px; + z-index: $codeSnippet; + padding: 5px 10px; + color: $teal; + text-transform: uppercase; + cursor: pointer; + border-radius: 3px; + transition: all 0.4s; + user-select: none; + + &:hover { + background-color: $gray-light; + transition: all 0.2s; + } + } + & .snippet { + overflow: hidden; + line-height: 20px; + border-radius: 5px; + user-select: none; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/ProjectCodeSnippet.js b/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/ProjectCodeSnippet.js new file mode 100644 index 000000000..c585cecf4 --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/ProjectCodeSnippet.js @@ -0,0 +1,154 @@ +import React, { useState } from 'react' +import { connect } from 'react-redux'; +import { editGDPR, saveGDPR } from 'Duck/site'; +import { Controlled as CodeMirror } from 'react-codemirror2'; +import copy from 'copy-to-clipboard'; +import { Select, Checkbox } from 'UI'; +import GDPR from 'Types/site/gdpr'; +import cn from 'classnames' +import styles from './projectCodeSnippet.css' + +const inputModeOptions = [ + { text: 'Record all inputs', value: 'plain' }, + { text: 'Ignore all inputs', value: 'obscured' }, + { text: 'Obscure all inputs', value: 'hidden' }, +]; + +const codeSnippet = `<!-- OpenReplay Tracking Code for HOST --> +<script> +(function(A,s,a,y,e,r){ + r=window.OpenReplay=[s,r,e,[y-1]]; + s=document.createElement('script');s.src=a;s.async=!A; + document.getElementsByTagName('head')[0].appendChild(s); + r.start=function(v){r.push([0])}; + r.stop=function(v){r.push([1])}; + r.setUserID=r.userID=function(id){r.push([2,id])}; + r.setUserAnonymousID=r.userAnonymousID=function(id){r.push([3,id])}; + r.setMetadata=r.metadata=function(k,v){r.push([4,k,v])}; + r.event=function(k,p,i){r.push([5,k,p,i])}; + r.issue=function(k,p){r.push([6,k,p])}; + r.isActive=r.active=function(){return false}; + r.getSessionToken=r.sessionID=function(){}; +})(0,PROJECT_HASH,"//${window.location.hostname}/static/openreplay.js",1,XXX); +<script>`; + +const ProjectCodeSnippet = props => { + const { site, gdpr, saving } = props; + const [changed, setChanged] = useState(false) + const [copied, setCopied] = useState(false) + + const saveGDPR = (value) => { + setChanged(true) + props.saveGDPR(site.id, GDPR({...value})); + } + + const onChangeSelect = (event, { name, value }) => { + const { gdpr } = site; + const _gdpr = { ...gdpr.toData() }; + props.editGDPR({ [ name ]: value }); + _gdpr[name] = value; + props.editGDPR({ [ name ]: value }); + saveGDPR(_gdpr) + }; + + const onChangeOption = (event, { name, checked }) => { + const { gdpr } = props.site; + const _gdpr = { ...gdpr.toData() }; + _gdpr[name] = checked; + props.editGDPR({ [ name ]: checked }); + saveGDPR(_gdpr) + } + + const getOptionValues = () => { + const { gdpr } = props.site; + return (!!gdpr.maskEmails)|(!!gdpr.maskNumbers << 1)|(['plain' , 'obscured', 'hidden'].indexOf(gdpr.defaultInputMode) << 5)|28 + } + + + const getCodeSnippet = site => { + let snippet = codeSnippet; + if (site && site.id) { + snippet = snippet.replace('PROJECT_HASH', site.projectKey); + } + return snippet + .replace('XXX', getOptionValues()) + .replace('HOST', site && site.host); + } + + const copyHandler = (code) => { + setCopied(true); + copy(code); + setTimeout(() => { + setCopied(false); + }, 1000); + }; + + const _snippet = getCodeSnippet(site); + + return ( + <div> + <div className="mb-4"> + <div className="font-semibold mb-2">1. Choose data recording options:</div> + <div className="flex items-center justify-between"> + <Select + name="defaultInputMode" + options={ inputModeOptions } + onChange={ onChangeSelect } + placeholder="Default Input Mode" + value={ gdpr.defaultInputMode } + /> + + <Checkbox + name="maskNumbers" + type="checkbox" + checked={ gdpr.maskNumbers } + onClick={ onChangeOption } + className="mr-2" + label="Do not record any numeric text" + /> + + <Checkbox + name="maskEmails" + type="checkbox" + checked={ gdpr.maskEmails } + onClick={ onChangeOption } + className="mr-2" + label="Do not record email addresses" + /> + </div> + </div> + <div className={ cn(styles.info,'rounded bg-gray mt-2 mb-4', { 'hidden': !changed })}> + Below code snippet changes depending on the data recording options chosen. + </div> + <div className={ styles.instructions }> + <div> + <span className="font-semibold">2. Paste this snippet </span><span>{ 'before the ' } </span> + <span className={ styles.highLight }> { '</head>' } </span> + <span>{ ' tag of your page.' }</span> + </div> + <div className={ styles.siteId }>{ 'Project ID: ' } <span>{ site.projectKey }</span></div> + </div> + <div className={ styles.snippetsWrapper }> + <button className={ styles.codeCopy } onClick={ () => copyHandler(_snippet) }>{ copied ? 'copied' : 'copy' }</button> + <CodeMirror + value={ _snippet } + className={ styles.snippet } + options={{ + height: 340, + mode: 'html', + readOnly: true, + showCursorWhenSelecting: false, + scroll: false + }} + /> + </div> + <div className="mt-6">See <a href="https://docs.openreplay.com/api" className="color-teal underline" target="_blank">API</a> for more options.</div> + </div> + ) +} + +export default connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), + gdpr: state.getIn([ 'site', 'instance', 'gdpr' ]), + saving: state.getIn([ 'site', 'saveGDPR', 'loading' ]) +}), { editGDPR, saveGDPR })(ProjectCodeSnippet) diff --git a/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/index.js b/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/index.js new file mode 100644 index 000000000..d665d3825 --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/index.js @@ -0,0 +1 @@ +export { default } from './ProjectCodeSnippet'; \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/projectCodeSnippet.css b/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/projectCodeSnippet.css new file mode 100644 index 000000000..659b706fe --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/projectCodeSnippet.css @@ -0,0 +1,88 @@ + +@import 'zindex.css'; + +.modalHeader { + display: flex !important; + align-items: center; +} + +.content { + background-color: white !important; +} + +.highLight { + background-color: rgba(204, 0, 0, 0.05); + color: $red; + padding: 2px 5px; + border-radius: 3px; +} + +.snippetsWrapper { + position: relative; + & .codeCopy { + position: absolute; + right: 10px; + top: 10px; + z-index: $codeSnippet; + padding: 5px 10px; + color: $teal; + text-transform: uppercase; + cursor: pointer; + border-radius: 3px; + transition: all 0.4s; + user-select: none; + + &:hover { + background-color: $gray-light; + transition: all 0.2s; + } + } + & .snippet { + overflow: hidden; + line-height: 18px; + border-radius: 5px; + user-select: none; + & > div { + background-color: $gray-lightest !important; + } + } +} + +.siteInfo { + display: flex; + align-items: center; + margin-bottom: 10px; + + & span { + color: $teal; + } +} +.instructions { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 15px; +} + +.closeButton { + margin-left: auto; + cursor: pointer; + padding: 5px; +} + +.siteId { + font-weight: 500; + & span { + background: #f6f6f6; + border-radius: 3px; + padding: 2px 7px; + font-weight: normal; + margin-left: 4px; + border: solid thin #eee; + } +} + +.info { + padding: 5px 10px; + background-color: #ffedd1; +} \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/TrackingCodeModal.js b/frontend/app/components/shared/TrackingCodeModal/TrackingCodeModal.js new file mode 100644 index 000000000..26e2d709c --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/TrackingCodeModal.js @@ -0,0 +1,67 @@ +import React from 'react'; +import { Modal, Icon, Tabs } from 'UI'; +import styles from './trackingCodeModal.css'; +import { editGDPR, saveGDPR } from 'Duck/site'; +import { connect } from 'react-redux'; +import ProjectCodeSnippet from './ProjectCodeSnippet'; +import InstallDocs from './InstallDocs'; +import cn from 'classnames'; + +const PROJECT = 'Using Script'; +const DOCUMENTATION = 'Using NPM'; +const TABS = [ + { key: PROJECT, text: PROJECT }, + { key: DOCUMENTATION, text: DOCUMENTATION } +]; + +class TrackingCodeModal extends React.PureComponent { + state = { copied: false, changed: false, activeTab: PROJECT }; + + setActiveTab = (tab) => { + this.setState({ activeTab: tab }); + } + + renderActiveTab = () => { + const { site } = this.props; + switch (this.state.activeTab) { + case PROJECT: + return <ProjectCodeSnippet />; + case DOCUMENTATION: + return <InstallDocs site={site} />; + } + return null; + } + + render() { + const { site, displayed, onClose, title = '', subTitle } = this.props; + const { activeTab } = this.state; + return ( + displayed && + <Modal size="small" onClose={ onClose } open={ displayed } style={{ top: "85px" }} > + <Modal.Header className={ styles.modalHeader }> + <div>{ title } { subTitle && <span className="text-sm color-gray-dark">{subTitle}</span>}</div> + <div className={ cn(styles.closeButton, { 'hidden' : !onClose }) } role="button" tabIndex="-1" onClick={ onClose }> + <Icon name="close" size="16" /> + </div> + </Modal.Header> + <Modal.Content className={ styles.content }> + <Tabs + className="px-5" + tabs={ TABS } + active={ activeTab } onClick={ this.setActiveTab } /> + <div className="p-5"> + { this.renderActiveTab() } + </div> + </Modal.Content> + </Modal> + ); + } +} + +export default connect(state => ({ + site: state.getIn([ 'site', 'instance' ]), + gdpr: state.getIn([ 'site', 'instance', 'gdpr' ]), + saving: state.getIn([ 'site', 'saveGDPR', 'loading' ]), +}), { + editGDPR, saveGDPR +})(TrackingCodeModal); \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/index.js b/frontend/app/components/shared/TrackingCodeModal/index.js new file mode 100644 index 000000000..6cd9cae99 --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/index.js @@ -0,0 +1 @@ +export { default } from './TrackingCodeModal'; \ No newline at end of file diff --git a/frontend/app/components/shared/TrackingCodeModal/trackingCodeModal.css b/frontend/app/components/shared/TrackingCodeModal/trackingCodeModal.css new file mode 100644 index 000000000..805329b16 --- /dev/null +++ b/frontend/app/components/shared/TrackingCodeModal/trackingCodeModal.css @@ -0,0 +1,20 @@ + +@import 'zindex.css'; + +.modalHeader { + display: flex !important; + align-items: center; +} + +.content { + background-color: white !important; + padding: 0 !important; +} + + +.closeButton { + margin-left: auto; + cursor: pointer; + padding: 5px; +} + diff --git a/frontend/app/components/shared/WidgetAutoComplete/WidgetAutoComplete.js b/frontend/app/components/shared/WidgetAutoComplete/WidgetAutoComplete.js new file mode 100644 index 000000000..1b4b81daf --- /dev/null +++ b/frontend/app/components/shared/WidgetAutoComplete/WidgetAutoComplete.js @@ -0,0 +1,86 @@ +import React, { useState } from 'react'; +import { Icon, CircularLoader, Button, TextEllipsis } from 'UI'; +import cn from 'classnames'; +import stl from './widgetAutoComplete.css'; +import { debounce } from 'App/utils'; + +const WidgetAutoComplete = props => { + const { className, placeholder = "Search for Resource", itemStyle = {}, filterParams = {} } = props; + const [selected, setSelected] = useState(null) + const [focused, setFocused] = useState(props.autoFocus) + + const fetchOptions = debounce(props.fetchOptions, 300) + + const handleChange = ({ target: { name, value } }) => { + fetchOptions({ ...filterParams, q: value }); + } + + const onSelected = opt => { + setSelected(opt); + props.onSelect(opt); + } + + const onItemClick = (e, { name, value }) => { + props.onSelect({ url: value }); + setSelected(value); + } + + const onClearHandle = (e) => { + e.preventDefault(); + e.stopPropagation(); + + setSelected(null); + props.onSelect({}); + } + + return ( + <div className={ cn("flex items-center relative", className)}> + <div + className={cn(stl.searchWrapper, 'flex items-center relative', { 'bg-gray-light' : focused })} + onClick={() => !focused && setFocused(true)} + > + { !focused && selected && ( + <div className={cn(stl.selected, 'flex items-center justify-between')}> + <span>{selected.value}</span> + <Button plain onClick={onClearHandle}><Icon name="close" size="14"/></Button> + </div> + )} + { (focused || !selected) && ( + <input + autoFocus={focused} + type="text" + className={cn( + stl.search, + 'absolute inset-0 w-full py-2 active:outline-none focus:outline-none mr-2', + { 'focused': focused } + )} + placeholder={placeholder} + onChange={handleChange} + onFocus={() => setFocused(true)} + onBlur={() => setFocused(false)} + /> + )} + <div className="absolute right-0 mr-2"> + { props.loading && <CircularLoader loading={ true } /> } + </div> + </div> + { focused && props.options.length > 0 && ( + <div className={cn(stl.menuWrapper, 'absolute top-10 left-0 rounded bg-white')}> + { + props.options.map(opt => ( + <div + className={cn(stl.optionItem)} + onMouseDown={() => onSelected(opt)} + style={itemStyle} + > + {opt.text || opt.value} + </div> + )) + } + </div> + )} + </div> + ) +} + +export default WidgetAutoComplete diff --git a/frontend/app/components/shared/WidgetAutoComplete/index.js b/frontend/app/components/shared/WidgetAutoComplete/index.js new file mode 100644 index 000000000..ab50b1725 --- /dev/null +++ b/frontend/app/components/shared/WidgetAutoComplete/index.js @@ -0,0 +1 @@ +export { default } from './WidgetAutoComplete'; diff --git a/frontend/app/components/shared/WidgetAutoComplete/widgetAutoComplete.css b/frontend/app/components/shared/WidgetAutoComplete/widgetAutoComplete.css new file mode 100644 index 000000000..7267dc593 --- /dev/null +++ b/frontend/app/components/shared/WidgetAutoComplete/widgetAutoComplete.css @@ -0,0 +1,84 @@ +.searchWrapper { + width: 250px; + padding: 10px 5px; + height: 30px; + border-radius: 3px; + cursor: pointer; + border: solid thin transparent; + margin: 0 -5px; + &:after { + content: ''; + width: 100%; + border-bottom: dotted thin $gray-light; + position: absolute; + right: 5px; + bottom: 0; + } + & input { + padding: 0 5px; + } + &:hover { + border: solid thin $gray-light; + &:after { + display: none; + } + } + &.focused { + background-color: $gray-light; + &:after { + display: none; + } + } +} + +.selected { + width: 100%; + & span { + max-width: 210px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.search { + padding: 8px 0; + border: none; + &:focus, &:active { + border: none !important; + } +} + +.menuWrapper { + display: flex; + flex-direction: column; + & > div { + flex-shrink: 0; + } + + border: solid thin $gray-light; + top: 31px; + z-index: 1; + margin-left: -5px; + max-height: 180px; + overflow-y: auto; + &::-webkit-scrollbar { + width: 1px; + } +} + +.optionItem { + border-bottom: solid thin $gray-light; + padding: 8px; + max-width: 250px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + &:last-child { + border-bottom: none; + } + &:hover { + background-color: $gray-lightest; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/WidgetSection/WidgetSection.js b/frontend/app/components/shared/WidgetSection/WidgetSection.js new file mode 100644 index 000000000..3893ff392 --- /dev/null +++ b/frontend/app/components/shared/WidgetSection/WidgetSection.js @@ -0,0 +1,20 @@ +import React from 'react' +import cn from 'classnames' +import AddWidgets from '../AddWidgets'; + +function WidgetSection({ className, title, children, description, type }) { + return ( + <div className={cn(className, 'rounded p-4 bg-gray-light-shade')}> + <div className="mb-4 flex items-center"> + <div className="flex items-center"> + <div className="text-2xl mr-3">{title}</div> + <AddWidgets type={type} /> + </div> + {description && <div className="ml-auto color-gray-darkest font-medium text-sm">{description}</div> } + </div> + { children } + </div> + ) +} + +export default WidgetSection diff --git a/frontend/app/components/shared/WidgetSection/index.js b/frontend/app/components/shared/WidgetSection/index.js new file mode 100644 index 000000000..13f279e4e --- /dev/null +++ b/frontend/app/components/shared/WidgetSection/index.js @@ -0,0 +1 @@ +export { default as WidgetSection } from './WidgetSection'; diff --git a/frontend/app/components/shared/addWidgets.css b/frontend/app/components/shared/addWidgets.css new file mode 100644 index 000000000..452ee92b7 --- /dev/null +++ b/frontend/app/components/shared/addWidgets.css @@ -0,0 +1,48 @@ +.widgetCard { + min-height: 110px; + padding: 15px; + width: 100%; + border: 1px solid $gray-light; + border-bottom: none; + + &:last-child { + border-bottom: 1px solid $gray-light; + } + & h4 { + margin-bottom: 10px; + } + & p { + color: $gray-medium; + font-weight: 300; + font-size: 12px; + } +} + +.thumb { + border: solid thin $gray-light; + margin-right: 10px; + width: 170px; +} + +.menuWrapper { + max-height: 300px; + overflow-y: auto; + &::-webkit-scrollbar { + width: 2px; + } +} + +.menuItem { + transition: all .2s; + border-bottom: solid thin $gray-light; + padding: 8px 10px; + overflow: hidden; + text-overflow: ellipsis; + &:last-child { + border-bottom: none; + } + &:hover { + transition: all .4s; + background-color: $gray-lightest; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/shared.stories.js b/frontend/app/components/shared/shared.stories.js new file mode 100644 index 000000000..1d08da8d9 --- /dev/null +++ b/frontend/app/components/shared/shared.stories.js @@ -0,0 +1,32 @@ +import { storiesOf } from '@storybook/react'; +import ResultTimings from './ResultTimings'; + +const timing = [ + { "name": "connectStart", "value": 1602181968963 }, + { "name": "navigationStart", "value": 1602181965923 }, + { "name": "loadEventEnd", "value": 1602181993795 }, + { "name": "domLoading", "value": 1602181971233 }, + { "name": "secureConnectionStart", "value": 1602181969010 }, + { "name": "fetchStart", "value": 1602181965976 }, + { "name": "domContentLoadedEventStart", "value": 1602181980930 }, + { "name": "responseStart", "value": 1602181970432 }, + { "name": "responseEnd", "value": 1602181970763 }, + { "name": "domInteractive", "value": 1602181980930 }, + { "name": "domainLookupEnd", "value": 1602181968963 }, + { "name": "redirectStart", "value": 0 }, + { "name": "requestStart", "value": 1602181969932 }, + { "name": "unloadEventEnd", "value": 0 }, + { "name": "unloadEventStart", "value": 0 }, + { "name": "domComplete", "value": 1602181993794 }, + { "name": "domainLookupStart", "value": 1602181968871 }, + { "name": "loadEventStart", "value": 1602181993794 }, + { "name": "domContentLoadedEventEnd", "value": 1602181982868 }, + { "name": "redirectEnd", "value": 0 }, + { "name": "connectEnd", "value": 1602181969783 } +]; + +storiesOf('Shared', module) + .add('ResultTimings', () => ( + <ResultTimings timing={timing} /> + )) + diff --git a/frontend/app/components/ui/Avatar/Avatar.js b/frontend/app/components/ui/Avatar/Avatar.js new file mode 100644 index 000000000..b369c5e30 --- /dev/null +++ b/frontend/app/components/ui/Avatar/Avatar.js @@ -0,0 +1,26 @@ +import React from 'react'; +import cn from 'classnames'; +import { avatarIconName } from 'App/iconNames'; +import stl from './avatar.css'; +import { Icon } from 'UI'; + +const ICON_LIST = ['icn_chameleon', 'icn_fox', 'icn_gorilla', 'icn_hippo', 'icn_horse', 'icn_hyena', +'icn_kangaroo', 'icn_lemur', 'icn_mammel', 'icn_monkey', 'icn_moose', 'icn_panda', +'icn_penguin', 'icn_porcupine', 'icn_quail', 'icn_rabbit', 'icn_rhino', 'icn_sea_horse', +'icn_sheep', 'icn_snake', 'icn_squirrel', 'icn_tapir', 'icn_turtle', 'icn_vulture', +'icn_wild1', 'icn_wild_bore'] + + +const Avatar = ({ className, width = "38px", height = "38px", iconSize = 26, seed }) => { + var iconName = avatarIconName(seed); + return ( + <div + className={ cn(stl.wrapper, "p-2 border flex items-center justify-center rounded-full")} + style={{ width, height }} + > + <Icon name={iconName} size={iconSize} color="tealx"/> + </div> + ); +}; + +export default Avatar; diff --git a/frontend/app/components/ui/Avatar/avatar.css b/frontend/app/components/ui/Avatar/avatar.css new file mode 100644 index 000000000..5948cb4d3 --- /dev/null +++ b/frontend/app/components/ui/Avatar/avatar.css @@ -0,0 +1,5 @@ +.wrapper { + background-color: rgba(62, 170, 175, 0.3); + border: none; + flex-shrink: 0; +} \ No newline at end of file diff --git a/frontend/app/components/ui/Avatar/index.js b/frontend/app/components/ui/Avatar/index.js new file mode 100644 index 000000000..01179471b --- /dev/null +++ b/frontend/app/components/ui/Avatar/index.js @@ -0,0 +1 @@ +export { default } from './Avatar'; \ No newline at end of file diff --git a/frontend/app/components/ui/BackLink/BackLink.js b/frontend/app/components/ui/BackLink/BackLink.js new file mode 100644 index 000000000..db47ae93f --- /dev/null +++ b/frontend/app/components/ui/BackLink/BackLink.js @@ -0,0 +1,31 @@ +import { Link, Icon } from 'UI'; +import cls from './backLink.css'; +import cn from 'classnames'; + +export default function BackLink ({ + className, to, onClick, label, vertical = false, style +}) { + const children = ( + <div className={ cn('flex items-center', {'border w-10 h-10 rounded-full bg-white p-3 items-center justify-center' : !label })}> + <Icon color="gray-dark" className={ cls.icon } name="prev1" size="16" /> + { label && <div className="ml-1">{ label }</div> } + </div> + ); + const verticalClassName = cn(className, cls.backLink, "flex justify-center items-center pr-4 color-gray-dark", { "flex-col": vertical }); + return to ? + <Link + className={ verticalClassName } + to={ to } + > + { children } + </Link> + : + <button + className={ verticalClassName } + onClick={ onClick } + style={style} + > + { children } + </button> +} + diff --git a/frontend/app/components/ui/BackLink/BackLink.stories.js b/frontend/app/components/ui/BackLink/BackLink.stories.js new file mode 100644 index 000000000..497cd8343 --- /dev/null +++ b/frontend/app/components/ui/BackLink/BackLink.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import BackLink from '.'; + +storiesOf('BackLink', module) + .add('Pure', () => ( + <BackLink /> + )) + diff --git a/frontend/app/components/ui/BackLink/backLink.css b/frontend/app/components/ui/BackLink/backLink.css new file mode 100644 index 000000000..d62b256b4 --- /dev/null +++ b/frontend/app/components/ui/BackLink/backLink.css @@ -0,0 +1,6 @@ +.backLink:hover { + color: $teal; + & .icon { + fill: $teal; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/BackLink/index.js b/frontend/app/components/ui/BackLink/index.js new file mode 100644 index 000000000..cae0cab87 --- /dev/null +++ b/frontend/app/components/ui/BackLink/index.js @@ -0,0 +1 @@ +export { default } from './BackLink'; diff --git a/frontend/app/components/ui/Button/Button.js b/frontend/app/components/ui/Button/Button.js new file mode 100644 index 000000000..7f2579114 --- /dev/null +++ b/frontend/app/components/ui/Button/Button.js @@ -0,0 +1,36 @@ +import { Button } from 'semantic-ui-react'; +import classnames from 'classnames'; +import styles from './button.css'; + +export default ({ + className, + size = '', + primary, + outline, + plain = false, + marginRight = false, + hover = false, + noPadding = false, + success = false, + error = false, + minWidth, + ...props +}) => ( + <Button + { ...props } + style={{ minWidth: minWidth }} + className={ classnames( + className, + size, + styles[ plain ? 'plain' : '' ], + styles[ hover ? 'hover' : '' ], + styles.button, + styles[ primary ? 'primary' : '' ], + styles[ outline ? 'outline' : '' ], + styles[ noPadding ? 'no-padding' : '' ], + styles[ success ? 'success' : '' ], + styles[ error ? 'error' : '' ], + styles[ marginRight ? 'margin-right' : '' ], + ) } + /> +); diff --git a/frontend/app/components/ui/Button/Button.stories.js b/frontend/app/components/ui/Button/Button.stories.js new file mode 100644 index 000000000..e5296ffd7 --- /dev/null +++ b/frontend/app/components/ui/Button/Button.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Button from '.'; + +storiesOf('Button', module) + .add('Pure', () => ( + <Button /> + )) + diff --git a/frontend/app/components/ui/Button/button.css b/frontend/app/components/ui/Button/button.css new file mode 100644 index 000000000..42fbffcfe --- /dev/null +++ b/frontend/app/components/ui/Button/button.css @@ -0,0 +1,84 @@ +.button { + background-color: white !important; + border-radius: 3px !important; + font-family: 'Roboto' !important; + font-weight: 400 !important; + font-size: 14px !important; + height: 38px; + + &.medium { + height: 38px; + } +} + +/* .small { + height: 33px !important; +} + +.smallest { + height: 26px !important; + font-size: 12px !important; +} */ + +.primary { + background-color: $teal !important; + box-shadow: 0 0 0 1px $teal inset !important; + color: #FFF !important; + transition: all 0.2s; + &:hover { + background-color: $teal-dark !important; + transition: all 0.2s; + box-shadow: 0 0 0 1px $teal-dark inset !important; + } +} + +.outline { + background-color: white !important; + box-shadow: 0 0 0 1px $teal inset !important; + color: $teal !important; + transition: all 0.2s; + &:hover { + background-color: $active-blue !important; + transition: all 0.2s; + } + &.disabled { + color: red !important; + } +} + +.plain { + background-color: transparent !important; + color: $teal !important; + box-shadow: none !important; + padding: 0 10px !important; + + &:hover { + background-color: transparent !important; + color: $teal-dark !important; + } + + &.hover:hover { + background-color: $gray-light !important; + } +} + +.margin-right { + margin-right: 10px !important; +} + +.no-padding { + padding: 0 !important; + margin: 0 !important; +} + +.success { + background-color: #E9F9ED !important; + color: #21BA45 !important; + border: solid thin #21BA45 !important; +} + +.error { + background-color: #FFF2F2 !important; + color: #CC0000 !important; + border: solid thin red !important; +} \ No newline at end of file diff --git a/frontend/app/components/ui/Button/index.js b/frontend/app/components/ui/Button/index.js new file mode 100644 index 000000000..efe8c800c --- /dev/null +++ b/frontend/app/components/ui/Button/index.js @@ -0,0 +1 @@ +export { default } from './Button'; diff --git a/frontend/app/components/ui/Checkbox/Checkbox.js b/frontend/app/components/ui/Checkbox/Checkbox.js new file mode 100644 index 000000000..93b3ff759 --- /dev/null +++ b/frontend/app/components/ui/Checkbox/Checkbox.js @@ -0,0 +1,8 @@ +import { Checkbox } from 'semantic-ui-react'; + +export default ({ className = '', ...props }) => ( + <Checkbox + className={`${ className } customCheckbox`} + { ...props } + /> +); \ No newline at end of file diff --git a/frontend/app/components/ui/Checkbox/Checkbox.stories.js b/frontend/app/components/ui/Checkbox/Checkbox.stories.js new file mode 100644 index 000000000..8c08cb954 --- /dev/null +++ b/frontend/app/components/ui/Checkbox/Checkbox.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Checkbox from '.'; + +storiesOf('Checkbox', module) + .add('Pure', () => ( + <Checkbox /> + )) + diff --git a/frontend/app/components/ui/Checkbox/index.js b/frontend/app/components/ui/Checkbox/index.js new file mode 100644 index 000000000..6fb014c8a --- /dev/null +++ b/frontend/app/components/ui/Checkbox/index.js @@ -0,0 +1 @@ +export { default } from './Checkbox'; \ No newline at end of file diff --git a/frontend/app/components/ui/CircularLoader/CircularLoader.js b/frontend/app/components/ui/CircularLoader/CircularLoader.js new file mode 100644 index 000000000..06d471263 --- /dev/null +++ b/frontend/app/components/ui/CircularLoader/CircularLoader.js @@ -0,0 +1,5 @@ +import { Loader } from 'semantic-ui-react'; + +export default ({ children = null, loading = true, size = 'tiny', ...props }) => (!loading ? children : + <Loader size={ size } active={ loading } inline { ...props } /> +) \ No newline at end of file diff --git a/frontend/app/components/ui/CircularLoader/CircularLoader.stories.js b/frontend/app/components/ui/CircularLoader/CircularLoader.stories.js new file mode 100644 index 000000000..e835c3d86 --- /dev/null +++ b/frontend/app/components/ui/CircularLoader/CircularLoader.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import CircularLoader from '.'; + +storiesOf('CircularLoader', module) + .add('Pure', () => ( + <CircularLoader /> + )) + diff --git a/frontend/app/components/ui/CircularLoader/index.js b/frontend/app/components/ui/CircularLoader/index.js new file mode 100644 index 000000000..6aa48c09e --- /dev/null +++ b/frontend/app/components/ui/CircularLoader/index.js @@ -0,0 +1 @@ +export { default } from './CircularLoader'; \ No newline at end of file diff --git a/frontend/app/components/ui/CloseButton/CloseButton.js b/frontend/app/components/ui/CloseButton/CloseButton.js new file mode 100644 index 000000000..0d33f03f2 --- /dev/null +++ b/frontend/app/components/ui/CloseButton/CloseButton.js @@ -0,0 +1,9 @@ +import { Icon } from 'UI'; + +export default function CloseButton({ size, onClick, className = '', style }){ + return ( + <button onClick={ onClick } className={ `${ className } cursor-pointer` } style={ style } > + <Icon name="close" size={ size } color="gray-medium"/> + </button> + ); +} diff --git a/frontend/app/components/ui/CloseButton/CloseButton.stories.js b/frontend/app/components/ui/CloseButton/CloseButton.stories.js new file mode 100644 index 000000000..b6cdd8645 --- /dev/null +++ b/frontend/app/components/ui/CloseButton/CloseButton.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import CloseButton from '.'; + +storiesOf('CloseButton', module) + .add('Pure', () => ( + <CloseButton /> + )) + diff --git a/frontend/app/components/ui/CloseButton/index.js b/frontend/app/components/ui/CloseButton/index.js new file mode 100644 index 000000000..b879d20e8 --- /dev/null +++ b/frontend/app/components/ui/CloseButton/index.js @@ -0,0 +1 @@ +export { default } from './CloseButton'; diff --git a/frontend/app/components/ui/CodeEditor/CodeEditor.js b/frontend/app/components/ui/CodeEditor/CodeEditor.js new file mode 100644 index 000000000..43c5e579a --- /dev/null +++ b/frontend/app/components/ui/CodeEditor/CodeEditor.js @@ -0,0 +1,32 @@ +import { Controlled as CodeMirror } from 'react-codemirror2'; + +class CodeEditor extends React.PureComponent { + onBeforeChange = (editor, data, value) => { + if (typeof this.props.onChange === 'function') { + this.props.onChange(data, { value, name: this.props.name }); + } + } + + render() { + const { lineNumbers = false, onChange, disabled = false, ...props } = this.props; + return ( + <CodeMirror + options={ { + mode: 'javascript', + theme: 'yeti', + lineNumbers, + lint: { esversion: 9 }, + gutters: [ 'CodeMirror-lint-markers' ], + readOnly: disabled, + } } + disabled="true" + onBeforeChange={ this.onBeforeChange } + { ...props } + /> + ); + } +} + +CodeEditor.displayName = "CodeEditor"; + +export default CodeEditor; \ No newline at end of file diff --git a/frontend/app/components/ui/CodeEditor/CodeEditor.stories.js b/frontend/app/components/ui/CodeEditor/CodeEditor.stories.js new file mode 100644 index 000000000..1ca34d4d1 --- /dev/null +++ b/frontend/app/components/ui/CodeEditor/CodeEditor.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import CodeEditor from '.'; + +storiesOf('CodeEditor', module) + .add('Pure', () => ( + <CodeEditor /> + )) + diff --git a/frontend/app/components/ui/CodeEditor/index.js b/frontend/app/components/ui/CodeEditor/index.js new file mode 100644 index 000000000..64b3b3a38 --- /dev/null +++ b/frontend/app/components/ui/CodeEditor/index.js @@ -0,0 +1 @@ +export { default } from './CodeEditor'; \ No newline at end of file diff --git a/frontend/app/components/ui/Confirmation/Confirmation.js b/frontend/app/components/ui/Confirmation/Confirmation.js new file mode 100644 index 000000000..d791b7fe2 --- /dev/null +++ b/frontend/app/components/ui/Confirmation/Confirmation.js @@ -0,0 +1,33 @@ +import React from 'react'; +import { Button} from 'UI'; +import { confirmable } from 'react-confirm'; +import { Confirm } from 'semantic-ui-react'; +import stl from './confirmation.css'; + +const Confirmation = ({ + show, + proceed, + header = 'Confirm', + confirmation = 'Are you sure?', + cancelButton = "Cancel", + confirmButton = "Proceed", + options +}) => { + return ( + <Confirm + dimmer + centered={false} + open={show} + size="mini" + content={confirmation} + header={header} + className="confirmCustom" + confirmButton={<Button size="small" id="confirm-button" primary>{ confirmButton }</Button>} + cancelButton={<Button size="small" id="cancel-button" plain className={ stl.cancelButton }>{ cancelButton }</Button>} + onCancel={() => proceed(false)} + onConfirm={() => proceed(true)} + /> + ) +} + +export default confirmable(Confirmation); \ No newline at end of file diff --git a/frontend/app/components/ui/Confirmation/confirmation.css b/frontend/app/components/ui/Confirmation/confirmation.css new file mode 100644 index 000000000..e5525838f --- /dev/null +++ b/frontend/app/components/ui/Confirmation/confirmation.css @@ -0,0 +1,5 @@ +@import 'mixins.css'; + +.cancelButton { + @mixin plainButton; +} \ No newline at end of file diff --git a/frontend/app/components/ui/Confirmation/index.js b/frontend/app/components/ui/Confirmation/index.js new file mode 100644 index 000000000..298ef242b --- /dev/null +++ b/frontend/app/components/ui/Confirmation/index.js @@ -0,0 +1,7 @@ +import { createConfirmation } from 'react-confirm'; +import Confirmation from './Confirmation'; + +// create confirm function +export const confirm = createConfirmation(Confirmation); + +// export { default } from './Confirmation'; \ No newline at end of file diff --git a/frontend/app/components/ui/CountryFlag/CountryFlag.js b/frontend/app/components/ui/CountryFlag/CountryFlag.js new file mode 100644 index 000000000..0ba14c967 --- /dev/null +++ b/frontend/app/components/ui/CountryFlag/CountryFlag.js @@ -0,0 +1,25 @@ +import cn from 'classnames'; +import { countries } from 'App/constants'; +import { Popup } from 'UI'; +import stl from './countryFlag.css'; + +const CountryFlag = ({ country, className }) => { + const knownCountry = !!country && country !== 'UN'; + const countryFlag = knownCountry ? country.toLowerCase() : ''; + const countryName = knownCountry ? countries[ country ] : 'Unknown Country'; + return ( + <Popup + trigger={ knownCountry + ? <span className={ cn(`flag flag-${ countryFlag }`, className, stl.default) } /> + : <span className={ className } >{ "N/A" }</span> + } + content={ countryName } + inverted + size="tiny" + /> + ); +} + +CountryFlag.displayName = "CountryFlag"; + +export default CountryFlag; \ No newline at end of file diff --git a/frontend/app/components/ui/CountryFlag/countryFlag.css b/frontend/app/components/ui/CountryFlag/countryFlag.css new file mode 100644 index 000000000..29a5d880b --- /dev/null +++ b/frontend/app/components/ui/CountryFlag/countryFlag.css @@ -0,0 +1,4 @@ +.default { + width: 22px !important; + height: 14px !important; +} \ No newline at end of file diff --git a/frontend/app/components/ui/CountryFlag/index.js b/frontend/app/components/ui/CountryFlag/index.js new file mode 100644 index 000000000..b1a61de93 --- /dev/null +++ b/frontend/app/components/ui/CountryFlag/index.js @@ -0,0 +1 @@ +export { default } from './CountryFlag'; \ No newline at end of file diff --git a/frontend/app/components/ui/Dropdown/Dropdown.js b/frontend/app/components/ui/Dropdown/Dropdown.js new file mode 100644 index 000000000..99150b5d1 --- /dev/null +++ b/frontend/app/components/ui/Dropdown/Dropdown.js @@ -0,0 +1,7 @@ +import { Dropdown } from 'semantic-ui-react'; + +export default props => ( + <Dropdown + { ...props } + /> +); diff --git a/frontend/app/components/ui/Dropdown/Dropdown.stories.js b/frontend/app/components/ui/Dropdown/Dropdown.stories.js new file mode 100644 index 000000000..335d9056d --- /dev/null +++ b/frontend/app/components/ui/Dropdown/Dropdown.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Dropdown from '.'; + +storiesOf('Dropdown', module) + .add('Pure', () => ( + <Dropdown /> + )) + diff --git a/frontend/app/components/ui/Dropdown/index.js b/frontend/app/components/ui/Dropdown/index.js new file mode 100644 index 000000000..0179bfccc --- /dev/null +++ b/frontend/app/components/ui/Dropdown/index.js @@ -0,0 +1 @@ +export { default } from './Dropdown'; \ No newline at end of file diff --git a/frontend/app/components/ui/DropdownPlain/DropdownPlain.js b/frontend/app/components/ui/DropdownPlain/DropdownPlain.js new file mode 100644 index 000000000..389b75b93 --- /dev/null +++ b/frontend/app/components/ui/DropdownPlain/DropdownPlain.js @@ -0,0 +1,32 @@ +import React from 'react' +import { Dropdown } from 'semantic-ui-react' +import { Icon } from 'UI'; +import stl from './dropdownPlain.css' + +const sessionSortOptions = { + 'latest': 'Newest', + 'editedAt': 'Last Modified' +}; +const sortOptions = Object.entries(sessionSortOptions) + .map(([ value, text ]) => ({ value, text })); + +function DropdownPlain({ name, label, options, onChange, defaultValue, wrapperStyle = {}, disabled = false }) { + return ( + <div className="flex items-center" style={wrapperStyle}> + { label && <span className="mr-2 color-gray-medium">{label}</span> } + <Dropdown + name={name} + className={ stl.dropdown } + // pointing="top right" + options={ options } + onChange={ onChange } + defaultValue={ defaultValue || options[ 0 ].value } + icon={null} + disabled={disabled} + icon={ <Icon name="chevron-down" color="gray-dark" size="14" className={stl.dropdownIcon} /> } + /> + </div> + ) +} + +export default DropdownPlain diff --git a/frontend/app/components/ui/DropdownPlain/dropdownPlain.css b/frontend/app/components/ui/DropdownPlain/dropdownPlain.css new file mode 100644 index 000000000..87e26bc68 --- /dev/null +++ b/frontend/app/components/ui/DropdownPlain/dropdownPlain.css @@ -0,0 +1,23 @@ +.dropdown { + display: flex !important; + padding: 4px 6px; + border-radius: 3px; + color: $gray-darkest; + font-weight: 500; + &:hover { + background-color: $gray-light; + } +} + +.dropdownTrigger { + padding: 4px 8px; + border-radius: 3px; + &:hover { + background-color: $gray-light; + } +} + +.dropdownIcon { + margin-top: 2px; + margin-left: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/ui/DropdownPlain/index.js b/frontend/app/components/ui/DropdownPlain/index.js new file mode 100644 index 000000000..e7c8ecebf --- /dev/null +++ b/frontend/app/components/ui/DropdownPlain/index.js @@ -0,0 +1 @@ +export { default } from './DropdownPlain'; diff --git a/frontend/app/components/ui/ErrorDetails/ErrorDetails.js b/frontend/app/components/ui/ErrorDetails/ErrorDetails.js new file mode 100644 index 000000000..68f48cb82 --- /dev/null +++ b/frontend/app/components/ui/ErrorDetails/ErrorDetails.js @@ -0,0 +1,65 @@ +import React, { useState } from 'react' +import ErrorFrame from '../ErrorFrame/ErrorFrame' +import cn from 'classnames'; +import { IconButton, Icon } from 'UI'; +import { connect } from 'react-redux'; + +const docLink = 'https://docs.openreplay.com/plugins/sourcemaps'; + +function ErrorDetails({ className, name = "Error", message, errorStack, sourcemapUploaded }) { + const [showRaw, setShowRaw] = useState(false) + const firstFunc = errorStack.first() && errorStack.first().function + + const openDocs = () => { + window.open(docLink, '_blank'); + } + + return ( + <div className={className} > + { !sourcemapUploaded && ( + <div + style={{ backgroundColor: 'rgba(204, 0, 0, 0.1)' }} + className="font-normal flex items-center text-sm font-regular color-red border p-2 rounded" + > + <Icon name="info" size="16" color="red" /> + <div className="ml-2">Source maps must be uploaded to OpenReplay to be able to see stack traces. <a href="#" className="color-red font-medium underline" style={{ textDecoration: 'underline' }} onClick={openDocs}>Learn more.</a></div> + </div> + ) } + <div className="flex items-center my-3"> + <h3 className="text-xl mr-auto"> + Stacktrace + </h3> + <div className="flex justify-end mr-2"> + <IconButton + onClick={() => setShowRaw(false) } + label="FULL" + plain={!showRaw} + primaryText={!showRaw} + /> + <IconButton + primaryText={showRaw} + onClick={() => setShowRaw(true) } + plain={showRaw} + label="RAW" + /> + </div> + </div> + <div className="mb-6 code-font" data-hidden={showRaw}> + <div className="leading-relaxed font-weight-bold">{ name }</div> + <div style={{ wordBreak: 'break-all'}}>{message}</div> + </div> + { showRaw && + <div className="mb-3 code-font">{name} : {firstFunc ? firstFunc : '?' }</div> + } + { errorStack.map((frame, i) => ( + <div className="mb-3" key={frame.key}> + <ErrorFrame frame={frame} showRaw={showRaw} isFirst={i == 0} /> + </div> + )) + } + </div> + ) +} + +ErrorDetails.displayName = "ErrorDetails"; +export default ErrorDetails; diff --git a/frontend/app/components/ui/ErrorDetails/index.js b/frontend/app/components/ui/ErrorDetails/index.js new file mode 100644 index 000000000..987da1320 --- /dev/null +++ b/frontend/app/components/ui/ErrorDetails/index.js @@ -0,0 +1 @@ +export { default } from './ErrorDetails'; diff --git a/frontend/app/components/ui/ErrorFrame/ErrorFrame.js b/frontend/app/components/ui/ErrorFrame/ErrorFrame.js new file mode 100644 index 000000000..3f74a9444 --- /dev/null +++ b/frontend/app/components/ui/ErrorFrame/ErrorFrame.js @@ -0,0 +1,53 @@ +import React, { useState } from 'react' +import { Icon } from 'UI'; +import cn from 'classnames'; +import stl from './errorFrame.css'; + +function ErrorFrame({ frame = {}, showRaw, isFirst }) { + const [open, setOpen] = useState(isFirst) + const hasContext = frame.context && frame.context.length > 0; + return ( + <div> + { showRaw ? + <div className={stl.rawLine}>at { frame.function ? frame.function : '?' } <span className="color-gray-medium">({`${frame.filename}:${frame.lineNo}:${frame.colNo}`})</span></div> + : + <div className={stl.formatted}> + <div className={cn(stl.header, 'flex items-center cursor-pointer')} onClick={() => setOpen(!open)}> + <div className="truncate"> + <span className="font-medium">{ frame.absPath }</span> + { frame.function && + <> + <span>{' in '}</span> + <span className="font-medium"> {frame.function} </span> + </> + } + <span>{' at line '}</span> + <span className="font-medium"> + {frame.lineNo}:{frame.colNo} + </span> + </div> + { hasContext && + <div className="ml-auto mr-3"> + <Icon name={ open ? 'minus' : 'plus'} size="14" color="gray-medium" /> + </div> + } + </div> + { open && hasContext && + <ol start={ frame.context[0][0]} className={stl.content}> + { frame.context.map(i => ( + <li + key={i[0]} + className={ cn("leading-7 text-sm break-all h-auto pl-2", { [stl.errorLine] :i[0] == frame.lineNo }) } + > + <span>{ i[1].replace(/ /g, "\u00a0") }</span> + </li> + ))} + </ol> + } + </div> + } + </div> + ) +} + +export default ErrorFrame; diff --git a/frontend/app/components/ui/ErrorFrame/errorFrame.css b/frontend/app/components/ui/ErrorFrame/errorFrame.css new file mode 100644 index 000000000..5e7f69e75 --- /dev/null +++ b/frontend/app/components/ui/ErrorFrame/errorFrame.css @@ -0,0 +1,25 @@ +.rawLine { + margin-left: 30px; + font-family: 'Menlo', 'monaco', 'consolas', monospace; + font-size: 13px; +} +.formatted { + border: solid thin #EEE; + border-radius: 3px; +} +.header { + background-color: $gray-lightest; + padding: 8px; + border-bottom: solid thin #EEE; +} +.content { + font-family: 'Menlo', 'monaco', 'consolas', monospace; + list-style-position: inside; + list-style-type: decimal-leading-zero; +} + +.errorLine { + background-color: $teal; + color: white !important; + font-weight: bold; +} \ No newline at end of file diff --git a/frontend/app/components/ui/ErrorFrame/index.js b/frontend/app/components/ui/ErrorFrame/index.js new file mode 100644 index 000000000..70caa16f6 --- /dev/null +++ b/frontend/app/components/ui/ErrorFrame/index.js @@ -0,0 +1 @@ +export { default } from './ErrorFrame'; \ No newline at end of file diff --git a/frontend/app/components/ui/ErrorItem/ErrorItem.js b/frontend/app/components/ui/ErrorItem/ErrorItem.js new file mode 100644 index 000000000..2d1813bcf --- /dev/null +++ b/frontend/app/components/ui/ErrorItem/ErrorItem.js @@ -0,0 +1,23 @@ +import React from 'react' +import cn from 'classnames' +import { IconButton } from 'UI' +import stl from './errorItem.css'; + +function ErrorItem({ error = {}, onErrorClick, onJump }) { + return ( + <div className={ cn(stl.wrapper, 'py-3 px-4 flex cursor-pointer') } onClick={onJump}> + <div className="mr-auto"> + <div className="color-red mb-1 cursor-pointer code-font"> + {error.name} + <span className="color-gray-darkest ml-2">{ error.stack0InfoString }</span> + </div> + <div className="text-sm color-gray-medium">{error.message}</div> + </div> + <div className="self-end"> + <IconButton plain onClick={onErrorClick} label="DETAILS" /> + </div> + </div> + ) +} + +export default ErrorItem diff --git a/frontend/app/components/ui/ErrorItem/errorItem.css b/frontend/app/components/ui/ErrorItem/errorItem.css new file mode 100644 index 000000000..5a185ed5c --- /dev/null +++ b/frontend/app/components/ui/ErrorItem/errorItem.css @@ -0,0 +1,3 @@ +.wrapper { + border-bottom: solid thin $gray-light-shade; +} \ No newline at end of file diff --git a/frontend/app/components/ui/ErrorItem/index.js b/frontend/app/components/ui/ErrorItem/index.js new file mode 100644 index 000000000..9cdee388f --- /dev/null +++ b/frontend/app/components/ui/ErrorItem/index.js @@ -0,0 +1 @@ +export { default } from './ErrorItem'; \ No newline at end of file diff --git a/frontend/app/components/ui/EscapeButton/EscapeButton.js b/frontend/app/components/ui/EscapeButton/EscapeButton.js new file mode 100644 index 000000000..69e68e8ee --- /dev/null +++ b/frontend/app/components/ui/EscapeButton/EscapeButton.js @@ -0,0 +1,14 @@ +import React from 'react' +import { Icon } from 'UI'; +import stl from './escapeButton.css' + +function EscapeButton({ onClose = null}) { + return ( + <div className={ stl.closeWrapper } onClick={ onClose }> + <Icon name="close" size="20" /> + <div>{ 'ESC' }</div> + </div> + ) +} + +export default EscapeButton diff --git a/frontend/app/components/ui/EscapeButton/escapeButton.css b/frontend/app/components/ui/EscapeButton/escapeButton.css new file mode 100644 index 000000000..d7507a724 --- /dev/null +++ b/frontend/app/components/ui/EscapeButton/escapeButton.css @@ -0,0 +1,29 @@ +$padding: 23px; + +.closeWrapper { + background-color: white; + padding: 10px; + border-radius: 50%; + width: 50px; + height: 50px; + position: fixed; + top: $padding; + right: 20px; + top: 20px; + display: flex; + align-items: center; + justify-content: center; + z-index: 102; /* stay top of the test builer stiky header */ + flex-direction: column; + cursor: pointer; + transition: all 0.3s ease-out; + opacity: 0.5; + &:hover { + opacity: 1 + } + + & div:last-child { + font-size: 8px; + line-height: 12px; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/EscapeButton/index.js b/frontend/app/components/ui/EscapeButton/index.js new file mode 100644 index 000000000..159432d9a --- /dev/null +++ b/frontend/app/components/ui/EscapeButton/index.js @@ -0,0 +1 @@ +export { default } from './EscapeButton'; \ No newline at end of file diff --git a/frontend/app/components/ui/Icon/Browser.js b/frontend/app/components/ui/Icon/Browser.js new file mode 100644 index 000000000..6339cf3ea --- /dev/null +++ b/frontend/app/components/ui/Icon/Browser.js @@ -0,0 +1,10 @@ +import { browserIcon } from 'App/iconNames'; +import { Icon } from 'UI'; + +const BrowserIcon = ({ browser, size="20", ...props }) => ( + <Icon name={ browserIcon(browser) } size={ size } { ...props } /> +); + +BrowserIcon.displayName = "BrowserIcon"; + +export default BrowserIcon; \ No newline at end of file diff --git a/frontend/app/components/ui/Icon/Icon.js b/frontend/app/components/ui/Icon/Icon.js new file mode 100644 index 000000000..c6c41efa0 --- /dev/null +++ b/frontend/app/components/ui/Icon/Icon.js @@ -0,0 +1,38 @@ +import cn from 'classnames'; +import SVG from 'UI/SVG'; +import styles from './icon.css'; + +const Icon = ({ + name, + size = 12, + height = size, + width = size, + color = 'gray-medium', + className = '', + style={}, + marginRight, + inline = false, + ...props +}) => { + const _style = { + width: `${ width }px`, + height: `${ height }px`, + ...style, + }; + if (marginRight){ + _style.marginRight = `${ marginRight }px`; + } + return ( + <span + { ...props } + style={ _style } + className={ cn(className, styles.wrapper, `fill-${ color }`) } + data-inline={ inline } + > + <SVG name={ name } height={ height } width={ width } /> + </span> + ); +} + +Icon.displayName = 'Icon'; +export default Icon; diff --git a/frontend/app/components/ui/Icon/Icon.stories.js b/frontend/app/components/ui/Icon/Icon.stories.js new file mode 100644 index 000000000..c315974e3 --- /dev/null +++ b/frontend/app/components/ui/Icon/Icon.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from '@storybook/react'; +import Icon from '.'; + +storiesOf('Icon', module) + .add('Pure', () => ( + <Icon /> + )) + .add('Icon', () => ( + <Icon name="close" /> + )) + .add('Icon Size 16', () => ( + <Icon name="close" size="16" /> + )) + diff --git a/frontend/app/components/ui/Icon/Os.js b/frontend/app/components/ui/Icon/Os.js new file mode 100644 index 000000000..37ecffc40 --- /dev/null +++ b/frontend/app/components/ui/Icon/Os.js @@ -0,0 +1,10 @@ +import { osIcon } from 'App/iconNames'; +import { Icon } from 'UI'; + +const OsIcon = ({ os, size="20", ...props }) => ( + <Icon name={ osIcon(os) } size={ size } { ...props } /> +); + +OsIcon.displayName = "OsIcon"; + +export default OsIcon; \ No newline at end of file diff --git a/frontend/app/components/ui/Icon/icon.css b/frontend/app/components/ui/Icon/icon.css new file mode 100644 index 000000000..2fb5567ec --- /dev/null +++ b/frontend/app/components/ui/Icon/icon.css @@ -0,0 +1,8 @@ +.wrapper { + display: flex; + align-items: center; + justify-content: center; + &[data-inline=true] { + display: inline-flex; + } +} diff --git a/frontend/app/components/ui/Icon/index.js b/frontend/app/components/ui/Icon/index.js new file mode 100644 index 000000000..dc6b45c35 --- /dev/null +++ b/frontend/app/components/ui/Icon/index.js @@ -0,0 +1 @@ +export { default } from './Icon'; diff --git a/frontend/app/components/ui/IconButton/IconButton.js b/frontend/app/components/ui/IconButton/IconButton.js new file mode 100644 index 000000000..53077f06c --- /dev/null +++ b/frontend/app/components/ui/IconButton/IconButton.js @@ -0,0 +1,73 @@ +import cn from 'classnames'; +import { CircularLoader, Icon, Tooltip } from 'UI'; +import stl from './iconButton.css'; + +const IconButton = React.forwardRef(({ + icon, + label = false, + active, + onClick, + plain = false, + shadow = false, + primary = false, + primaryText = false, + outline = false, + loading = false, + roundedOutline = false, + hideLoader = false, + circle = false, + size = 'default', + marginRight, + buttonSmall, + className = '', + style, + name, + disabled = false, + tooltip = false, + compact = false, + ...rest +}, ref) => ( + <Tooltip + tooltip={tooltip} + trigger={ + <button + ref={ ref } + name={ name } + className={ cn(stl.button, className, { + [ stl.plain ]: plain, + [ stl.active ]: active, + [ stl.shadow ]: shadow, + [ stl.primary ]: primary, + [ stl.primaryText ]: primaryText, + [ stl.outline ]: outline, + [ stl.circle ]: circle, + [ stl.roundedOutline ]: roundedOutline, + [ stl.buttonSmall ]: buttonSmall, + [ stl.small ]: size === 'small', + [ stl.tiny ]: size === 'tiny', + [ stl.marginRight ]: marginRight, + [ stl.compact ]: compact, + [ stl.hasLabel]: !!label + }) } + onClick={ onClick } + disabled={ disabled || loading } + style={style} + { ...rest } + > + { !hideLoader && <CircularLoader loading={ loading } /> } + { icon && + <Icon + color="teal" + name={ icon } + data-hidden={ loading } + size={ size === 'tiny' || size === 'small' || buttonSmall ? '14' : '16' } + /> + } + { label && <span className={ cn(stl.label, icon || loading ? 'ml-2' : '') }>{ label }</span> } + </button> + } + /> +)); + +IconButton.displayName = "IconButton"; +export default IconButton; diff --git a/frontend/app/components/ui/IconButton/IconButton.stories.js b/frontend/app/components/ui/IconButton/IconButton.stories.js new file mode 100644 index 000000000..4a47fcbfb --- /dev/null +++ b/frontend/app/components/ui/IconButton/IconButton.stories.js @@ -0,0 +1,20 @@ +import { storiesOf } from '@storybook/react'; +import IconButton from '.'; + +storiesOf('IconButton', module) + .add('Pure', () => ( + <IconButton /> + )) + .add('Icon', () => ( + <IconButton icon="cog" /> + )) + .add('Icon & Label', () => ( + <IconButton icon="cog" label="Button" /> + )) + .add('Plain', () => ( + <IconButton icon="cog" label="Button" plain /> + )) + .add('Primary', () => ( + <IconButton icon="cog" label="Button" primary /> + )) + diff --git a/frontend/app/components/ui/IconButton/iconButton.css b/frontend/app/components/ui/IconButton/iconButton.css new file mode 100644 index 000000000..41ed89e45 --- /dev/null +++ b/frontend/app/components/ui/IconButton/iconButton.css @@ -0,0 +1,115 @@ + +@import 'icons.css'; +@import 'mixins.css'; + +.button { + padding: 0px 0.75rem; + border-radius: 3px; + display: flex; + align-items: center; + cursor: pointer; + height: 36px; + font-size: 14px; + border: none; + + &:disabled, + &[disabled] { + opacity: 0.5 !important; + } + + &.marginRight { + margin-right: 10px; + } + + &.buttonSmall { + height: 23px; + font-size: 12px; + padding: 0px 10px; + } + + &.circle { + border-radius: 50%; + width: 36px; + padding: 0; + justify-content: center; + } + + &.shadow { + @mixin shadow-light; + } + + &.small { + padding: 0px 12px; + height: 28px; + width: 28px; + font-size: 12px; + + & .label { + margin-left: 4px; + line-height: 2px; + } + } + + &.hasLabel { + width: fit-content; + } + + &.compact { + padding: 0 8px; + } + + &.tiny { + padding: 0 2px; + height: 20px; + font-size: 10px; + } + + &.primary { + background-color: $teal; + box-shadow: 0 0 0 1px rgba(62, 170, 175, .8) inset !important; + + & .icon { + fill: white; + } + + &:hover { + background-color: $teal-dark; + } + } + + &.outline { + box-shadow: 0 0 0 1px $teal inset !important; + & .label { + color: $teal; + } + &:hover { + background-color: $active-blue !important; + } + } + + &.plain { + background-color: transparent; + &:hover { + background-color: $active-blue; + } + } + + & .label { + white-space: nowrap; + color: $gray-dark; + } + + &:hover { + background-color: $active-blue; + } + + &roundedOutline { + border-radius: 15px; + box-shadow: 0 0 0 1px rgba(62,170,175,1) inset !important; + color: $teal; + } +} + +.primaryText .label { + color: $teal !important; +} \ No newline at end of file diff --git a/frontend/app/components/ui/IconButton/index.js b/frontend/app/components/ui/IconButton/index.js new file mode 100644 index 000000000..86c5e513a --- /dev/null +++ b/frontend/app/components/ui/IconButton/index.js @@ -0,0 +1 @@ +export { default } from './IconButton'; diff --git a/frontend/app/components/ui/Information/Information.js b/frontend/app/components/ui/Information/Information.js new file mode 100644 index 000000000..882f0fa2d --- /dev/null +++ b/frontend/app/components/ui/Information/Information.js @@ -0,0 +1,13 @@ +import React from 'react' +import stl from './information.css' +import cn from 'classnames' + +function Information({ primary = true, content = '' }) { + return ( + <div className={cn(stl.wrapper, { [stl.primary]: primary })}> + { content } + </div> + ) +} + +export default Information diff --git a/frontend/app/components/ui/Information/index.js b/frontend/app/components/ui/Information/index.js new file mode 100644 index 000000000..d49723b8f --- /dev/null +++ b/frontend/app/components/ui/Information/index.js @@ -0,0 +1 @@ +export { default } from './Information'; \ No newline at end of file diff --git a/frontend/app/components/ui/Information/information.css b/frontend/app/components/ui/Information/information.css new file mode 100644 index 000000000..3bb39792b --- /dev/null +++ b/frontend/app/components/ui/Information/information.css @@ -0,0 +1,17 @@ +.wrapper { + position: fixed; + background-color: white; + top: 50px; + left: 0; + right: 0; + height: 28px; + display: flex; + justify-content: center; + align-items: center; + border-top: solid thin $gray-light-shade; +} + +.primary { + background-color: $teal; + color: white; +} diff --git a/frontend/app/components/ui/InputAutocomplete/DropdownItem.js b/frontend/app/components/ui/InputAutocomplete/DropdownItem.js new file mode 100644 index 000000000..9467a4292 --- /dev/null +++ b/frontend/app/components/ui/InputAutocomplete/DropdownItem.js @@ -0,0 +1,13 @@ +import stl from './dropdownItem.css'; + +const DropdownItem = ({ event }) => ( + <div className={ stl.wrapper }> + <div className={ stl.values } data-type={ event.type }> + { event.value } + </div> + </div> +); + +DropdownItem.displayName = 'DropdownItem'; + +export default DropdownItem; diff --git a/frontend/app/components/ui/InputAutocomplete/InputAutocomplete.js b/frontend/app/components/ui/InputAutocomplete/InputAutocomplete.js new file mode 100644 index 000000000..3887c7286 --- /dev/null +++ b/frontend/app/components/ui/InputAutocomplete/InputAutocomplete.js @@ -0,0 +1,56 @@ +import { Dropdown } from 'semantic-ui-react'; + +const defaultValueToText = value => value; +const defaultOptionMapping = (values, valueToText) => values.map(value => ({ text: valueToText(value), value })); + +// TODO: get rid of semantic +export default class InputAutocomplete extends React.PureComponent { + state = { ddOpen: false } + + onSearchChange = (e, { searchQuery }) => { + const { onChange } = this.props; + if (typeof onChange === 'function') { + onChange(e, { value: searchQuery, name: this.props.name }); + } + } + + onSelect = (e, t) => { + const { onChange, onSelect } = this.props; + if (typeof onChange === 'function') { + onChange(e, t); + } + if (typeof onSelect === 'function') { + onSelect(e, t); + } + } + + render() { + const { + values = [], + valueToText = defaultValueToText, + optionMapping = defaultOptionMapping, + ...otherProps + } = this.props; + + const { ddOpen } = this.state; + + const options = optionMapping(values, valueToText) + return ( + <Dropdown + { ...otherProps } + selection + options={ options } + onChange={ this.onSelect } + onSelect={ null } + searchQuery={ this.props.value } + onSearchChange={ this.onSearchChange } + selectOnBlur={ false } + selectOnNavigation={ false } + search + deburr + searchInput={{ autoFocus: true }} + value={ null } + /> + ); + } +} diff --git a/frontend/app/components/ui/InputAutocomplete/InputAutocomplete.stories.js b/frontend/app/components/ui/InputAutocomplete/InputAutocomplete.stories.js new file mode 100644 index 000000000..d02fc7a62 --- /dev/null +++ b/frontend/app/components/ui/InputAutocomplete/InputAutocomplete.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import InputAutocomplete from '.'; + +storiesOf('InputAutocomplete', module) + .add('Pure', () => ( + <InputAutocomplete /> + )) + diff --git a/frontend/app/components/ui/InputAutocomplete/dropdownItem.css b/frontend/app/components/ui/InputAutocomplete/dropdownItem.css new file mode 100644 index 000000000..aa02cbb1c --- /dev/null +++ b/frontend/app/components/ui/InputAutocomplete/dropdownItem.css @@ -0,0 +1,5 @@ +.wrapper { + & .values { + color: red; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/InputAutocomplete/index.js b/frontend/app/components/ui/InputAutocomplete/index.js new file mode 100644 index 000000000..a5fae14ba --- /dev/null +++ b/frontend/app/components/ui/InputAutocomplete/index.js @@ -0,0 +1 @@ +export { default } from './InputAutocomplete'; \ No newline at end of file diff --git a/frontend/app/components/ui/ItemMenu/ItemMenu.js b/frontend/app/components/ui/ItemMenu/ItemMenu.js new file mode 100644 index 000000000..c31130071 --- /dev/null +++ b/frontend/app/components/ui/ItemMenu/ItemMenu.js @@ -0,0 +1,71 @@ +import { Icon } from 'UI'; +import styles from './itemMenu.css'; + +export default class ItemMenu extends React.PureComponent { + state = { + displayed: false, + }; + + componentDidMount() { + document.addEventListener('click', this.handleClickOutside); + } + + componentWillUnmount() { + document.removeEventListener('click', this.handleClickOutside); + } + + onClick = callback => (e) => { + e.stopPropagation(); + callback(e); + } + + handleClickOutside = (e) => { + if (!this.state.displayed) return; + if (e.target !== this.menuBtnRef) { + this.closeMenu(); + } + } + + toggleMenu = (e) => { + e.stopPropagation(); + this.setState({ displayed: !this.state.displayed }); + } + + closeMenu = () => this.setState({ displayed: false }) + + render() { + const { items } = this.props; + const { displayed } = this.state; + + return ( + <div className={ styles.wrapper }> + <div + ref={ (ref) => { this.menuBtnRef = ref; } } + className={ styles.menuBtn } + onClick={ this.toggleMenu } + role="button" + tabIndex="-1" + /> + <div + className={ styles.menu } + data-displayed={ displayed } + > + { items.filter(({ hidden }) => !hidden).map(({ onClick, text, icon }) => ( + <div + key={ text } + className={ styles.menuItem } + onClick={ this.onClick(onClick) } + role="menuitem" + tabIndex="-1" + > + <div className={ styles.iconWrapper }> + <Icon name={ icon } size="13" color="gray-dark" /> + </div> + <div>{ text }</div> + </div> + ))} + </div> + </div> + ); + } +} diff --git a/frontend/app/components/ui/ItemMenu/ItemMenu.stories.js b/frontend/app/components/ui/ItemMenu/ItemMenu.stories.js new file mode 100644 index 000000000..3db7ba180 --- /dev/null +++ b/frontend/app/components/ui/ItemMenu/ItemMenu.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import ItemMenu from '.'; + +storiesOf('ItemMenu', module) + .add('Pure', () => ( + <ItemMenu /> + )) + diff --git a/frontend/app/components/ui/ItemMenu/index.js b/frontend/app/components/ui/ItemMenu/index.js new file mode 100644 index 000000000..94d7f0584 --- /dev/null +++ b/frontend/app/components/ui/ItemMenu/index.js @@ -0,0 +1 @@ +export { default } from './ItemMenu'; diff --git a/frontend/app/components/ui/ItemMenu/itemMenu.css b/frontend/app/components/ui/ItemMenu/itemMenu.css new file mode 100644 index 000000000..bb9bd6426 --- /dev/null +++ b/frontend/app/components/ui/ItemMenu/itemMenu.css @@ -0,0 +1,88 @@ +@import "icons.css"; + +.wrapper { + position: relative; + display: inline-block; +} + +.menuBtn { + @mixin icon-before ellipsis-v, $gray-darkest, 25px { + margin: 5px; + } + width: 36px; + height: 36px; + border-radius: 18px; + border: 1px solid transparent; + transition: all 0.2s; + margin: 0 auto; + cursor: pointer; + + &:hover { + border-color: $active-blue-border; + transition: all 0.2s; + background-color: #fff; + } +} +.menu { + &[data-displayed=false] { + display: none; + } + + z-index: 10; + position: absolute; + right: 31px; + top: 18px; + width: 150px; + background-color: $white; + border-radius: 3px; + box-shadow: 0px 1px 3px 0 $gray-light; + + & .menuItem { + cursor: pointer; + padding: 10px; + display: flex; + align-items: center; + border-bottom: 1px solid $gray-light; + color: $gray-dark; + + & .iconWrapper { + width: 13px; + height: 13px ; + margin-right: 8px; + } + + &:hover { + background-color: $gray-lightest; + } + + &:last-child { + border: none; + } + + & .edit { + @mixin icon pencil, $gray-medium, 15px; + margin-right: 10px; + } + + & .copy { + @mixin icon copy, $gray-medium, 15px; + margin-right: 10px; + } + + & .remove { + @mixin icon trash, $gray-medium, 15px; + margin-right: 10px; + } + + & .enabled { + @mixin icon eye, $gray-medium, 15px; + margin-right: 10px; + } + + & .disabled { + @mixin icon eye-slash, $gray-medium, 15px; + margin-right: 10px; + } + + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/JSONTree/JSONTree.js b/frontend/app/components/ui/JSONTree/JSONTree.js new file mode 100644 index 000000000..d27e082bd --- /dev/null +++ b/frontend/app/components/ui/JSONTree/JSONTree.js @@ -0,0 +1,23 @@ +import JSONTree from 'react-json-view'; + +function updateObjectLink(obj) { + if (typeof obj !== 'object' || obj === null) return obj; + if (Array.isArray(obj)) return [ ...obj ]; + return { ...obj } +} + +export default ({ src, ...props }) => ( + <JSONTree + name={ false } + collapsed={ 1 } + enableClipboard={ false } + iconStyle="circle" + indentWidth={ 1 } + sortKeys + displayDataTypes={ false } + displayObjectSize={ false } + src={ updateObjectLink(src) } + iconStle="triangle" + { ...props } + /> +); \ No newline at end of file diff --git a/frontend/app/components/ui/JSONTree/index.js b/frontend/app/components/ui/JSONTree/index.js new file mode 100644 index 000000000..69c3eee8c --- /dev/null +++ b/frontend/app/components/ui/JSONTree/index.js @@ -0,0 +1 @@ +export { default } from './JSONTree'; \ No newline at end of file diff --git a/frontend/app/components/ui/Label/Label.js b/frontend/app/components/ui/Label/Label.js new file mode 100644 index 000000000..ffe9080fc --- /dev/null +++ b/frontend/app/components/ui/Label/Label.js @@ -0,0 +1,14 @@ +import { Label } from 'semantic-ui-react'; +import styles from './label.css'; +import cn from 'classnames'; + +export default ({ + children, className, ...props +}) => ( + <Label + { ...props } + className={ cn(className, styles.label, 'border') } + > + { children } + </Label> +); diff --git a/frontend/app/components/ui/Label/Label.stories.js b/frontend/app/components/ui/Label/Label.stories.js new file mode 100644 index 000000000..2a56124ee --- /dev/null +++ b/frontend/app/components/ui/Label/Label.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Label from '.'; + +storiesOf('Label', module) + .add('Pure', () => ( + <Label /> + )) + diff --git a/frontend/app/components/ui/Label/index.js b/frontend/app/components/ui/Label/index.js new file mode 100644 index 000000000..a1e5f51f5 --- /dev/null +++ b/frontend/app/components/ui/Label/index.js @@ -0,0 +1 @@ +export { default } from './Label'; diff --git a/frontend/app/components/ui/Label/label.css b/frontend/app/components/ui/Label/label.css new file mode 100644 index 000000000..04f7021aa --- /dev/null +++ b/frontend/app/components/ui/Label/label.css @@ -0,0 +1,22 @@ +.label { + font-weight: 500 !important; + + & > div { + display: flex; + align-items: center; + } + + &[data-rounded] { + border-radius: 16px; + } + + &[data-red = true] { + color: $red !important; + background-color: rgba(204, 0, 0, 0.1); + } + + &[data-green = true] { + color: #12722A !important; + background-color: rgba(60, 180, 0, 0.1); + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/Link/Link.js b/frontend/app/components/ui/Link/Link.js new file mode 100644 index 000000000..6424f6e55 --- /dev/null +++ b/frontend/app/components/ui/Link/Link.js @@ -0,0 +1,19 @@ +import { Link } from 'react-router-dom'; +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { withSiteId } from 'App/routes'; +import styles from './link.css'; + +const OpenReplayLink = ({ siteId, to, className="", dispatch, ...other }) => ( + <Link + { ...other } + className={ cn(className, styles.link) } + to={ withSiteId(to, siteId) } + /> +); + +OpenReplayLink.displayName = 'OpenReplayLink'; + +export default connect((state, props) => ({ + siteId: props.siteId || state.getIn([ 'user', 'siteId' ]) +}))(OpenReplayLink); \ No newline at end of file diff --git a/frontend/app/components/ui/Link/Link.stories.js b/frontend/app/components/ui/Link/Link.stories.js new file mode 100644 index 000000000..e0cafc6f6 --- /dev/null +++ b/frontend/app/components/ui/Link/Link.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Link from '.'; + +storiesOf('Link', module) + .add('Pure', () => ( + <Link /> + )) + diff --git a/frontend/app/components/ui/Link/index.js b/frontend/app/components/ui/Link/index.js new file mode 100644 index 000000000..241046084 --- /dev/null +++ b/frontend/app/components/ui/Link/index.js @@ -0,0 +1 @@ +export { default } from './Link'; diff --git a/frontend/app/components/ui/Link/link.css b/frontend/app/components/ui/Link/link.css new file mode 100644 index 000000000..be433ac89 --- /dev/null +++ b/frontend/app/components/ui/Link/link.css @@ -0,0 +1,4 @@ +.link[disabled] { + pointer-events: none; + opacity: .3 +} diff --git a/frontend/app/components/ui/LinkStyledInput/LinkStyledInput.js b/frontend/app/components/ui/LinkStyledInput/LinkStyledInput.js new file mode 100644 index 000000000..137d35ccb --- /dev/null +++ b/frontend/app/components/ui/LinkStyledInput/LinkStyledInput.js @@ -0,0 +1,101 @@ +import cn from 'classnames'; +import styles from './linkStyledInput.css'; + +export default class LinkStyledInput extends React.PureComponent { + state = { + value: this.props.value || '', + changing: false, + } + + componentDidUpdate(prevProps, prevState) { + if (prevProps.value !== this.props.value) { + this.setState({ value: this.props.value }); + } + + if (!prevState.changing && this.state.changing) { + this.inputRef.focus(); + document.addEventListener('click', this.onEndChange, false); + this.inputRef.addEventListener('blur', this.onEndChange, false); + this.inputRef.addEventListener('keydown', this.escapeHandler, false); + } + } + + componentWillUnmount() { + document.removeEventListener('click', this.onEndChange, false); + if (this.inputRef) { + this.inputRef.removeEventListener('blur', this.onEndChange, false); + this.inputRef.removeEventListener('keydown', this.escapeHandler, false); + } + } + + onStartChange = () => { + this.setState({ changing: true }); + } + + onChange = (e) => { + this.props.onChange(e, e.target); + if (!this.props.value) { + this.setState({ value: e.target.value }); + } + } + + onEndChange = (e) => { + e.preventDefault(); + if (this.inputRef === e.target) return; + document.removeEventListener('click', this.onEndChange, false); + this.setState({ + changing: false, + value: this.state.value.trim(), + }); + } + + escapeHandler = (e) => { + if (e.keyCode === 27) { + this.onEndChange(e); + } + } + + render() { + const { + name, + placeholder, + displayLabel, + maxLength, + fluid, + consoleFont = false, + disabled, + disabledStyle = disabled, + className = '', + hint = "Click to Type", + } = this.props; + const { changing, value = this.props.value } = this.state; + + const text = value ? value.trim() : displayLabel; + return ( + <form className={ className } onSubmit={ this.onEndChange }> + { changing ? + <input + ref={ (ref) => { this.inputRef = ref; } } + className={ styles.input } + name={ name } + value={ value } + maxLength={ maxLength || 35 } + onChange={ this.onChange } + placeholder={ placeholder } + data-fluid={ fluid } + /> + : + <div + className={ cn(styles.linkStyled, { + [ styles.disabled ] : disabledStyle, + [ styles.console ]: consoleFont, + }) } + onClick={ disabled ? null : this.onStartChange } + > + {text} + </div> + } + </form> + ); + } +} diff --git a/frontend/app/components/ui/LinkStyledInput/LinkStyledInput.stories.js b/frontend/app/components/ui/LinkStyledInput/LinkStyledInput.stories.js new file mode 100644 index 000000000..6098713b5 --- /dev/null +++ b/frontend/app/components/ui/LinkStyledInput/LinkStyledInput.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import LinkStyledInput from '.'; + +storiesOf('LinkStyledInput', module) + .add('Pure', () => ( + <LinkStyledInput /> + )) + diff --git a/frontend/app/components/ui/LinkStyledInput/index.js b/frontend/app/components/ui/LinkStyledInput/index.js new file mode 100644 index 000000000..a3e3b2a61 --- /dev/null +++ b/frontend/app/components/ui/LinkStyledInput/index.js @@ -0,0 +1 @@ +export { default } from './LinkStyledInput'; diff --git a/frontend/app/components/ui/LinkStyledInput/linkStyledInput.css b/frontend/app/components/ui/LinkStyledInput/linkStyledInput.css new file mode 100644 index 000000000..84abeee2d --- /dev/null +++ b/frontend/app/components/ui/LinkStyledInput/linkStyledInput.css @@ -0,0 +1,34 @@ +.input { + border-radius: 3px; + padding: 3px 5px; + background-color: white; + margin-right: 5px; + min-width: 55%; + line-height: 15px; + height: 28px !important; + + &[data-fluid] { + min-width: 90%; + } + &:focus { + border: solid 1px $gray-light !important; + color: #454545 !important; + } +} + +.linkStyled { + &.disabled { + color: $gray-light; + } + cursor: pointer; + line-height: 15px; + padding: 3px 5px; + border: solid thin transparent; + height: 24px; + width: max-content; + color: $teal; + text-align: right; + &.console { + font-family: 'Menlo', 'Courier' !important; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/LoadMoreButton/LoadMoreButton.js b/frontend/app/components/ui/LoadMoreButton/LoadMoreButton.js new file mode 100644 index 000000000..bffe48bef --- /dev/null +++ b/frontend/app/components/ui/LoadMoreButton/LoadMoreButton.js @@ -0,0 +1,26 @@ +import React from 'react' +import cn from 'classnames' + +function LoadMoreButton({className = '', totalCount, displayedCount, onClick, loading, description = false}) { + return ( + <div className={ cn("flex flex-col items-center", className)}> + <div className="color-gray-medium text-sm"> + Showing <span className="font-bold">{ displayedCount }</span> of <span className="font-bold">{ totalCount }</span> + </div> + { totalCount > displayedCount && + <a + className="color-teal uppercase mt-1 cursor-pointer" + onClick={ onClick } + disabled={ loading } + > + { 'Load more' } + </a> + } + { description && ( + <div>{ description }</div> + )} + </div> + ) +} + +export default LoadMoreButton diff --git a/frontend/app/components/ui/LoadMoreButton/index.js b/frontend/app/components/ui/LoadMoreButton/index.js new file mode 100644 index 000000000..67ed6f08b --- /dev/null +++ b/frontend/app/components/ui/LoadMoreButton/index.js @@ -0,0 +1 @@ +export { default } from './LoadMoreButton'; diff --git a/frontend/app/components/ui/Loader/Loader.js b/frontend/app/components/ui/Loader/Loader.js new file mode 100644 index 000000000..5977af141 --- /dev/null +++ b/frontend/app/components/ui/Loader/Loader.js @@ -0,0 +1,12 @@ +import cn from 'classnames'; +import styles from './loader.css'; + +const Loader = React.memo(({ className, loading = true, children = null, size, style = { minHeight: '150px' } }) => (!loading ? children : + <div className={ cn(styles.wrapper, className) } style={style}> + <div className={ styles.loader } data-size={ size } /> + </div> +)); + +Loader.displayName = 'Loader'; + +export default Loader; diff --git a/frontend/app/components/ui/Loader/Loader.stories.js b/frontend/app/components/ui/Loader/Loader.stories.js new file mode 100644 index 000000000..7b969e07b --- /dev/null +++ b/frontend/app/components/ui/Loader/Loader.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Loader from '.'; + +storiesOf('Loader', module) + .add('Pure', () => ( + <Loader /> + )) + diff --git a/frontend/app/components/ui/Loader/index.js b/frontend/app/components/ui/Loader/index.js new file mode 100644 index 000000000..348c02a98 --- /dev/null +++ b/frontend/app/components/ui/Loader/index.js @@ -0,0 +1 @@ +export { default } from './Loader'; diff --git a/frontend/app/components/ui/Loader/loader.css b/frontend/app/components/ui/Loader/loader.css new file mode 100644 index 000000000..454e8f2db --- /dev/null +++ b/frontend/app/components/ui/Loader/loader.css @@ -0,0 +1,27 @@ +.loader { + display: block; + margin: auto; + background-image: svg-load(openreplay-preloader.svg, fill=#CCC); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + width: 50px; + height: 50px; + + &[data-size=medium] { + width: 70px; + height: 70px; + } + + &[data-size=small] { + width: 28px; + height: 28px; + } +} + +.wrapper { + height: 98%; + display: flex; + align-items: center; + justify-content: center; +} \ No newline at end of file diff --git a/frontend/app/components/ui/Message/Message.js b/frontend/app/components/ui/Message/Message.js new file mode 100644 index 000000000..037ceb0c8 --- /dev/null +++ b/frontend/app/components/ui/Message/Message.js @@ -0,0 +1,15 @@ +import styles from './message.css'; + +const Message = ({ children, inline=false, success=false, info=true, text }) => ( + <div className={ styles.message } data-inline={ inline }> + <Icon name="check" color='green' /> + { text + ? text + : children + } + </div> +); + +Message.displayName = "Message"; + +export default Message; \ No newline at end of file diff --git a/frontend/app/components/ui/Message/Message.stories.js b/frontend/app/components/ui/Message/Message.stories.js new file mode 100644 index 000000000..1b20c941c --- /dev/null +++ b/frontend/app/components/ui/Message/Message.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Message from '.'; + +storiesOf('Message', module) + .add('Pure', () => ( + <Message /> + )) + diff --git a/frontend/app/components/ui/Message/index.js b/frontend/app/components/ui/Message/index.js new file mode 100644 index 000000000..a8132bac3 --- /dev/null +++ b/frontend/app/components/ui/Message/index.js @@ -0,0 +1 @@ +export { default } from './Message'; diff --git a/frontend/app/components/ui/Message/message.css b/frontend/app/components/ui/Message/message.css new file mode 100644 index 000000000..7e4067a9b --- /dev/null +++ b/frontend/app/components/ui/Message/message.css @@ -0,0 +1,5 @@ +.message { + &[data-inline=true]{ + display: inline-block; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/NoContent/NoContent.js b/frontend/app/components/ui/NoContent/NoContent.js new file mode 100644 index 000000000..ee3e29b90 --- /dev/null +++ b/frontend/app/components/ui/NoContent/NoContent.js @@ -0,0 +1,23 @@ +import { Icon } from 'UI'; +import styles from './noContent.css'; + +export default ({ + title = "No data available.", + subtext, + icon, + size, + show = true, + children = null, + empty = false, +}) => (!show ? children : +<div className={ `${ styles.wrapper } ${ size && styles[ size ] }` }> + { + icon && <div className={ empty ? styles.emptyIcon : styles.icon } /> + } + { title && <div className={ styles.title }>{ title }</div> } + { + subtext && + <div className={ styles.subtext }>{ subtext }</div> + } +</div> +); diff --git a/frontend/app/components/ui/NoContent/NoContent.stories.js b/frontend/app/components/ui/NoContent/NoContent.stories.js new file mode 100644 index 000000000..333a5e31a --- /dev/null +++ b/frontend/app/components/ui/NoContent/NoContent.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from '@storybook/react'; +import NoContent from '.'; + +storiesOf('NoContent', module) + .add('Pure', () => ( + <NoContent /> + )) + .add('Text and icon', () => ( + <NoContent icon subtext="this is subtext to be displayed."/> + )) + .add('Empty Content', () => ( + <NoContent empty icon subtext="this is subtext to be displayed."/> + )) + diff --git a/frontend/app/components/ui/NoContent/index.js b/frontend/app/components/ui/NoContent/index.js new file mode 100644 index 000000000..3b7fa8f20 --- /dev/null +++ b/frontend/app/components/ui/NoContent/index.js @@ -0,0 +1 @@ +export { default } from './NoContent'; diff --git a/frontend/app/components/ui/NoContent/noContent.css b/frontend/app/components/ui/NoContent/noContent.css new file mode 100644 index 000000000..f4296757c --- /dev/null +++ b/frontend/app/components/ui/NoContent/noContent.css @@ -0,0 +1,59 @@ +.wrapper { + margin: auto; + width: 100%; + text-align: center; + min-height: 100px; + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; + color: $gray-medium; + font-weight: 300; + transition: all 0.2s; + padding-top: 40px; + + &.small { + & .title { + font-size: 20px !important; + } + + & .subtext { + font-size: 16px; + } + } +} + +.title { + font-size: 32px; + margin-bottom: 15px; +} + +.subtext { + font-size: 16px; + margin-bottom: 20px; +} + + +.icon { + display: block; + margin: auto; + background-image: svg-load(no-results.svg, fill=#CCC); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + width: 166px; + height: 166px; + margin-bottom: 20px; +} + +.emptyIcon { + display: block; + margin: auto; + background-image: svg-load(empty-state.svg, fill=#CCC); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + width: 166px; + height: 166px; + margin-bottom: 20px; +} diff --git a/frontend/app/components/ui/Notification/Notification.js b/frontend/app/components/ui/Notification/Notification.js new file mode 100644 index 000000000..c2e69d054 --- /dev/null +++ b/frontend/app/components/ui/Notification/Notification.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { ToastContainer, Flip } from 'react-toastify'; +import styles from './notification.css' + +export default ({ transition = Flip, position = 'bottom-right', autoClose = 3000, ...props }) => ( + <ToastContainer + hideProgressBar + position={ position } + draggable + pauseOnHover + transition={ transition } + autoClose={ autoClose } + className={ styles.container } + toastClassName={ styles.toast } + { ...props } + /> +); diff --git a/frontend/app/components/ui/Notification/Notification.stories.js b/frontend/app/components/ui/Notification/Notification.stories.js new file mode 100644 index 000000000..e711e81d3 --- /dev/null +++ b/frontend/app/components/ui/Notification/Notification.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Notification from '.'; + +storiesOf('Notification', module) + .add('Pure', () => ( + <Notification /> + )) + diff --git a/frontend/app/components/ui/Notification/index.js b/frontend/app/components/ui/Notification/index.js new file mode 100644 index 000000000..8b7ed4aa8 --- /dev/null +++ b/frontend/app/components/ui/Notification/index.js @@ -0,0 +1 @@ +export { default } from './Notification'; \ No newline at end of file diff --git a/frontend/app/components/ui/Notification/notification.css b/frontend/app/components/ui/Notification/notification.css new file mode 100644 index 000000000..b5e8e1cf9 --- /dev/null +++ b/frontend/app/components/ui/Notification/notification.css @@ -0,0 +1,5 @@ +.toast { + padding: 14px !important; + min-height: 40px !important; + border-radius: 3px !important; +} \ No newline at end of file diff --git a/frontend/app/components/ui/PopMenu/PopMenu.js b/frontend/app/components/ui/PopMenu/PopMenu.js new file mode 100644 index 000000000..bdd43583c --- /dev/null +++ b/frontend/app/components/ui/PopMenu/PopMenu.js @@ -0,0 +1,58 @@ +import React, { useState, useCallback } from 'react'; +import cn from 'classnames'; +import { Icon, Popup } from 'UI'; +import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; +import cls from './popMenu.css'; + +export default React.memo(function PopMenu({ items }) { + const [ open, setOpen ] = useState(false); + return ( + <OutsideClickDetectingDiv + className={ cls.wrapper } + onClickOutside={() => setOpen(false)} + > + { open && + <div className={ cls.menuItems } > + { items.map(item => ( + <button + key={ item.label } + onClick={ (e) => { + item.onClick(e); + setOpen(false); + }} + className={ cn("flex items-center justify-end color-green bg-white uppercase overflow-hidden", cls.menuItemButton) } + > + <div className={ cls.buttonLabel }>{ item.label }</div> + <Icon + name={ item.icon } + size="18" + className={ cls.icon } + color="teal" + /> + </button> + ))} + </div> + } + <Popup + trigger={ + <button + onClick={ () => setOpen(o => !o) } + className={ cn("bg-teal flex items-center justify-center", cls.addStepButton, {[cls.openMenuBtn] : open }) } + > + <Icon + name="plus" + size="18" + className={ cls.plusIcon } + color="white" + /> + </button> + } + content={ `Add Step` } + size="tiny" + inverted + position="top center" + /> + </OutsideClickDetectingDiv> + ); +}); + diff --git a/frontend/app/components/ui/PopMenu/PopMenu.stories.js b/frontend/app/components/ui/PopMenu/PopMenu.stories.js new file mode 100644 index 000000000..3adb369d1 --- /dev/null +++ b/frontend/app/components/ui/PopMenu/PopMenu.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import PopMenu from '.'; + +storiesOf('PopMenu', module) + .add('Pure', () => ( + <PopMenu /> + )) + diff --git a/frontend/app/components/ui/PopMenu/index.js b/frontend/app/components/ui/PopMenu/index.js new file mode 100644 index 000000000..ab316bab1 --- /dev/null +++ b/frontend/app/components/ui/PopMenu/index.js @@ -0,0 +1 @@ +export { default } from './PopMenu'; diff --git a/frontend/app/components/ui/PopMenu/popMenu.css b/frontend/app/components/ui/PopMenu/popMenu.css new file mode 100644 index 000000000..e2e2d7065 --- /dev/null +++ b/frontend/app/components/ui/PopMenu/popMenu.css @@ -0,0 +1,83 @@ +@import 'mixins.css'; + +.wrapper { + position: relative; + bottom: 0; + right: 0; +} + +.menuItems { + display: flex; + flex-direction: column; + position: absolute; + right: 6px; + bottom: 70px; + align-items: flex-end; + + & .menuItemButton { + width: 50px; + height: 50px; + border-radius: 25px; + + border-radius: 25px; + transition: all 0.4s; + + @mixin shadow; + margin-top: 10px; + + & .buttonLabel { + opacity: 0; + color: $teal; + margin-right: 40px; + white-space: nowrap; + transition: all 0.1s; + } + + &:hover { + width: 100%; + transition: all 0.2s; + padding-left: 20px; + & .buttonLabel { + opacity: 1; + transition: all 0.2s; + } + } + + & .icon { + position: absolute; + right: 17px; + } + } +} + +.addStepButton { + position: absolute; + width: 60px; + height: 60px; + border-radius: 50%; + color: $green; + right: 0; + bottom: 0; + transition: all 0.2s; + box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.3); + transition: all 0.2s; + + &:hover { + background-color: $teal-dark; + box-shadow: 0 2px 7px 0 rgba(0, 0, 0, 0.3); + transition: all 0.2s; + } + + & .plusIcon { + transition: all 0.3s; + filter: drop-shadow( 1px 1px 1px rgba(0, 0, 0, 0.2) ); + } + + &.openMenuBtn { + background-color: $gray-darkest; + & .plusIcon { + transform: rotate(45deg) !important; + transition: all 0.3s; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/Popup/Popup.js b/frontend/app/components/ui/Popup/Popup.js new file mode 100644 index 000000000..9ba5f3804 --- /dev/null +++ b/frontend/app/components/ui/Popup/Popup.js @@ -0,0 +1,10 @@ +import { Popup } from 'semantic-ui-react'; + +export default ({ + position, ...props +}) => ( + <Popup + { ...props } + position={ position || 'top left' } + /> +); diff --git a/frontend/app/components/ui/Popup/Popup.stories.js b/frontend/app/components/ui/Popup/Popup.stories.js new file mode 100644 index 000000000..022c84731 --- /dev/null +++ b/frontend/app/components/ui/Popup/Popup.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Popup from '.'; + +storiesOf('Popup', module) + .add('Pure', () => ( + <Popup /> + )) + diff --git a/frontend/app/components/ui/Popup/index.js b/frontend/app/components/ui/Popup/index.js new file mode 100644 index 000000000..ab5f1602c --- /dev/null +++ b/frontend/app/components/ui/Popup/index.js @@ -0,0 +1 @@ +export { default } from './Popup'; \ No newline at end of file diff --git a/frontend/app/components/ui/Progress/Progress.js b/frontend/app/components/ui/Progress/Progress.js new file mode 100644 index 000000000..32d5426a8 --- /dev/null +++ b/frontend/app/components/ui/Progress/Progress.js @@ -0,0 +1,10 @@ +import { Progress } from 'semantic-ui-react'; + +export default ({ + percent, ...props +}) => ( + <Progress + percent={ percent } + { ...props } + /> +); diff --git a/frontend/app/components/ui/Progress/Progress.stories.js b/frontend/app/components/ui/Progress/Progress.stories.js new file mode 100644 index 000000000..95a14f813 --- /dev/null +++ b/frontend/app/components/ui/Progress/Progress.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Progress from '.'; + +storiesOf('Progress', module) + .add('Pure', () => ( + <Progress /> + )) + diff --git a/frontend/app/components/ui/Progress/index.js b/frontend/app/components/ui/Progress/index.js new file mode 100644 index 000000000..66510020d --- /dev/null +++ b/frontend/app/components/ui/Progress/index.js @@ -0,0 +1 @@ +export { default } from './Progress'; \ No newline at end of file diff --git a/frontend/app/components/ui/QuestionMarkHint/QuestionMarkHint.js b/frontend/app/components/ui/QuestionMarkHint/QuestionMarkHint.js new file mode 100644 index 000000000..5dc6965fb --- /dev/null +++ b/frontend/app/components/ui/QuestionMarkHint/QuestionMarkHint.js @@ -0,0 +1,16 @@ +import cn from "classnames"; +import { Icon, Popup } from 'UI'; + +export default function QuestionMarkHint({ onHover = false, content, className, ...props }) { + return ( + <Popup + on={ onHover ? 'hover' : 'click'} + content={ content } + inverted + trigger={ + <Icon name="question-circle" size="18" className={ cn("cursor-pointer", className) }/> + } + { ...props } + /> + ); +} \ No newline at end of file diff --git a/frontend/app/components/ui/QuestionMarkHint/index.js b/frontend/app/components/ui/QuestionMarkHint/index.js new file mode 100644 index 000000000..0fbc359a8 --- /dev/null +++ b/frontend/app/components/ui/QuestionMarkHint/index.js @@ -0,0 +1 @@ +export { default } from './QuestionMarkHint'; \ No newline at end of file diff --git a/frontend/app/components/ui/RandomElement/RandomElement.js b/frontend/app/components/ui/RandomElement/RandomElement.js new file mode 100644 index 000000000..ad19b1548 --- /dev/null +++ b/frontend/app/components/ui/RandomElement/RandomElement.js @@ -0,0 +1,40 @@ +import React from 'react'; + +let interval = null; +class RandomElement extends React.Component { + state = { currentIndex: 0 } + + getRandomNumber = () => { + return Math.floor(Math.random() * this.props.list.length) + } + + componentDidMount() { + const { list } = this.props; + if (list && list.length > 0) { + interval = setInterval(function() { + this.setState({ currentIndex: this.getRandomNumber() }) + }.bind(this), 2000); + } + } + + componentWillUnmount() { + clearInterval(interval) + } + + render() { + const { list, onClick } = this.props; + const { currentIndex } = this.state; + if (currentIndex < 0) return ''; + + const currentItem = list[currentIndex]; + if (!currentItem) return ''; + + return ( + <React.Fragment> + { currentItem.element } + </React.Fragment> + ); + } +} + +export default RandomElement; diff --git a/frontend/app/components/ui/RandomElement/index.js b/frontend/app/components/ui/RandomElement/index.js new file mode 100644 index 000000000..9aad2d474 --- /dev/null +++ b/frontend/app/components/ui/RandomElement/index.js @@ -0,0 +1 @@ +export { default } from './RandomElement'; \ No newline at end of file diff --git a/frontend/app/components/ui/SavedSearchList/ListItem.js b/frontend/app/components/ui/SavedSearchList/ListItem.js new file mode 100644 index 000000000..5f4e61dd0 --- /dev/null +++ b/frontend/app/components/ui/SavedSearchList/ListItem.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { Icon } from 'UI'; +import cn from "classnames"; +import stl from './listItem.css'; + +const ListItem = ({icon, label, onClick, onRemove }) => { + return ( + <div className={ cn(stl.wrapper, 'flex items-center capitalize') } onClick={ onClick }> + <div className="flex items-center mr-auto"> + <Icon name={ icon } color="teal" size="16" /> + <span className="ml-3">{ label }</span> + </div> + <div className={ cn(stl.actionWrapper, "p-2")} onClick={onRemove}> + <Icon name="trash" color="teal" size="12" /> + </div> + </div> + ); +}; + +export default ListItem; diff --git a/frontend/app/components/ui/SavedSearchList/SavedSearchList.js b/frontend/app/components/ui/SavedSearchList/SavedSearchList.js new file mode 100644 index 000000000..3bbd8d05b --- /dev/null +++ b/frontend/app/components/ui/SavedSearchList/SavedSearchList.js @@ -0,0 +1,159 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import stl from './savedSearchList.css'; +import cn from 'classnames'; +import { Icon, IconButton, Loader, Button } from 'UI'; +import { confirm } from 'UI/Confirmation'; +import { withRouter } from 'react-router-dom'; +import { addEvent } from 'Duck/filters'; +import { + fetchList as fetchFunnelsList, + applySavedFilter, + remove as deleteSearch, + setActiveFlow, + clearEvents, + init +} from 'Duck/funnels'; +import { setActiveTab } from 'Duck/sessions'; +import { funnel as funnelRoute, withSiteId } from 'App/routes'; +import Event, { TYPES } from 'Types/filter/event'; +import FunnelMenuItem from 'Components/Funnels/FunnelMenuItem'; +import FunnelSaveModal from 'Components/Funnels/FunnelSaveModal'; +import NewBadge from 'Shared/NewBadge'; +import { blink as setBlink } from 'Duck/funnels'; + +const DEFAULT_VISIBLE = 3; +@withRouter +class SavedSearchList extends React.Component { + state = { showMore: false, showSaveModal: false } + + setFlow = flow => { + this.props.setActiveTab({ name: 'All', type: 'all' }); + this.props.setActiveFlow(flow) + if (flow && flow.type === 'flows') { + this.props.clearEvents() + } + } + + renameHandler = funnel => { + this.props.init(funnel); + this.setState({ showSaveModal: true }) + } + + deleteSearch = async (e, funnel) => { + e.preventDefault(); + e.stopPropagation(); + + if (await confirm({ + header: 'Delete Funnel', + confirmButton: 'Delete', + confirmation: `Are you sure you want to permanently delete "${funnel.name}"?` + })) { + this.props.deleteSearch(funnel.funnelId).then(function() { + this.props.fetchFunnelsList(); + this.setState({ showSaveModal: false }) + }.bind(this)); + } else {} + } + + createHandler = () => { + const { events } = this.props; + if (events.size === 0) { + this.props.addEvent(Event({ type: TYPES.LOCATION, key: TYPES.LOCATION } )) + this.props.addEvent(Event({ type: TYPES.LOCATION, key: TYPES.LOCATION } )) + this.props.addEvent(Event({ type: TYPES.CLICK, key: TYPES.CLICK } )) + } else { + this.props.setBlink() + } + } + + onFlowClick = ({ funnelId }) => { + const { siteId, history } = this.props; + history.push(withSiteId(funnelRoute(funnelId), siteId)); + } + + render() { + const { funnels, activeFlow, activeTab, loading } = this.props; + const { showMore, showSaveModal } = this.state; + const shouldLimit = funnels.size > DEFAULT_VISIBLE; + + return ( + <div className={ stl.wrapper }> + <FunnelSaveModal + show={showSaveModal} + closeHandler={() => this.setState({ showSaveModal: false })} + /> + <Loader loading={loading} size="small"> + <div className={ cn(stl.header, 'mt-3') }> + <div className={ cn(stl.label, 'flex items-center relative') }> + <span className="mr-2">Funnels</span> + + { funnels.size > 0 && ( + <IconButton + tooltip="Create Funnel" + circle + size="small" + icon="plus" + outline + onClick={ this.createHandler } + /> + )} + <div className="ml-2">{ <NewBadge />}</div> + </div> + </div> + { funnels.size === 0 && + <div className="flex flex-col"> + <div className="color-gray-medium text-justify font-light mb-2"> + Funnels makes it easy to uncover the most significant issues that impacted conversions. + </div> + <IconButton className="-ml-2" icon="plus" label="Create Funnel" primaryText onClick={ this.createHandler } /> + </div> + } + { funnels.size > 0 && + <React.Fragment> + { funnels.take(showMore ? funnels.size : DEFAULT_VISIBLE).map(filter => ( + <div key={filter.key}> + <FunnelMenuItem + title={filter.name} + isPublic={filter.isPublic} + iconName="filter" + active={activeFlow && activeFlow.funnelId === filter.funnelId && activeTab.type !== 'flows'} + onClick={ () => this.onFlowClick(filter)} + deleteHandler={ (e) => this.deleteSearch(e, filter) } + renameHandler={() => this.renameHandler(filter)} + /> + </div> + ))} + { shouldLimit && + <div + onClick={() => this.setState({ showMore: !showMore})} + className={cn(stl.showMore, 'cursor-pointer py-2 flex items-center')} + > + {/* <Icon name={showMore ? 'arrow-up' : 'arrow-down'} size="16"/> */} + <span className="ml-4 color-teal text-sm">{ showMore ? 'SHOW LESS' : 'SHOW MORE' }</span> + </div> + } + </React.Fragment> + } + </Loader> + </div> + ); + } +} + +export default connect(state => ({ + funnels: state.getIn([ 'funnels', 'list' ]), + loading: state.getIn(['funnels', 'fetchListRequest', 'loading']), + activeFlow: state.getIn([ 'filters', 'activeFlow' ]), + activeTab: state.getIn([ 'sessions', 'activeTab' ]), + siteId: state.getIn([ 'user', 'siteId' ]), + events: state.getIn([ 'filters', 'appliedFilter', 'events' ]), +}), { + applySavedFilter, + deleteSearch, setActiveTab, + setActiveFlow, clearEvents, + addEvent, + init, + fetchFunnelsList, + setBlink +})(SavedSearchList) diff --git a/frontend/app/components/ui/SavedSearchList/index.js b/frontend/app/components/ui/SavedSearchList/index.js new file mode 100644 index 000000000..009c383d7 --- /dev/null +++ b/frontend/app/components/ui/SavedSearchList/index.js @@ -0,0 +1 @@ +export { default } from './SavedSearchList' \ No newline at end of file diff --git a/frontend/app/components/ui/SavedSearchList/listItem.css b/frontend/app/components/ui/SavedSearchList/listItem.css new file mode 100644 index 000000000..dcf9fdddd --- /dev/null +++ b/frontend/app/components/ui/SavedSearchList/listItem.css @@ -0,0 +1,24 @@ +.wrapper { + padding: 4px 5px; + cursor: pointer; + border: solid thin transparent; + border-radius: 3px; + margin-left: -5px; + + &.active, + &:hover { + background-color: $active-blue; + border-color: $active-blue-border; + & .actionWrapper { + opacity: 1; + } + } + + & span { + color: $teal + } + + & .actionWrapper { + opacity: 0; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/SavedSearchList/savedSearchList.css b/frontend/app/components/ui/SavedSearchList/savedSearchList.css new file mode 100644 index 000000000..1b6a2aeb4 --- /dev/null +++ b/frontend/app/components/ui/SavedSearchList/savedSearchList.css @@ -0,0 +1,20 @@ +.header { + margin-bottom: 15px; + & .label { + text-transform: uppercase; + color: gray; + letter-spacing: 0.2em; + } +} + +.showMore { + &:hover { + color: $teal; + & svg { + fill: $teal; + } + & .actions { + opacity: 1; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js new file mode 100644 index 000000000..c4d71a93a --- /dev/null +++ b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js @@ -0,0 +1,37 @@ +import React from 'react'; +import { Icon } from 'UI'; +import cn from 'classnames'; +import styles from './segmentSelection.css'; + +class SegmentSelection extends React.Component { + setActiveItem = (item) => { + this.props.onSelect(null, { name: this.props.name, value: item.value }); + } + + render() { + const { className, list, primary = false, size = "normal" } = this.props; + + return ( + <div className={ cn(styles.wrapper, { + [styles.primary] : primary, + [styles.small] : size === 'small' + }, className) } + > + { list.map(item => ( + <div + key={ item.name } + className={ styles.item } + data-active={ this.props.value && this.props.value.value === item.value } + onClick={ () => this.setActiveItem(item) } + > + { item.icon && <Icon name={ item.icon } size="20" marginRight="10" /> } + <div>{ item.name }</div> + </div> + )) + } + </div> + ); + } +} + +export default SegmentSelection; diff --git a/frontend/app/components/ui/SegmentSelection/SegmentSelection.stories.js b/frontend/app/components/ui/SegmentSelection/SegmentSelection.stories.js new file mode 100644 index 000000000..ba6b2d5b1 --- /dev/null +++ b/frontend/app/components/ui/SegmentSelection/SegmentSelection.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import SegmentSelection from '.'; + +storiesOf('SegmentSelection', module) + .add('Pure', () => ( + <SegmentSelection /> + )) + diff --git a/frontend/app/components/ui/SegmentSelection/index.js b/frontend/app/components/ui/SegmentSelection/index.js new file mode 100644 index 000000000..c49d186e8 --- /dev/null +++ b/frontend/app/components/ui/SegmentSelection/index.js @@ -0,0 +1 @@ +export { default } from './SegmentSelection'; diff --git a/frontend/app/components/ui/SegmentSelection/segmentSelection.css b/frontend/app/components/ui/SegmentSelection/segmentSelection.css new file mode 100644 index 000000000..543016246 --- /dev/null +++ b/frontend/app/components/ui/SegmentSelection/segmentSelection.css @@ -0,0 +1,64 @@ +.wrapper { + display: flex; + align-items: center; + justify-content: space-around; + border: solid thin $gray-light; + border-radius: 5px; + overflow: hidden; + + & .item { + color: $gray-medium; + font-weight: medium; + padding: 10px; + flex: 1; + text-align: center; + border-right: solid thin $gray-light; + cursor: pointer; + background-color: $gray-lightest; + display: flex; + align-items: center; + justify-content: center; + + & span svg { + fill: $gray-medium; + } + + &[data-active=true] { + background-color: white; + color: $teal; + + & span svg { + fill: $teal; + } + } + + &:last-child { + border: none; + } + + &:hover { + background-color: white; + color: $teal; + + & span svg { + fill: $teal; + } + } + } +} + +.primary { + border: solid thin $teal; + & .item { + color: $teal; + background-color: white; + &[data-active=true] { + background-color: $teal; + color: white; + } + } +} + +.small .item { + padding: 4px 8px; +} \ No newline at end of file diff --git a/frontend/app/components/ui/Select/Select.js b/frontend/app/components/ui/Select/Select.js new file mode 100644 index 000000000..4a0e80709 --- /dev/null +++ b/frontend/app/components/ui/Select/Select.js @@ -0,0 +1,14 @@ +import { Select } from 'semantic-ui-react'; + +export default ({ + placeholder, options, value, onChange, ...props +}) => ( + <Select + { ...props } + placeholder={ placeholder } + options={ options } + value={ value } + onChange={ onChange } + selection + /> +); diff --git a/frontend/app/components/ui/Select/Select.stories.js b/frontend/app/components/ui/Select/Select.stories.js new file mode 100644 index 000000000..bd98b5632 --- /dev/null +++ b/frontend/app/components/ui/Select/Select.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Select from '.'; + +storiesOf('Select', module) + .add('Pure', () => ( + <Select /> + )) + diff --git a/frontend/app/components/ui/Select/index.js b/frontend/app/components/ui/Select/index.js new file mode 100644 index 000000000..b56d05f24 --- /dev/null +++ b/frontend/app/components/ui/Select/index.js @@ -0,0 +1 @@ +export { default } from './Select'; \ No newline at end of file diff --git a/frontend/app/components/ui/SideMenuitem/SideMenuitem.js b/frontend/app/components/ui/SideMenuitem/SideMenuitem.js new file mode 100644 index 000000000..24720e785 --- /dev/null +++ b/frontend/app/components/ui/SideMenuitem/SideMenuitem.js @@ -0,0 +1,41 @@ +import React from 'react'; +import { Icon, Popup } from 'UI'; +import cn from 'classnames'; +import stl from './sideMenuItem.css'; + +function SideMenuitem({ iconBg = false, iconColor = "gray-dark", iconSize = 18, className, iconName = 'info', title, active = false, disabled = false, onClick, deleteHandler, ...props }) { + return ( + <Popup + trigger={ + <div + className={ cn( + className, + stl.menuItem, + "flex items-center py-2 justify-between", + { [stl.active] : active } + )} + onClick={disabled ? null : onClick} + {...props} + > + <div className={ cn(stl.iconLabel, 'flex items-center', { [stl.disabled] : disabled })}> + <div className="flex items-center justify-center w-8 h-8"> + <div className={cn({ "w-8 h-8 rounded-full relative opacity-20" : iconBg }, iconBg)} style={{ opacity: '0.2'}} /> + <Icon name={ iconName } size={ iconSize } color={active ? 'teal' : iconColor} className="absolute" /> + </div> + <span className={stl.title}>{ title }</span> + </div> + {deleteHandler && + <div onClick={deleteHandler} className={stl.actions}><Icon name="trash" size="14" /></div> + } + </div> + } + disabled={ !disabled } + content={ 'No Sessions' } + size="tiny" + inverted + position="left center" + /> + ) +} + +export default SideMenuitem diff --git a/frontend/app/components/ui/SideMenuitem/index.js b/frontend/app/components/ui/SideMenuitem/index.js new file mode 100644 index 000000000..f0572c532 --- /dev/null +++ b/frontend/app/components/ui/SideMenuitem/index.js @@ -0,0 +1 @@ +export { default } from './SideMenuitem'; \ No newline at end of file diff --git a/frontend/app/components/ui/SideMenuitem/sideMenuItem.css b/frontend/app/components/ui/SideMenuitem/sideMenuItem.css new file mode 100644 index 000000000..6b7d0743e --- /dev/null +++ b/frontend/app/components/ui/SideMenuitem/sideMenuItem.css @@ -0,0 +1,38 @@ +.menuItem { + border-radius: 3px; + border: solid thin transparent; + color: $gray-dark; + cursor: pointer; + + &:hover { + color: $teal; + & svg { + fill: $teal; + } + & .actions { + opacity: 1; + } + } + &.active { + color: $teal; + } + + & .disabled { + opacity: 0.5; + } + + & .iconLabel { + max-width: 85%; + } + & .title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-left: 10px; + margin-top: 1px; + } + + & .actions { + opacity: 0; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/SlideModal/SlideModal.js b/frontend/app/components/ui/SlideModal/SlideModal.js new file mode 100644 index 000000000..cc329463c --- /dev/null +++ b/frontend/app/components/ui/SlideModal/SlideModal.js @@ -0,0 +1,61 @@ +import styles from './slideModal.css'; +import cn from 'classnames'; +export default class SlideModal extends React.PureComponent { + componentDidMount() { + document.addEventListener('keydown', this.keyPressHandler); + } + + componentWillUnmount() { + document.removeEventListener('keydown', this.keyPressHandler); + } + + keyPressHandler = (e) => { + if (e.key === 'Escape' && this.props.onClose) { + this.props.onClose(false); // false for togglers (?) + } + } + + render() { + const { + title, + subtitle, + onClose, + content, + isDisplayed, + size = 'big', + detailContent, + right = false, + bgColor="white", + overlay = true + } = this.props; + return ( + <div + className={ cn(styles.main, right ? styles.right : styles.left) } + data-displayed={ isDisplayed } + > + <div + className={ cn( { [styles.overlay] : overlay }) } + data-displayed={ isDisplayed } + onClick={ onClose ? onClose : null } + role="button" + /> + + <div className={ cn(styles.contentWrapper, 'bg-' + bgColor) } data-size={ size } > + <div className={ cn(styles.mainPanel) }> + { title && + <div className={ cn(styles.header, 'text-2xl') }> + { title } + { subtitle && <div className="text-sm mt-2">{ subtitle }</div>} + </div> + } + { content } + </div> + <div className={ styles.detailContent } data-displayed={ !!detailContent } > + { detailContent } + </div> + </div> + + </div> + ); + } +} diff --git a/frontend/app/components/ui/SlideModal/SlideModal.stories.js b/frontend/app/components/ui/SlideModal/SlideModal.stories.js new file mode 100644 index 000000000..7bead9cbe --- /dev/null +++ b/frontend/app/components/ui/SlideModal/SlideModal.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import SlideModal from '.'; + +storiesOf('SlideModal', module) + .add('Pure', () => ( + <SlideModal /> + )) + diff --git a/frontend/app/components/ui/SlideModal/SlideModalProvider.js b/frontend/app/components/ui/SlideModal/SlideModalProvider.js new file mode 100644 index 000000000..ca25d9ab4 --- /dev/null +++ b/frontend/app/components/ui/SlideModal/SlideModalProvider.js @@ -0,0 +1,8 @@ +import { createContext } from 'react'; + +const ModalContext = createContext({ + component: null, + props: {}, + showModal: () => {}, + hideModal: () => {} +}); \ No newline at end of file diff --git a/frontend/app/components/ui/SlideModal/index.js b/frontend/app/components/ui/SlideModal/index.js new file mode 100644 index 000000000..ebe2e27d5 --- /dev/null +++ b/frontend/app/components/ui/SlideModal/index.js @@ -0,0 +1 @@ +export { default } from './SlideModal'; diff --git a/frontend/app/components/ui/SlideModal/slideModal.css b/frontend/app/components/ui/SlideModal/slideModal.css new file mode 100644 index 000000000..bdbbb8bad --- /dev/null +++ b/frontend/app/components/ui/SlideModal/slideModal.css @@ -0,0 +1,192 @@ +$padding: 23px; + +@keyframes fadeInRight { + 0% { + transform: translate(-100%,0px); + } + 100% { + transform: translate(0,0px); + } +} + +@keyframes fadeInLeft { + 0% { + transform: translate(1000px,0px); + } + 100% { + transform: translate(0px,0px); + } +} + +.main { + &.left { + & .contentWrapper { + left: -200%; + } + } + + &.right { + & .contentWrapper { + right: -1000px; + } + } +} + +.mainPanel { + box-shadow: 5px 0 5px rgba(0,0,0,.05); + z-index: 1; + height: 100vh; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 2px; + } + + &::-webkit-scrollbar-thumb { + background: transparent; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &:hover { + &::-webkit-scrollbar-track { + background: #f3f3f3; + } + &::-webkit-scrollbar-thumb { + background: $gray-medium; + } + } +} + +.contentWrapper { + background: $white; + position: fixed; + top: 0; + bottom: 0; + height: 100vh; + display: flex; + flex-direction: column; + z-index: 102; /* stay top of the test builer stiky header */ + transition: left .2s ease-in-out; + + &[data-size=big] { + width: 1006px; + } + + &[data-size=middle] { + width: 500px; + } + + &[data-size=lg] { + width: 400px; + } + + &[data-size=small] { + width: 350px; + } + +} + +.content { + z-index: 1; + height: 100%; + background: $white; +} + +.detailContent { + position: absolute; + top: 0; + bottom: 0; + background-color: $white; + border-left: solid 2px $gray-lightest; + left: 0; + height: 100vh; + overflow-y: auto; + + &[data-displayed=true] { + left: 100%; + } + + &::-webkit-scrollbar { + width: 2px; + } + + &::-webkit-scrollbar-thumb { + background: transparent; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &:hover { + &::-webkit-scrollbar-track { + background: #f3f3f3; + } + &::-webkit-scrollbar-thumb { + background: $gray-medium; + } + } +} + + +.header { + font-size: 20px; + padding: 20px 14px; +} + +.overlay { + background-color: rgba(0, 0, 0, 0.5); + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 100%; + z-index: 102; /* stay top of the test builer stiky header */ + opacity: 0; + transition: opacity 0.2s; +} + +.main[data-displayed=true] { + & > .overlay { + right: 0; + opacity: 1; + transition: opacity 0.6s; + } + + &.left { + & > .contentWrapper { + left: 0; + animation: fadeInRight ease-in-out 0.3s; + animation-iteration-count: 1; + transform-origin: 50% 50%; + animation-fill-mode:forwards; + } + + & > .closeWrapper { + top: 30px; + right: 30px; + transition: all 0.3s ease-in; + } + } + + &.right { + & > .contentWrapper { + right: 0; + animation: fadeInLeft ease-in-out 0.3s; + animation-iteration-count: 1; + transform-origin: 50% 50%; + animation-fill-mode:forwards; + } + + & > .closeWrapper { + top: 30px; + left: 30px; + transition: all 0.3s ease-in; + } + } + + & .closeWrapper { + top: 30px; + right: 30px; + transition: all 0.3s ease-in; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/Slider/Slider.js b/frontend/app/components/ui/Slider/Slider.js new file mode 100644 index 000000000..58350b91c --- /dev/null +++ b/frontend/app/components/ui/Slider/Slider.js @@ -0,0 +1,9 @@ +import { Checkbox } from 'semantic-ui-react'; + +export default ({ className="", ...props }) => ( + <Checkbox + { ...props } + toggle + className={ `customCheckbox ${ className }` } + /> +); \ No newline at end of file diff --git a/frontend/app/components/ui/Slider/Slider.stories.js b/frontend/app/components/ui/Slider/Slider.stories.js new file mode 100644 index 000000000..ab0c0f5dd --- /dev/null +++ b/frontend/app/components/ui/Slider/Slider.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Slider from '.'; + +storiesOf('Slider', module) + .add('Pure', () => ( + <Slider /> + )) + diff --git a/frontend/app/components/ui/Slider/index.js b/frontend/app/components/ui/Slider/index.js new file mode 100644 index 000000000..eed87a07a --- /dev/null +++ b/frontend/app/components/ui/Slider/index.js @@ -0,0 +1 @@ +export { default } from './Slider'; \ No newline at end of file diff --git a/frontend/app/components/ui/SplitButton/SplitButton.js b/frontend/app/components/ui/SplitButton/SplitButton.js new file mode 100644 index 000000000..bcb8cb616 --- /dev/null +++ b/frontend/app/components/ui/SplitButton/SplitButton.js @@ -0,0 +1,19 @@ +import React from 'react'; +import { Button, Icon } from 'UI'; +import cn from 'classnames'; +import stl from './splitButton.css'; + +const SplitButton = ({primary, label, icon, onButtonClick, onIconClick, disabled = false }) => { + return ( + <div className={cn('flex items-center', disabled? 'btn-disabled' : '')}> + <Button size="small" outline className={ stl.left } onClick={ onButtonClick }> + { label } + </Button> + <Button size="small" outline className={ stl.right } onClick={ onIconClick }> + <Icon className={ stl.icon } name={ icon } size="14" color={ primary ? 'teal' : '' } /> + </Button> + </div> + ); +}; + +export default SplitButton; diff --git a/frontend/app/components/ui/SplitButton/SplitButton.stories.js b/frontend/app/components/ui/SplitButton/SplitButton.stories.js new file mode 100644 index 000000000..51b78fadc --- /dev/null +++ b/frontend/app/components/ui/SplitButton/SplitButton.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import SplitButton from './SplitButton'; + +storiesOf('SplitButton', module) + .add('Pure', () => ( + <SplitButton label="Issues" primary icon="plus" /> + )) + diff --git a/frontend/app/components/ui/SplitButton/index.js b/frontend/app/components/ui/SplitButton/index.js new file mode 100644 index 000000000..2e35014dc --- /dev/null +++ b/frontend/app/components/ui/SplitButton/index.js @@ -0,0 +1 @@ +export { default } from './SplitButton'; \ No newline at end of file diff --git a/frontend/app/components/ui/SplitButton/splitButton.css b/frontend/app/components/ui/SplitButton/splitButton.css new file mode 100644 index 000000000..46dc7f26a --- /dev/null +++ b/frontend/app/components/ui/SplitButton/splitButton.css @@ -0,0 +1,16 @@ +.left { + margin: 0 !important; + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; + border: solid thin $teal !important; + border-right: 0 !important; + box-shadow: none !important; +} + +.right { + border-top-left-radius: 0 !important; + border-bottom-left-radius: 0 !important; + box-shadow: none !important; + border: solid thin $teal !important; + padding: 0 12px !important; +} \ No newline at end of file diff --git a/frontend/app/components/ui/Tabs/Tabs.js b/frontend/app/components/ui/Tabs/Tabs.js new file mode 100644 index 000000000..10ee939c0 --- /dev/null +++ b/frontend/app/components/ui/Tabs/Tabs.js @@ -0,0 +1,23 @@ +import cn from 'classnames'; +import stl from './tabs.css'; + +const Tabs = ({ tabs, active, onClick, border = true, className }) => ( + <div className={ cn(stl.tabs, className, { [ stl.bordered ]: border }) } role="tablist" > + { tabs.map(({ key, text, hidden = false, disabled = false }) => ( + <div + key={ key } + className={ cn(stl.tab, { [ stl.active ]: active === key, [ stl.disabled ]: disabled }) } + data-hidden={ hidden } + onClick={ onClick && (() => onClick(key)) } + role="tab" + data-openreplay-label={text} + > + { text } + </div> + ))} + </div> +); + +Tabs.displayName = 'Tabs'; + +export default Tabs; \ No newline at end of file diff --git a/frontend/app/components/ui/Tabs/Tabs.stories.js b/frontend/app/components/ui/Tabs/Tabs.stories.js new file mode 100644 index 000000000..bcb739725 --- /dev/null +++ b/frontend/app/components/ui/Tabs/Tabs.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Tabs from '.'; + +storiesOf('Tabs', module) + .add('Pure', () => ( + <Tabs /> + )) + diff --git a/frontend/app/components/ui/Tabs/index.js b/frontend/app/components/ui/Tabs/index.js new file mode 100644 index 000000000..bc6749b1b --- /dev/null +++ b/frontend/app/components/ui/Tabs/index.js @@ -0,0 +1 @@ +export { default } from './Tabs'; diff --git a/frontend/app/components/ui/Tabs/tabs.css b/frontend/app/components/ui/Tabs/tabs.css new file mode 100644 index 000000000..4bc951f36 --- /dev/null +++ b/frontend/app/components/ui/Tabs/tabs.css @@ -0,0 +1,33 @@ +.tabs { + display: flex; + justify-content: flex-start; + align-items: center; + &.bordered { + border-bottom: solid thin $gray-light; + } +} + +.tab { + padding: 10px 15px; + cursor: pointer; + transition: all 0.2s; + color: $gray-darkest; + border-bottom: solid thin transparent; + margin-bottom: -1px; + font-weight: 500; + white-space: nowrap; + + &:hover { + color: $teal; + } + + &.active { + color: $teal; + border-bottom: solid thin $teal; + } +} + +.disabled { + pointer-events: none; + opacity: 0.5; +} \ No newline at end of file diff --git a/frontend/app/components/ui/TagBadge/TagBadge.js b/frontend/app/components/ui/TagBadge/TagBadge.js new file mode 100644 index 000000000..40d52ada0 --- /dev/null +++ b/frontend/app/components/ui/TagBadge/TagBadge.js @@ -0,0 +1,32 @@ +import cn from 'classnames'; +import styles from './tagBadge.css'; + +export default class TagBadge extends React.PureComponent { + + onClick = () => { + if (this.props.onClick) { + this.props.onClick(this.props.text); + } + } + + render() { + const { + className, text, onRemove, onClick, hashed = true, outline = false, + } = this.props; + return ( + <div + className={ cn(styles.badge, { "cursor-pointer": !!onClick }, className) } + onClick={ this.onClick } + data-hashed={ hashed } + data-outline={ outline } + > + <span>{ text }</span> + { onRemove && + <button type="button" onClick={ onRemove }> + <i className={ styles.closeIcon } /> + </button> + } + </div> + ); + } +} diff --git a/frontend/app/components/ui/TagBadge/TagBadge.stories.js b/frontend/app/components/ui/TagBadge/TagBadge.stories.js new file mode 100644 index 000000000..6b4c12a5b --- /dev/null +++ b/frontend/app/components/ui/TagBadge/TagBadge.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import TagBadge from '.'; + +storiesOf('TagBadge', module) + .add('Pure', () => ( + <TagBadge /> + )) + diff --git a/frontend/app/components/ui/TagBadge/index.js b/frontend/app/components/ui/TagBadge/index.js new file mode 100644 index 000000000..81a1c897a --- /dev/null +++ b/frontend/app/components/ui/TagBadge/index.js @@ -0,0 +1 @@ +export { default } from './TagBadge'; diff --git a/frontend/app/components/ui/TagBadge/tagBadge.css b/frontend/app/components/ui/TagBadge/tagBadge.css new file mode 100644 index 000000000..46aad3cf6 --- /dev/null +++ b/frontend/app/components/ui/TagBadge/tagBadge.css @@ -0,0 +1,45 @@ + +@import 'icons.css'; + +.badge { + padding: 2px 10px; + border-radius: 15px; + background-color: white; + display: flex; + align-items: center; + font-size: 13px; + height: 29px; + margin-right: 8px; + font-weight: 300; + user-select: none; + text-transform: capitalize; + color: $gray-dark !important; + + &[data-outline=true] { + box-shadow: 0 0 0 1px $gray-light inset; + backgorund-color: white; + } + + &:hover { + background-color: $active-blue; + } + + & button { + margin-left: 2px; + margin-right: -5px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + & .closeIcon { + @mixin icon close, $gray-medium, 13px; + } + } + + &[data-hashed=true]:before { + content: '#'; + margin-right: 1px; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/TagInput/TagInput.js b/frontend/app/components/ui/TagInput/TagInput.js new file mode 100644 index 000000000..e3245d75f --- /dev/null +++ b/frontend/app/components/ui/TagInput/TagInput.js @@ -0,0 +1,82 @@ +import React from 'react'; +import { Icon, Button } from 'UI'; +import { validateKeyCode } from 'App/validate'; +import styles from './tagInput.css'; + +class TagInput extends React.Component { + constructor(props) { + super(props); + this.state = {}; + } + + componentDidUpdate() { + const { tagEditorDisplayed } = this.props; + if (tagEditorDisplayed && this.inputRef) { + this.inputRef.focus(); + this.inputRef.addEventListener('keydown', this.escapeHandler, false); + } else { + this.inputRef.removeEventListener('keydown', this.escapeHandler); + } + } + + escapeHandler = (e) => { + if (e.keyCode === 27) { + this.props.toggleTagEditor(); + } + } + + handleKeyPress = (e) => { + if (!validateKeyCode(e.keyCode, e.key, new RegExp('^[a-zA-Z0-9]+'))) { + e.preventDefault(); + return; + } + + // add tag on pressing Enter. + if (e.key === 'Enter' && e.target.value.length > 0) { + e.preventDefault(); + this.props.addTag(e.target.value); + e.target.value = ''; + } + } + + render() { + const { toggleTagEditor, tagEditorDisplayed, placeholder = 'Tag' } = this.props; + return ( + <div className={ styles.wrapper }> + <div className={ styles.inputWrapper } data-hidden={ !tagEditorDisplayed } > + <div>{ '#' }</div> + <input + type="text" + ref={ (ref) => { this.inputRef = ref; } } + onKeyPress={ this.handleKeyPress } + placeholder={ placeholder } + /> + </div> + + { tagEditorDisplayed && + <Button + plain + size="small" + onClick={ toggleTagEditor } + > + { 'Cancel' } + </Button> + } + + { !tagEditorDisplayed && + <div ref={ (ref) => { this.addButtonRef = ref; } }> + <div + onClick={ toggleTagEditor } + className="flex items-center cursor-pointer rounded p-2 gray-hover" + > + <Icon name="plus" color="teal" size="12" /> + <div className="ml-2 text-sm font-normal color-teal leading-none">ADD TAG</div> + </div> + </div> + } + </div> + ); + } +} + +export default TagInput; diff --git a/frontend/app/components/ui/TagInput/TagInput.stories.js b/frontend/app/components/ui/TagInput/TagInput.stories.js new file mode 100644 index 000000000..919d1f9c1 --- /dev/null +++ b/frontend/app/components/ui/TagInput/TagInput.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import TagInput from '.'; + +storiesOf('TagInput', module) + .add('Pure', () => ( + <TagInput /> + )) + diff --git a/frontend/app/components/ui/TagInput/index.js b/frontend/app/components/ui/TagInput/index.js new file mode 100644 index 000000000..9d308e8ad --- /dev/null +++ b/frontend/app/components/ui/TagInput/index.js @@ -0,0 +1 @@ +export { default } from './TagInput'; diff --git a/frontend/app/components/ui/TagInput/tagInput.css b/frontend/app/components/ui/TagInput/tagInput.css new file mode 100644 index 000000000..66a7a89f8 --- /dev/null +++ b/frontend/app/components/ui/TagInput/tagInput.css @@ -0,0 +1,35 @@ +.wrapper { + display: flex; + align-items: center; + width: 150px; + + & .inputWrapper { + position: relative; + margin-right: 5px; + + & input { + background-color: white; + border-radius: 15px !important; + padding: 4px; + border: solid thin $gray-light; + padding-left: 25px !important; + width: 120px; + height: 25px; + } + + & div { + z-index: 99; + background-color: $gray-lightest; + position: absolute; + left: 1px; + top: 1px; + bottom: 1px; + width: 20px; + display: flex; + align-items: center; + justify-content: center; + border-top-left-radius: 15px; + border-bottom-left-radius: 15px; + } + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/TagList/TagList.js b/frontend/app/components/ui/TagList/TagList.js new file mode 100644 index 000000000..32877124d --- /dev/null +++ b/frontend/app/components/ui/TagList/TagList.js @@ -0,0 +1,31 @@ +import { TagInput, TagBadge } from 'UI'; +import styles from './tagList.css'; +import cn from 'classnames'; + +const TagList = ({ + tags, onRemove = null, onTagClick, className = '', style, outline = false, + input = false, toggleTagEditor = null, tagEditorDisplayed = null, addTag = null, +}) => ( + <div className={ cn(styles.tagList, className)} style={ style } > + { tags.map(tag => ( + <TagBadge + key={ tag } + text={ tag } + onRemove={ onRemove ? () => onRemove(tag) : null } + onClick={ onTagClick } + outline={ outline } + /> + ))} + { input && + <TagInput + toggleTagEditor={ toggleTagEditor } + tagEditorDisplayed={ tagEditorDisplayed } + addTag={ addTag } + /> + } + </div> +); + +TagList.displayName = 'TagList'; + +export default TagList; diff --git a/frontend/app/components/ui/TagList/TagList.stories.js b/frontend/app/components/ui/TagList/TagList.stories.js new file mode 100644 index 000000000..37d66f280 --- /dev/null +++ b/frontend/app/components/ui/TagList/TagList.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import TagList from '.'; + +storiesOf('TagList', module) + .add('Pure', () => ( + <TagList /> + )) + diff --git a/frontend/app/components/ui/TagList/index.js b/frontend/app/components/ui/TagList/index.js new file mode 100644 index 000000000..6abe6b358 --- /dev/null +++ b/frontend/app/components/ui/TagList/index.js @@ -0,0 +1 @@ +export { default } from './TagList'; diff --git a/frontend/app/components/ui/TagList/tagList.css b/frontend/app/components/ui/TagList/tagList.css new file mode 100644 index 000000000..5ba5f69a5 --- /dev/null +++ b/frontend/app/components/ui/TagList/tagList.css @@ -0,0 +1,12 @@ +.tagList { + display: flex; + align-items: center; + flex-wrap: wrap; + margin-top: -8px; + min-height: 40px; + + & > div { + flex-shrink: 0; + flex-grow: 0; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/TextEllipsis/TextEllipsis.js b/frontend/app/components/ui/TextEllipsis/TextEllipsis.js new file mode 100644 index 000000000..a6d3e6abc --- /dev/null +++ b/frontend/app/components/ui/TextEllipsis/TextEllipsis.js @@ -0,0 +1,39 @@ +import cn from 'classnames'; +import { Popup } from 'UI'; +import styles from './textEllipsis.css'; + +const TextEllipsis = ({ + text, + hintText = text, + children, + maxWidth="auto", + style = {}, + className="", + noHint=false, + popupProps={}, + hintProps={}, + ...props +}) => { + const textOrChildren = text || children; + const trigger = ( + <div + className={ cn(styles.textEllipsis, className) } + style={{ maxWidth, ...style }} + { ...props } + > + { textOrChildren } + </div> + ); + if (noHint) return trigger; + return ( + <Popup + trigger={ trigger } + content={ <div className="customPopupText" { ...hintProps } >{ hintText || textOrChildren }</div> } + { ...popupProps } + /> + ); +}; + +TextEllipsis.displayName ="TextEllipsis"; + +export default TextEllipsis; \ No newline at end of file diff --git a/frontend/app/components/ui/TextEllipsis/TextEllipsis.stories.js b/frontend/app/components/ui/TextEllipsis/TextEllipsis.stories.js new file mode 100644 index 000000000..ec1a4d0fd --- /dev/null +++ b/frontend/app/components/ui/TextEllipsis/TextEllipsis.stories.js @@ -0,0 +1,23 @@ +import { storiesOf } from '@storybook/react'; +import TextEllipsis from '.'; + +storiesOf('TextEllipsis', module) + .add('Pure', () => ( + <TextEllipsis /> + )) + .add('Normal Text', () => ( + <TextEllipsis popupProps={{ wide: 'very'}}> + {'this is test'} + </TextEllipsis> + )) + .add('Inverted', () => ( + <TextEllipsis popupProps={{ wide: 'very', inverted: true }}> + {'this is test'} + </TextEllipsis> + )) + .add('Bigger Text', () => ( + <TextEllipsis popupProps={{ wide: 'very'}}> + <div style={{width: '200px', }}>{'this is the biggest text in the application to test the popup content. this is the biggest text in the application to test the popup content.'}</div> + </TextEllipsis> + )) + diff --git a/frontend/app/components/ui/TextEllipsis/index.js b/frontend/app/components/ui/TextEllipsis/index.js new file mode 100644 index 000000000..d5d1abcec --- /dev/null +++ b/frontend/app/components/ui/TextEllipsis/index.js @@ -0,0 +1 @@ +export { default } from './TextEllipsis'; diff --git a/frontend/app/components/ui/TextEllipsis/textEllipsis.css b/frontend/app/components/ui/TextEllipsis/textEllipsis.css new file mode 100644 index 000000000..9baca35cc --- /dev/null +++ b/frontend/app/components/ui/TextEllipsis/textEllipsis.css @@ -0,0 +1,7 @@ +.textEllipsis { + text-overflow: ellipsis; + overflow: hidden; + display: inline-block; + white-space: nowrap; + max-width: 100%; +} \ No newline at end of file diff --git a/frontend/app/components/ui/TextLabel/TextLabel.js b/frontend/app/components/ui/TextLabel/TextLabel.js new file mode 100644 index 000000000..d5d56f828 --- /dev/null +++ b/frontend/app/components/ui/TextLabel/TextLabel.js @@ -0,0 +1,38 @@ +import { Popup } from 'semantic-ui-react'; +import cn from 'classnames'; +import { Icon } from 'UI'; +import styles from './textLabel.css'; + +export default function TextLabel({ + icon, + label, + minWidth = 0, + maxWidth = false, + popupLabel = false, + textTransform = '', + color = 'gray-medium', + iconColor = color, +}) { + return ( + <div className={ cn("flex items-center", styles.sessionLabel) } style={ { minWidth: `${ minWidth }` } }> + <Icon name={ icon } size="16" color={ iconColor } /> + { popupLabel ? + <Popup + trigger={ + <div style={ { maxWidth: `${ maxWidth }px` } } className={textTransform}>{ label }</div> + } + content={ popupLabel } + size="mini" + inverted + /> + : + <div + style={ { maxWidth: `${ maxWidth }px`, lineHeight: '16px' } } + className={cn(`color-${color}`, textTransform)} // textTransform by tailwind + > + { label } + </div> + } + </div> + ); +} diff --git a/frontend/app/components/ui/TextLabel/TextLabel.stories.js b/frontend/app/components/ui/TextLabel/TextLabel.stories.js new file mode 100644 index 000000000..01633eabf --- /dev/null +++ b/frontend/app/components/ui/TextLabel/TextLabel.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import TextLabel from '.'; + +storiesOf('TextLabel', module) + .add('Pure', () => ( + <TextLabel /> + )) + diff --git a/frontend/app/components/ui/TextLabel/index.js b/frontend/app/components/ui/TextLabel/index.js new file mode 100644 index 000000000..78fa8869c --- /dev/null +++ b/frontend/app/components/ui/TextLabel/index.js @@ -0,0 +1 @@ +export { default } from './TextLabel'; diff --git a/frontend/app/components/ui/TextLabel/textLabel.css b/frontend/app/components/ui/TextLabel/textLabel.css new file mode 100644 index 000000000..23c7d98c5 --- /dev/null +++ b/frontend/app/components/ui/TextLabel/textLabel.css @@ -0,0 +1,12 @@ +.sessionLabel { + font-weight: 400; + font-size: 14px; + line-height: 17px; + & > div:last-child { + min-height: 16px; + margin-left: 4px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} diff --git a/frontend/app/components/ui/TextLink/TextLink.js b/frontend/app/components/ui/TextLink/TextLink.js new file mode 100644 index 000000000..4738e2152 --- /dev/null +++ b/frontend/app/components/ui/TextLink/TextLink.js @@ -0,0 +1,24 @@ +import React from 'react' +import cn from 'classnames' +import { Icon } from 'UI'; + +function TextLink({ + target = '_blank', + href = '', + icon = '', + label='', + className = '' +}) { + return ( + <a + target={target} + className={cn('cursor-pointer flex items-center default-hover', className)} + href={href} + > + { icon && <Icon name={icon} size="16" color="gray-medium" marginRight="5" /> } + {label} + </a> + ) +} + +export default TextLink diff --git a/frontend/app/components/ui/TextLink/index.js b/frontend/app/components/ui/TextLink/index.js new file mode 100644 index 000000000..764ac1aee --- /dev/null +++ b/frontend/app/components/ui/TextLink/index.js @@ -0,0 +1 @@ +export { default } from './TextLink'; \ No newline at end of file diff --git a/frontend/app/components/ui/TimelinePointer/TimelinePointer.js b/frontend/app/components/ui/TimelinePointer/TimelinePointer.js new file mode 100644 index 000000000..e97b3270d --- /dev/null +++ b/frontend/app/components/ui/TimelinePointer/TimelinePointer.js @@ -0,0 +1,24 @@ +import React from 'react' +import { Icon, Popup } from 'UI' +import stl from './timelinePointer.css' +import cn from 'classnames' + +function TimelinePointer({ icon, content }) { + return ( + <Popup + offset={-20} + pinned + trigger={ + <div className={cn(stl.wrapper, 'flex items-center justify-center relative')}> + <div className={stl.pin} /> + <div style={{ top: '3px' }} className={stl.icon} > + <Icon name={icon} size="18" style={{ fill: '#D3545F' }} /> + </div> + </div> + } + content={content} + /> + ) +} + +export default TimelinePointer diff --git a/frontend/app/components/ui/TimelinePointer/index.js b/frontend/app/components/ui/TimelinePointer/index.js new file mode 100644 index 000000000..e0f9399ff --- /dev/null +++ b/frontend/app/components/ui/TimelinePointer/index.js @@ -0,0 +1 @@ +export { default } from './TimelinePointer' \ No newline at end of file diff --git a/frontend/app/components/ui/TimelinePointer/timelinePointer.css b/frontend/app/components/ui/TimelinePointer/timelinePointer.css new file mode 100644 index 000000000..238d516ea --- /dev/null +++ b/frontend/app/components/ui/TimelinePointer/timelinePointer.css @@ -0,0 +1,26 @@ +.wrapper { + position: relative; + /* margin-left: 25px; */ + + &:hover .pin { + border: solid thin rgba(0,0,0,0.2); + } + + & .icon { + position: absolute; + top: 3px; + } + + & .pin { + width: 30px; + height: 30px; + border-radius: 50% 50% 50% 0; + background: #EEEEEE; + position: absolute; + box-shadow: 0 1px 0 0 rgba(0,0,0, 0.1); + transform: rotate(-45deg); + top: -5px; + border: solid thin transparent; + z-index: 0; + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/TimezoneDropdown/TimezoneDropdown.js b/frontend/app/components/ui/TimezoneDropdown/TimezoneDropdown.js new file mode 100644 index 000000000..bafebfa76 --- /dev/null +++ b/frontend/app/components/ui/TimezoneDropdown/TimezoneDropdown.js @@ -0,0 +1,35 @@ +import React from 'react' +import { Dropdown } from 'semantic-ui-react'; +import { Icon } from 'UI'; +import stl from './timezoneDropdown.css'; +import { connect } from 'react-redux'; +import { setTimezone } from 'Duck/sessions'; + +const timezoneOptions = { + 'local': new Date().toString().match(/([A-Z]+[\+-][0-9]+)/)[1], + 'UTC': 'UTC' +}; + +function TimezoneDropdown({ local, setTimezone }) { + const sortOptions = Object.entries(timezoneOptions) + .map(([ value, text ]) => ({ value, text })); + + const writeOption = (e, { name, value }) => setTimezone(value); + + return ( + <div> + <Dropdown + name="sortSessions" + className={ stl.dropdown } + options={ sortOptions } + onChange={ writeOption } + defaultValue={ local || sortOptions[ 0 ].value } + icon={ <Icon name="chevron-down" color="gray-dark" size="14" className={stl.dropdownIcon} /> } + /> + </div> + ) +} + +export default connect(state => ({ + local: state.getIn(['sessions', 'timezone']), +}), { setTimezone })(TimezoneDropdown) diff --git a/frontend/app/components/ui/TimezoneDropdown/index.js b/frontend/app/components/ui/TimezoneDropdown/index.js new file mode 100644 index 000000000..c99bfeab9 --- /dev/null +++ b/frontend/app/components/ui/TimezoneDropdown/index.js @@ -0,0 +1 @@ +export { default } from './TimezoneDropdown' \ No newline at end of file diff --git a/frontend/app/components/ui/TimezoneDropdown/timezoneDropdown.css b/frontend/app/components/ui/TimezoneDropdown/timezoneDropdown.css new file mode 100644 index 000000000..50ec0f028 --- /dev/null +++ b/frontend/app/components/ui/TimezoneDropdown/timezoneDropdown.css @@ -0,0 +1,24 @@ +.dropdown { + display: flex !important; + padding: 4px 6px; + border-radius: 3px; + color: $gray-darkest; + font-weight: 500; + &:hover { + background-color: $gray-light; + } +} + +.dropdownTrigger { + padding: 4px 8px; + border-radius: 3px; + + &:hover { + background-color: $gray-light; + } +} + +.dropdownIcon { + margin-top: 2px; + margin-left: 3px; +} \ No newline at end of file diff --git a/frontend/app/components/ui/Toggler/Toggler.js b/frontend/app/components/ui/Toggler/Toggler.js new file mode 100644 index 000000000..ef6097936 --- /dev/null +++ b/frontend/app/components/ui/Toggler/Toggler.js @@ -0,0 +1,20 @@ +import styles from './toggler.css'; + +export default ({ + onChange, + name, + className, + checked, +}) => ( + <div className={ className }> + <label className={ styles.switch }> + <input + type={ styles.checkbox } + onClick={ onChange } + name={ name } + checked={ checked } + /> + <span className={ `${ styles.slider } ${ checked ? styles.checked : '' }` } /> + </label> + </div> +); diff --git a/frontend/app/components/ui/Toggler/Toggler.stories.js b/frontend/app/components/ui/Toggler/Toggler.stories.js new file mode 100644 index 000000000..ec70f0be4 --- /dev/null +++ b/frontend/app/components/ui/Toggler/Toggler.stories.js @@ -0,0 +1,8 @@ +import { storiesOf } from '@storybook/react'; +import Toggler from '.'; + +storiesOf('Toggler', module) + .add('Pure', () => ( + <Toggler /> + )) + diff --git a/frontend/app/components/ui/Toggler/index.js b/frontend/app/components/ui/Toggler/index.js new file mode 100644 index 000000000..726b314d9 --- /dev/null +++ b/frontend/app/components/ui/Toggler/index.js @@ -0,0 +1 @@ +export { default } from './Toggler'; \ No newline at end of file diff --git a/frontend/app/components/ui/Toggler/toggler.css b/frontend/app/components/ui/Toggler/toggler.css new file mode 100644 index 000000000..171272d67 --- /dev/null +++ b/frontend/app/components/ui/Toggler/toggler.css @@ -0,0 +1,48 @@ + +.switch { + position: relative; + display: inline-block; + width: 35px; + height: 16px; +} + +.switch input { + display:none; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc !important; /* postss reset is bad */ + transition: .4s; + border-radius: 34px !important; +} + +.slider:before { + position: absolute; + content: ""; + height: 20px; + width: 20px; + left: 0; + bottom: -2px; + background-color: white; + transition: .4s; + border-radius: 50%; + border: solid 1px rgba(0, 0, 0, 0.2); +} + +.slider.checked { + background-color: $teal !important; +} + +.slider.checked:before { + border: solid 1px $teal; +} + +.slider.checked:before { + /* transform: translateX(15px); */ +} diff --git a/frontend/app/components/ui/Tooltip/Tooltip.js b/frontend/app/components/ui/Tooltip/Tooltip.js new file mode 100644 index 000000000..50e23647b --- /dev/null +++ b/frontend/app/components/ui/Tooltip/Tooltip.js @@ -0,0 +1,44 @@ +import { Popup } from 'UI'; + +export default class Tooltip extends React.PureComponent { + static defaultProps = { + timeout: 500, + } + state = { + open: false, + } + mouseOver = false + onMouseEnter = () => { + this.mouseOver = true; + setTimeout(() => { + if (this.mouseOver) this.setState({ open: true }); + }, this.props.timeout) + } + onMouseLeave = () => { + this.mouseOver = false; + this.setState({ + open: false, + }); + } + + render() { + const { trigger, tooltip } = this.props; + const { open } = this.state; + return ( + <Popup + open={ open } + content={ tooltip } + inverted + disabled={ !tooltip } + trigger={ + <span //TODO: no wrap component around + onMouseEnter={ this.onMouseEnter } + onMouseLeave={ this.onMouseLeave } + > + { trigger } + </span> + } + /> + ); + } +} \ No newline at end of file diff --git a/frontend/app/components/ui/Tooltip/index.js b/frontend/app/components/ui/Tooltip/index.js new file mode 100644 index 000000000..70239f042 --- /dev/null +++ b/frontend/app/components/ui/Tooltip/index.js @@ -0,0 +1 @@ +export { default } from './Tooltip'; \ No newline at end of file diff --git a/frontend/app/components/ui/index.js b/frontend/app/components/ui/index.js new file mode 100644 index 000000000..c64e5082d --- /dev/null +++ b/frontend/app/components/ui/index.js @@ -0,0 +1,54 @@ +export { default as Loader } from './Loader'; +export { default as Link } from './Link'; +export { default as Dropdown } from './Dropdown'; +export { default as Select } from './Select'; +export { default as Button } from './Button'; +export { default as Label } from './Label'; +export { default as Popup } from './Popup'; +export { default as Progress } from './Progress'; +export { default as SlideModal } from './SlideModal'; +export { default as NoContent } from './NoContent'; +export { default as LinkStyledInput } from './LinkStyledInput'; +export { default as IconButton } from './IconButton'; +export { default as ItemMenu } from './ItemMenu'; +export { default as InputAutocomplete } from './InputAutocomplete'; +export { default as TagBadge } from './TagBadge'; +export { default as TagList } from './TagList'; +export { default as CircularLoader } from './CircularLoader'; +export { default as TextLabel } from './TextLabel'; +export { default as CodeEditor } from './CodeEditor'; +export { default as BackLink } from './BackLink'; +export { default as PopMenu } from './PopMenu'; +export { default as Icon } from './Icon'; +export { default as OsIcon } from './Icon/Os'; +export { default as BrowserIcon } from './Icon/Browser'; +export { default as Checkbox } from './Checkbox'; +export { default as TagInput } from './TagInput'; +export { default as CloseButton } from './CloseButton'; +export { default as SegmentSelection } from './SegmentSelection'; +export { default as TextEllipsis } from './TextEllipsis'; +export { default as Tabs } from './Tabs'; +export { default as Slider } from './Slider'; +export { default as Notification } from './Notification'; +export { default as JSONTree } from './JSONTree'; +export { default as Tooltip } from './Tooltip'; +export { default as CountryFlag } from './CountryFlag'; +export { default as RandomElement } from './RandomElement'; +export { default as SavedSearchList } from './SavedSearchList'; +export { default as SplitButton } from './SplitButton'; +export { default as confirm } from './Confirmation'; +export { default as SideMenuitem } from './SideMenuitem'; +export { default as Avatar } from './Avatar'; +export { default as TimezoneDropdown } from './TimezoneDropdown'; +export { default as ErrorItem } from './ErrorItem'; +export { default as ErrorFrame } from './ErrorFrame'; +export { default as ErrorDetails } from './ErrorDetails'; +export { default as LoadMoreButton } from './LoadMoreButton'; +export { default as EscapeButton } from './EscapeButton'; +export { default as DropdownPlain } from './DropdownPlain'; +export { default as TextLink } from './TextLink'; +export { default as Information } from './Information'; +export { default as QuestionMarkHint } from './QuestionMarkHint'; +export { default as TimelinePointer } from './TimelinePointer'; + +export { Input, Modal, Form, Message, Card } from 'semantic-ui-react'; diff --git a/frontend/app/components/ui/ui.stories.js b/frontend/app/components/ui/ui.stories.js new file mode 100644 index 000000000..e8c276c27 --- /dev/null +++ b/frontend/app/components/ui/ui.stories.js @@ -0,0 +1,91 @@ +import { storiesOf } from '@storybook/react'; +import { List } from 'immutable'; +import SideMenuitem from './SideMenuitem'; +import { Avatar, ErrorItem, ErrorFrame, ErrorDetails, TimelinePointer } from 'UI'; +import Error from 'Types/session/error'; +import ErrorStackModel from 'Types/session/errorStack'; + +const errorStack = ErrorStackModel( + { + "url": "https://staging.openreplay.com/app-1cac32a.js", + "args": [], + "func": "FilterModal._this.onFilterClick", + "line": 75, + "column": 100, + "context": [ + [ 70, " });" ], + [ 71, " } else {" ], + [ 72, " props.fetchSession(props.sessionId).then(() => {" ], + [ 73, " const { session } = this.props;" ], + [ 74, " if (!session.sessionId) return; // shouldn't be. On first load component constructed twise somewhy" ], + [ 75, " initPlayer(session, props.jwt);" ], + [ 76, " });" ], + [ 77, " }" ], + [ 78, " }" ], + [ 79, "" ], + [ 80, " componentDidUpdate(prevProps) {" ] + ] + } +); + +const errors = [ + Error({ + "sessionId": 2315691667741445, + "messageId": 220546, + "timestamp": 1585335179312, + "errorId": "1_5c3b207b20a36c08c408c4990b9f5cbc", + "projectId": 1, + "source": "js_exception", + "name": "TypeError", + "message": "Cannot read property '0' of undefined", + "payload": { + "mode": "stack", + "stack": [ + { + "url": "https://staging.openreplay.com/app-1cac32a.js", + "args": [], + "func": "FilterModal._this.onFilterClick", + "line": 3233, + "column": 62, + "context": [] + }, + { + "url": "https://staging.openreplay.com/app-1cac32a.js", + "args": [], + "func": "onClick", + "line": 3342, + "column": 25, + "context": [] + }, + ] + }, + "status": "unresolved", + "parentErrorId": null + }) +] + +storiesOf('UI Components', module) + .add('SideMenuItem', () => ( + <SideMenuitem title="Menu Label" /> + )) + .add('SideMenuItem active', () => ( + <SideMenuitem title="Menu Label" active /> + )) + .add('Avatar', () => ( + <Avatar /> + )) + .add('ErrorItem', () => ( + <ErrorItem error={errors[0]} /> + )) + .add('ErrorFrame', () => ( + <ErrorFrame stack={errorStack} /> + )) + .add('ErrorDetails', () => ( + <div className="p-4 bg-white"> + <ErrorDetails error={errors[0]} /> + </div> + )) + .add('Timeline POinter', () => ( + <TimelinePointer /> + )) + diff --git a/frontend/app/constants/alertConditions.js b/frontend/app/constants/alertConditions.js new file mode 100644 index 000000000..deea60033 --- /dev/null +++ b/frontend/app/constants/alertConditions.js @@ -0,0 +1,6 @@ +export default [ + { value: '>', text: 'above' }, + { value: '>=', text: 'above or equal to' }, + { value: '<', text: 'below' }, + { value: '<=', text: 'below or equal to' }, +]; diff --git a/frontend/app/constants/alertMetrics.js b/frontend/app/constants/alertMetrics.js new file mode 100644 index 000000000..88cc99754 --- /dev/null +++ b/frontend/app/constants/alertMetrics.js @@ -0,0 +1,21 @@ +export default [ + { value: 'performance.dom_content_loaded.average', text: 'performance.dom_content_loaded.average', unit: 'ms' }, + { value: 'performance.first_meaningful_paint.average', text: 'performance.first_meaningful_paint.average', unit: 'ms' }, + { value: 'performance.page_load_time.average', text: 'performance.page_load_time.average', unit: 'ms' }, + { value: 'performance.dom_build_time.average', text: 'performance.dom_build_time.average', unit: 'ms' }, + { value: 'performance.speed_index', text: 'performance.speed_index.average', unit: 'ms' }, + { value: 'performance.page_response_time.average', text: 'performance.page_response_time.average', unit: 'ms' }, + { value: 'performance.ttfb.average', text: 'performance.ttfb.average', unit: 'ms' }, + { value: 'performance.time_to_render.average', text: 'performance.time_to_render.average', unit: 'ms' }, + { value: 'performance.image_load_time.average', text: 'performance.image_load_time.average', unit: 'ms' }, + { value: 'performance.request_load_time.average', text: 'performance.request_load_time.average', unit: 'ms' }, + { value: 'resources.load_time.average', text: 'resources.load_time.average', unit: 'ms' }, + { value: 'resources.missing.count', text: 'resources.missing.count', unit: '' }, + { value: 'errors.4xx_5xx.count', text: 'errors.4xx_5xx.count', unit: '' }, + { value: 'errors.4xx.count', text: 'errors.4xx.count', unit: '' }, + { value: 'errors.5xx.count', text: 'errors.5xx.count', unit: '' }, + { value: 'errors.javascript.impacted_sessions.count', text: 'errors.javascript.impacted_sessions.count', unit: '' }, + { value: 'performance.crashes.count', text: 'performance.crashes.count', unit: '' }, + { value: 'errors.javascript.count', text: 'errors.javascript.count', unit: '' }, + { value: 'errors.backend.count', text: 'errors.backend.count', unit: '' }, +]; diff --git a/frontend/app/constants/browserIcon.js b/frontend/app/constants/browserIcon.js new file mode 100644 index 000000000..c3a38b541 --- /dev/null +++ b/frontend/app/constants/browserIcon.js @@ -0,0 +1,30 @@ +// this can be reducer level to call it once and optimize the performance. +export default (iconName="") => { + switch (iconName.toLocaleLowerCase()) { + case 'chrome': + case 'chrome mobile': + case 'chrome mobile webview': + case 'chrome mobile ios': + case 'headlesschrome': + return 'chrome'; + case 'safari': + case 'mobile safari': + case 'mobile safari ui/wkwebview': + return 'safari'; + case 'firefox': + case 'firefox ios': + case 'firefox mobile': + return 'firefox'; + case 'opera mobile': + case 'opera': + return 'opera'; + case 'facebook': + return 'facebook'; + case 'edge': + return 'edge'; + case 'ie': + return 'ie'; + default: + return 'browser'; + } +}; diff --git a/frontend/app/constants/browsers.js b/frontend/app/constants/browsers.js new file mode 100644 index 000000000..99c8a18bb --- /dev/null +++ b/frontend/app/constants/browsers.js @@ -0,0 +1,9 @@ +export default { + chrome: 'Chrome', + firefox: 'Firefox', + electron: 'Electron', + opera: 'Opera', + edge: 'Edge', + ie: 'IE', + safari: 'Safari', +}; diff --git a/frontend/app/constants/consoleLevels.js b/frontend/app/constants/consoleLevels.js new file mode 100644 index 000000000..f449548d7 --- /dev/null +++ b/frontend/app/constants/consoleLevels.js @@ -0,0 +1,5 @@ +export default { + warning: 'Warnings', + alert: 'Alerts', + all: 'Log Entires', +}; diff --git a/frontend/app/constants/countries.js b/frontend/app/constants/countries.js new file mode 100644 index 000000000..bf3fbaea5 --- /dev/null +++ b/frontend/app/constants/countries.js @@ -0,0 +1,284 @@ +export const threeLetter = {'BD':'BGD', 'BE':'BEL', 'BF':'BFA', 'BG':'BGR', 'BA':'BIH', 'BB':'BRB', 'WF':'WLF', 'BL':'BLM', 'BM':'BMU', 'BN':'BRN', 'BO':'BOL', 'BH':'BHR', 'BI':'BDI', 'BJ':'BEN', 'BT':'BTN', 'JM':'JAM', 'BV':'BVT', 'BW':'BWA', 'WS':'WSM', 'BQ':'BES', 'BR':'BRA', 'BS':'BHS', 'JE':'JEY', 'BY':'BLR', 'BZ':'BLZ', 'RU':'RUS', 'RW':'RWA', 'RS':'SRB', 'TL':'TLS', 'RE':'REU', 'TM':'TKM', 'TJ':'TJK', 'RO':'ROU', 'TK':'TKL', 'GW':'GNB', 'GU':'GUM', 'GT':'GTM', 'GS':'SGS', 'GR':'GRC', 'GQ':'GNQ', 'GP':'GLP', 'JP':'JPN', 'GY':'GUY', 'GG':'GGY', 'GF':'GUF', 'GE':'GEO', 'GD':'GRD', 'GB':'GBR', 'GA':'GAB', 'SV':'SLV', 'GN':'GIN', 'GM':'GMB', 'GL':'GRL', 'GI':'GIB', 'GH':'GHA', 'OM':'OMN', 'TN':'TUN', 'JO':'JOR', 'HR':'HRV', 'HT':'HTI', 'HU':'HUN', 'HK':'HKG', 'HN':'HND', 'HM':'HMD', 'VE':'VEN', 'PR':'PRI', 'PS':'PSE', 'PW':'PLW', 'PT':'PRT', 'SJ':'SJM', 'PY':'PRY', 'IQ':'IRQ', 'PA':'PAN', 'PF':'PYF', 'PG':'PNG', 'PE':'PER', 'PK':'PAK', 'PH':'PHL', 'PN':'PCN', 'PL':'POL', 'PM':'SPM', 'ZM':'ZMB', 'EH':'ESH', 'EE':'EST', 'EG':'EGY', 'ZA':'ZAF', 'EC':'ECU', 'IT':'ITA', 'VN':'VNM', 'SB':'SLB', 'ET':'ETH', 'SO':'SOM', 'ZW':'ZWE', 'SA':'SAU', 'ES':'ESP', 'ER':'ERI', 'ME':'MNE', 'MD':'MDA', 'MG':'MDG', 'MF':'MAF', 'MA':'MAR', 'MC':'MCO', 'UZ':'UZB', 'MM':'MMR', 'ML':'MLI', 'MO':'MAC', 'MN':'MNG', 'MH':'MHL', 'MK':'MKD', 'MU':'MUS', 'MT':'MLT', 'MW':'MWI', 'MV':'MDV', 'MQ':'MTQ', 'MP':'MNP', 'MS':'MSR', 'OR':'SEÑMRT', 'IM':'IMN', 'UG':'UGA', 'TZ':'TZA', 'MIS':'MYS', 'MX':'MEX', 'IL':'ISR', 'FR':'FRA', 'IO':'IOT', 'SH':'SHN', 'FI':'FIN', 'FJ':'FJI', 'FK':'FLK', 'FM':'FSM', 'FO':'FRO', 'NI':'NIC', 'NL':'NLD', 'NO':'NOR', 'NA':'NAM', 'VU':'VUT', 'NC':'NCL', 'NE':'NER', 'NF':'NFK', 'NG':'NGA', 'NZ':'NZL', 'NP':'NPL', 'NR':'NRU', 'NU':'NIU', 'CK':'COK', 'XK':'XKX', 'CI':'CIV', 'CH':'CHE', 'CO':'COL', 'CN':'CHN', 'CM':'CMR', 'CL':'CHL', 'CC':'CCK', 'CA':'CAN', 'CG':'COG', 'CF':'CAF', 'CD':'COD', 'CZ':'CZE', 'CY':'CYP', 'CX':'CXR', 'CR':'CRI', 'CW':'CUW', 'CV':'CPV', 'CU':'CUB', 'SZ':'SWZ', 'SY':'SYR', 'SX':'SXM', 'KG':'KGZ', 'KE':'KEN', 'SS':'SSD', 'SR':'SUR', 'KI':'KIR', 'KH':'KHM', 'KN':'KNA', 'KM':'COM', 'ST':'STP', 'SK':'SVK', 'KR':'KOR', 'SI':'SVN', 'KP':'PRK', 'KW':'KWT', 'SN':'SEN', 'SM':'SMR', 'SL':'SLE', 'SC':'SYC', 'KZ':'KAZ', 'KY':'CYM', 'SG':'SGP', 'SE':'SWE', 'SD':'SDN', 'DO':'DOM', 'DM':'DMA', 'DJ':'DJI', 'DK':'DNK', 'VG':'VGB', 'DE':'DEU', 'YE':'YEM', 'DZ':'DZA', 'US':'USA', 'UY':'URY', 'YT':'MYT', 'UM':'UMI', 'LB':'LBN', 'LC':'LCA', 'LA':'LAO', 'TV':'TUV', 'TW':'TWN', 'TT':'TTO', 'TR':'TUR', 'LK':'LKA', 'LI':'LIE', 'LV':'LVA', 'TO':'TON', 'LT':'LTU', 'LU':'LUX', 'LR':'LBR', 'LS':'LSO', 'TH':'THA', 'TF':'ATF', 'TG':'TGO', 'TD':'TCD', 'TC':'TCA', 'LY':'LBY', 'VA':'VAT', 'VC':'VCT', 'AE':'ARE', 'AD':'AND', 'AG':'ATG', 'AF':'AFG', 'AI':'AIA', 'VI':'VIR', 'IS':'ISL', 'IR':'IRN', 'AM':'ARM', 'AL':'ALB', 'AO':'AGO', 'AQ':'ATA', 'AS':'ASM', 'AR':'ARG', 'AU':'AUS', 'AT':'AUT', 'AW':'ABW', 'IN':'IND', 'AX':'ALA', 'AZ':'AZE', 'IE':'IRL', 'ID':'IDN', 'UA':'UKR', 'QA':'QAT', 'MZ':'MOZ'} +export default { + AC: 'Ascension Island', + AD: 'Andorra', + AE: 'United Arab Emirates', + AF: 'Afghanistan', + AG: 'Antigua And Barbuda', + AI: 'Anguilla', + AL: 'Albania', + AM: 'Armenia', + AN: 'Netherlands Antilles', + AO: 'Angola', + AQ: 'Antarctica', + AR: 'Argentina', + AS: 'American Samoa', + AT: 'Austria', + AU: 'Australia', + AW: 'Aruba', + AX: 'Åland Islands', + AZ: 'Azerbaijan', + BA: 'Bosnia & Herzegovina', + BB: 'Barbados', + BD: 'Bangladesh', + BE: 'Belgium', + BF: 'Burkina Faso', + BG: 'Bulgaria', + BH: 'Bahrain', + BI: 'Burundi', + BJ: 'Benin', + BL: 'Saint Barthélemy', + BM: 'Bermuda', + BN: 'Brunei Darussalam', + BO: 'Bolivia, Plurinational State Of', + BQ: 'Bonaire, Saint Eustatius And Saba', + BR: 'Brazil', + BS: 'Bahamas', + BT: 'Bhutan', + BU: 'Burma', + BV: 'Bouvet Island', + BW: 'Botswana', + BY: 'Belarus', + BZ: 'Belize', + CA: 'Canada', + CC: 'Cocos (Keeling) Islands', + CD: 'Democratic Republic Of Congo', + CF: 'Central African Republic', + CG: 'Republic Of Congo', + CH: 'Switzerland', + CI: "Côte d'Ivoire", + CK: 'Cook Islands', + CL: 'Chile', + CM: 'Cameroon', + CN: 'China', + CO: 'Colombia', + CP: 'Clipperton Island', + CR: 'Costa Rica', + CS: 'Serbia and Montenegro', + CT: 'Canton and Enderbury Islands', + CU: 'Cuba', + CV: 'Cabo Verde', + CW: 'Curacao', + CX: 'Christmas Island', + CY: 'Cyprus', + CZ: 'Czech Republic', + DD: 'German Democratic Republic', + DE: 'Germany', + DG: 'Diego Garcia', + DJ: 'Djibouti', + DK: 'Denmark', + DM: 'Dominica', + DO: 'Dominican Republic', + DY: 'Dahomey', + DZ: 'Algeria', + EA: 'Ceuta, Mulilla', + EC: 'Ecuador', + EE: 'Estonia', + EG: 'Egypt', + EH: 'Western Sahara', + ER: 'Eritrea', + ES: 'Spain', + ET: 'Ethiopia', + FI: 'Finland', + FJ: 'Fiji', + FK: 'Falkland Islands', + FM: 'Micronesia, Federated States Of', + FO: 'Faroe Islands', + FQ: 'French Southern and Antarctic Territories', + FR: 'France', + FX: 'France, Metropolitan', + GA: 'Gabon', + GB: 'United Kingdom', + GD: 'Grenada', + GE: 'Georgia', + GF: 'French Guiana', + GG: 'Guernsey', + GH: 'Ghana', + GI: 'Gibraltar', + GL: 'Greenland', + GM: 'Gambia', + GN: 'Guinea', + GP: 'Guadeloupe', + GQ: 'Equatorial Guinea', + GR: 'Greece', + GS: 'South Georgia And The South Sandwich Islands', + GT: 'Guatemala', + GU: 'Guam', + GW: 'Guinea-bissau', + GY: 'Guyana', + HK: 'Hong Kong', + HM: 'Heard Island And McDonald Islands', + HN: 'Honduras', + HR: 'Croatia', + HT: 'Haiti', + HU: 'Hungary', + HV: 'Upper Volta', + IC: 'Canary Islands', + ID: 'Indonesia', + IE: 'Ireland', + IL: 'Israel', + IM: 'Isle Of Man', + IN: 'India', + IO: 'British Indian Ocean Territory', + IQ: 'Iraq', + IR: 'Iran, Islamic Republic Of', + IS: 'Iceland', + IT: 'Italy', + JE: 'Jersey', + JM: 'Jamaica', + JO: 'Jordan', + JP: 'Japan', + JT: 'Johnston Island', + KE: 'Kenya', + KG: 'Kyrgyzstan', + KH: 'Cambodia', + KI: 'Kiribati', + KM: 'Comoros', + KN: 'Saint Kitts And Nevis', + KP: "Korea, Democratic People's Republic Of", + KR: 'Korea, Republic Of', + KW: 'Kuwait', + KY: 'Cayman Islands', + KZ: 'Kazakhstan', + LA: "Lao People's Democratic Republic", + LB: 'Lebanon', + LC: 'Saint Lucia', + LI: 'Liechtenstein', + LK: 'Sri Lanka', + LR: 'Liberia', + LS: 'Lesotho', + LT: 'Lithuania', + LU: 'Luxembourg', + LV: 'Latvia', + LY: 'Libya', + MA: 'Morocco', + MC: 'Monaco', + MD: 'Moldova', + ME: 'Montenegro', + MF: 'Saint Martin', + MG: 'Madagascar', + MH: 'Marshall Islands', + MI: 'Midway Islands', + MK: 'Macedonia, The Former Yugoslav Republic Of', + ML: 'Mali', + MM: 'Myanmar', + MN: 'Mongolia', + MO: 'Macao', + MP: 'Northern Mariana Islands', + MQ: 'Martinique', + MR: 'Mauritania', + MS: 'Montserrat', + MT: 'Malta', + MU: 'Mauritius', + MV: 'Maldives', + MW: 'Malawi', + MX: 'Mexico', + MY: 'Malaysia', + MZ: 'Mozambique', + NA: 'Namibia', + NC: 'New Caledonia', + NE: 'Niger', + NF: 'Norfolk Island', + NG: 'Nigeria', + NH: 'New Hebrides', + NI: 'Nicaragua', + NL: 'Netherlands', + NO: 'Norway', + NP: 'Nepal', + NQ: 'Dronning Maud Land', + NR: 'Nauru', + NT: 'Neutral Zone', + NU: 'Niue', + NZ: 'New Zealand', + OM: 'Oman', + PA: 'Panama', + PC: 'Pacific Islands, Trust Territory of the', + PE: 'Peru', + PF: 'French Polynesia', + PG: 'Papua New Guinea', + PH: 'Philippines', + PK: 'Pakistan', + PL: 'Poland', + PM: 'Saint Pierre And Miquelon', + PN: 'Pitcairn', + PR: 'Puerto Rico', + PS: 'Palestinian Territory, Occupied', + PT: 'Portugal', + PU: 'U.S. Miscellaneous Pacific Islands', + PW: 'Palau', + PY: 'Paraguay', + PZ: 'Panama Canal Zone', + QA: 'Qatar', + RE: 'Reunion', + RH: 'Southern Rhodesia', + RO: 'Romania', + RS: 'Serbia', + RU: 'Russian Federation', + RW: 'Rwanda', + SA: 'Saudi Arabia', + SB: 'Solomon Islands', + SC: 'Seychelles', + SD: 'Sudan', + SE: 'Sweden', + SG: 'Singapore', + SH: 'Saint Helena, Ascension And Tristan Da Cunha', + SI: 'Slovenia', + SJ: 'Svalbard And Jan Mayen', + SK: 'Slovakia', + SL: 'Sierra Leone', + SM: 'San Marino', + SN: 'Senegal', + SO: 'Somalia', + SR: 'Suriname', + SS: 'South Sudan', + ST: 'Sao Tome and Principe', + SU: 'USSR', + SV: 'El Salvador', + SX: 'Sint Maarten', + SY: 'Syrian Arab Republic', + SZ: 'Swaziland', + TA: 'Tristan de Cunha', + TC: 'Turks And Caicos Islands', + TD: 'Chad', + TF: 'French Southern Territories', + TG: 'Togo', + TH: 'Thailand', + TJ: 'Tajikistan', + TK: 'Tokelau', + TL: 'Timor-Leste, Democratic Republic of', + TM: 'Turkmenistan', + TN: 'Tunisia', + TO: 'Tonga', + TP: 'East Timor', + TR: 'Turkey', + TT: 'Trinidad And Tobago', + TV: 'Tuvalu', + TW: 'Taiwan', + TZ: 'Tanzania, United Republic Of', + UA: 'Ukraine', + UG: 'Uganda', + UM: 'United States Minor Outlying Islands', + US: 'United States', + UY: 'Uruguay', + UZ: 'Uzbekistan', + VA: 'Vatican City State', + VC: 'Saint Vincent And The Grenadines', + VD: 'Viet-Nam, Democratic Republic of', + VE: 'Venezuela, Bolivarian Republic Of', + VG: 'Virgin Islands (British)', + VI: 'Virgin Islands (US)', + VN: 'Viet Nam', + VU: 'Vanuatu', + WF: 'Wallis And Futuna', + WK: 'Wake Island', + WS: 'Samoa', + XK: 'Kosovo', + YD: 'Yemen, Democratic', + YE: 'Yemen', + YT: 'Mayotte', + YU: 'Yugoslavia', + ZA: 'South Africa', + ZM: 'Zambia', + ZR: 'Zaire', + ZW: 'Zimbabwe', +}; diff --git a/frontend/app/constants/countryShortName.js b/frontend/app/constants/countryShortName.js new file mode 100644 index 000000000..05948ccd6 --- /dev/null +++ b/frontend/app/constants/countryShortName.js @@ -0,0 +1,96 @@ +// this can be reducer level to call it once and optimize the performance. +export default (countryName) => { + switch (countryName) { + case 'United States': + return 'USA'; + case 'United Arab Emirates': + return 'UAE'; + case 'United Kingdom': + return 'UK'; + case 'Russian Federation': + return 'RU'; + case 'Trinidad and Tobago': + return 'TTO'; + case 'Bosnia and Herzegovina': + return 'BIH'; + case 'British Indian Ocean Territory': + return 'IOT'; + case 'Brunei Darussalam': + return 'BRN'; + case 'Central African Republic': + return 'CAF'; + case 'Democratic Republic of the Congo': + case 'Republic of the Congo': + return 'Congo'; + case 'Dominican Republic': + return 'DOM'; + case 'Equatorial Guinea': + return 'GNQ'; + case 'Turks and Caicos Islands': + return 'TCA'; + case 'British Virgin Islands': + return 'VGB'; + case 'South Georgia and the South Sandwich Islands': + return 'SGS'; + case 'Saint Vincent and the Grenadines': + return 'VCT'; + case 'Papua New Guinea': + return 'PNG'; + case 'Northern Mariana Islands': + return 'NMI'; + case 'New Caledonia': + return 'NCL'; + case 'Micronesia, Federated States Of': + return 'FSM'; + case 'Moldova, Republic Of': + return 'MDA'; + case 'Macedonia, The Former Yugoslav Republic Of': + return 'Macedonia'; + case 'Lao People\'s Democratic Republic': + return 'LAO'; + case 'Korea, Republic Of': + case 'Korea, Democratic People\'s Republic Of': + return 'PRK'; + case 'Iran, Islamic Republic Of': + return 'Iran'; + case 'Heard Island and McDonald Islands': + return 'HMD'; + case 'French Southern Territories': + return 'ATF'; + case 'Falkland Islands': + return 'FLK'; + case 'Antigua and Barbuda': + return 'ATG'; + case 'American Samoa': + return 'ASM'; + case 'Brunei Darussalam': + return 'BRN'; + case 'Palestine, State Of': + return 'PSE'; + case 'Saint Kitts and Nevis': + return 'KNA'; + case 'Saint Pierre and Miquelon': + return 'SPM'; + case 'Sao Tome and Principe': + return 'STP'; + case 'Svalbard and Jan Mayen': + return 'SJM'; + case 'United Republic of Tanzania': + case 'Tanzania, United Republic Of': + return 'TZA'; + case 'United States Minor Outlying Islands': + return 'UMI'; + case 'Wallis and Futuna': + return 'WLF'; + case 'US Virgin Islands': + return 'VIR'; + case 'Venezuela, Bolivarian Republic Of': + return 'Venezuela'; + case 'Bolivia, Plurinational State Of': + return 'Bolivia'; + case 'French Polynesia': + return 'PYF'; + default: + return countryName; + } +}; diff --git a/frontend/app/constants/frameworks.js b/frontend/app/constants/frameworks.js new file mode 100644 index 000000000..047581c55 --- /dev/null +++ b/frontend/app/constants/frameworks.js @@ -0,0 +1,5 @@ +export default { + SELENIUM: 'selenium', + CYPRESS: 'cypress', + ANY: 'any', +}; diff --git a/frontend/app/constants/index.js b/frontend/app/constants/index.js new file mode 100644 index 000000000..ba6f53cf0 --- /dev/null +++ b/frontend/app/constants/index.js @@ -0,0 +1,20 @@ +export { default as browsers } from './browsers'; +export { default as browserIcon } from './browserIcon'; +export { default as countryShortName } from './countryShortName'; +export { default as os } from './os'; +export { default as countries } from './countries'; +export { default as yesOrNoOptions } from './yesOrNoOptions'; +export { default as FRAMEWORKS } from './frameworks'; +export { default as consoleLevels } from './consoleLevels'; +export { default as alertConditions } from './alertConditions'; +export { default as alertMetrics } from './alertMetrics'; +export { default as regions } from './regions'; +export { default as links } from './links'; +export { + DAYS as SCHEDULE_DAYS, + HOURS as SCHEDULE_HOURS, + CHANNEL as SCHEDULE_CHANNEL, + EMAIL as CHANNEL_EMAIL, + SLACK as CHANNEL_SLACK, + WEBHOOK as CHANNEL_WEBHOOK +} from './schedule'; diff --git a/frontend/app/constants/links.js b/frontend/app/constants/links.js new file mode 100644 index 000000000..8121bccf8 --- /dev/null +++ b/frontend/app/constants/links.js @@ -0,0 +1,4 @@ +export default { + "chrome-plugin": "https://chrome.google.com/webstore/detail/openreplay-test-recorder/pihfenmacbofppgeabciedojhjiigiml?utm_source=google", + "npm-package": "https://www.npmjs.com/package/@openreplay/openreplay-cli", +} \ No newline at end of file diff --git a/frontend/app/constants/os.js b/frontend/app/constants/os.js new file mode 100644 index 000000000..604f0b363 --- /dev/null +++ b/frontend/app/constants/os.js @@ -0,0 +1,7 @@ +export default { + windows: 'Windows', + mac_os_x: 'Mac OS X', + android: 'Android', + linux: 'Linux', + ios: 'iOS', +}; diff --git a/frontend/app/constants/regions.js b/frontend/app/constants/regions.js new file mode 100644 index 000000000..7d6813cc8 --- /dev/null +++ b/frontend/app/constants/regions.js @@ -0,0 +1,21 @@ +export default { + "europe-west1-d": "Belgium", + "us-east-1": "US East (N. Virginia)", + "us-east-2": "US East (Ohio)", + "us-west-1": "US West (N. California)", + "us-west-2": "US West (Oregon)", + "ap-east-1": "Asia Pacific (Hong Kong)", + "ap-south-1": "Asia Pacific (Mumbai)", + "ap-northeast-2": "Asia Pacific (Seoul)", + "ap-southeast-1": "Asia Pacific (Singapore)", + "ap-southeast-2": "Asia Pacific (Sydney)", + "ap-northeast-1": "Asia Pacific (Tokyo)", + "ca-central-1": "Canada (Central)", + "eu-central-1": "EU (Frankfurt)", + "eu-west-1": "EU (Ireland)", + "eu-west-2": "EU (London)", + "eu-west-3": "EU (Paris)", + "eu-north-1": "EU (Stockholm)", + "me-south-1": "Middle East (Bahrain)", + "sa-east-1": "South America (São Paulo)" +} \ No newline at end of file diff --git a/frontend/app/constants/schedule.js b/frontend/app/constants/schedule.js new file mode 100644 index 000000000..1b55b8630 --- /dev/null +++ b/frontend/app/constants/schedule.js @@ -0,0 +1,66 @@ +export const MINUTES = [ + { value: 5, text: '5 Minutes' }, + { value: 15, text: '15 Minutes' }, + { value: 30, text: '30 Minutes' }, + { value: 60, text: '60 Minutes' }, +]; + +export const HOURS = [ ...Array(24).keys() ].map(i => ({ value: i, text: `${ i > 9 ? '' : '0' }${ i }:00` })); + +export const DAYS = [ + { + value: -2, + text: 'Every', + }, + { + value: -1, + text: 'Everyday', + }, + { + value: 6, + text: 'Sunday', + }, + { + value: 0, + text: 'Monday', + }, + { + value: 1, + text: 'Tuesday', + }, + { + value: 2, + text: 'Wednesday', + }, + { + value: 3, + text: 'Thursday', + }, + { + value: 4, + text: 'Friday', + }, + { + value: 5, + text: 'Saturday', + }, +]; + +export const EMAIL = 'email'; +export const SLACK = 'slack'; +export const WEBHOOK = 'webhook'; + +export const CHANNEL = [ + { + value: EMAIL, + text: 'Email' + }, + { + value: SLACK, + text: 'Slack' + }, + { + value: WEBHOOK, + text: 'Webhook' + } +] \ No newline at end of file diff --git a/frontend/app/constants/yesOrNoOptions.js b/frontend/app/constants/yesOrNoOptions.js new file mode 100644 index 000000000..5be41ac5c --- /dev/null +++ b/frontend/app/constants/yesOrNoOptions.js @@ -0,0 +1,5 @@ +export default { + all: 'All', + yes: 'Yes', + no: 'No', +}; diff --git a/frontend/app/date.js b/frontend/app/date.js new file mode 100644 index 000000000..783da4428 --- /dev/null +++ b/frontend/app/date.js @@ -0,0 +1,113 @@ +// @flow + +import { DateTime, Duration } from 'luxon'; // TODO + +export const durationFormatted = (duration: Duration):string => { + if (duration.as('minutes') < 1) { // show in seconds + duration = duration.toFormat('s\'s\''); + } else if (duration.as('hours') < 1) { // show in minutes + duration = duration.toFormat('m\'m\'s\'s'); + } else if (duration.as('days') < 1) { // show in hours and minutes + duration = duration.toFormat('h\'h\'m\'m'); + } else if (duration.as('months') < 1) { // show in days and hours + duration = duration.toFormat('d\'d\'h\'h'); + } else { // + duration = duration.toFormat('m\'m\'s\'s\''); + } + + return duration; +}; + +export function durationFromMsFormatted(ms: number): string { + return durationFormatted(Duration.fromMillis(ms || 0)); +} + +export const durationFormattedFull = (duration: Duration): string => { + if (duration.as('minutes') < 1) { // show in seconds + let d = duration.toFormat('s'); + duration = d + (d > 1 ? ' seconds' : ' second'); + } else if (duration.as('hours') < 1) { // show in minutes + let d = duration.toFormat('m'); + duration = d + (d > 1 ? ' minutes' : ' minute'); + } else if (duration.as('days') < 1) { // show in hours and minutes + let d = duration.toFormat('h'); + duration = d + (d > 1 ? ' hours' : ' hour'); + } else if (duration.as('months') < 1) { // show in days and hours + let d = duration.toFormat('d'); + duration = d + (d > 1 ? ' days' : ' day'); + } else { + let d = Math.trunc(duration.as('months')); + duration = d + (d > 1 ? ' months' : ' month');; + } + + return duration; +}; + +export const msToMin = (ms:number): number => Math.round(ms / 60000); +export const msToSec = (ms:number): number => Math.round(ms / 1000); + +export const diffFromNowString = (ts:number): string => + durationFormattedFull(DateTime.fromMillis(Date.now()).diff(DateTime.fromMillis(ts))); + +export const diffFromNowShortString = (ts: number): string => + durationFormatted(DateTime.fromMillis(Date.now()).diff(DateTime.fromMillis(ts))); + +export const getDateFromMill = date => + (typeof date === "number" ? DateTime.fromMillis(date) : undefined); + + +/** + * Check if the given date is today. + * @param {Date} Date to be checked. + * @return {Boolean} + */ +export const isToday = (date: Date):boolean => date.hasSame(new Date(), 'day'); + + +export function formatDateTimeDefault(timestamp: number): string { + const date = DateTime.fromMillis(timestamp); + return isToday(date) ? 'Today' : date.toFormat('LLL dd, yyyy') + ', ' + date.toFormat('hh:mm a') +} + +export function formatTimeOrDate(timestamp: number, timezone: string): string { + var date = DateTime.fromMillis(timestamp) + if (timezone === 'UTC') + date = date.toUTC(); + + return isToday(date) ? date.toFormat('hh:mm a') : date.toFormat('LLL dd, yyyy, hh:mm a'); +} + +/** + * Check if the given date is today/yesterday else return in specified format. + * @param {Date} date Date to be cheked. + * @param {String} format Returning date format. + * @return {String} Formated date string. + */ +export const checkForRecent = (date: DateTime, format: string): string => { + const d = new Date(); + // Today + if (date.hasSame(d, 'day')) return 'Today'; + + // Yesterday + if (date.hasSame(d.setDate(d.getDate() - 1), 'day')) return 'Yesterday'; + + // Formatted + return date.toFormat(format); +}; +export const resentOrDate = (ts) => { + const date = DateTime.fromMillis(ts); + const d = new Date(); + // Today + if (date.hasSame(d, 'day')) return 'Today at ' + date.toFormat('hh:mm a'); + + // Yesterday + if (date.hasSame(d.setDate(d.getDate() - 1), 'day')) return 'Yesterday at ' + date.toFormat('hh:mm a'); + return date.toFormat('LLL dd, yyyy, hh:mm a'); +} + +export const checkRecentTime = (date, format) => { + return date.toRelative() +}; + +export const formatMs = (ms: number): string => ms < 1000 ? `${ Math.trunc(ms) }ms` : `${ Math.trunc(ms/100) / 10 }s`; + diff --git a/frontend/app/dateRange.js b/frontend/app/dateRange.js new file mode 100644 index 000000000..b50ec2fb9 --- /dev/null +++ b/frontend/app/dateRange.js @@ -0,0 +1,95 @@ +import origMoment from 'moment'; +import { extendMoment } from 'moment-range'; + +export const moment = extendMoment(origMoment); + +export const CUSTOM_RANGE = 'CUSTOM_RANGE'; + +const DATE_RANGE_LABELS = { + LAST_30_MINUTES: '30 Minutes', + TODAY: 'Today', + YESTERDAY: 'Yesterday', + LAST_7_DAYS: 'Past 7 Days', + LAST_30_DAYS: 'Past 30 Days', + //THIS_MONTH: 'This Month', + //LAST_MONTH: 'Previous Month', + //THIS_YEAR: 'This Year', + [ CUSTOM_RANGE ]: 'Custom Range', +}; + +const DATE_RANGE_VALUES = {}; +Object.keys(DATE_RANGE_LABELS).forEach((key) => { DATE_RANGE_VALUES[ key ] = key; }); + +export { DATE_RANGE_VALUES }; +export const dateRangeValues = Object.keys(DATE_RANGE_VALUES); + +export function getDateRangeFromTs(start, end) { + return moment.range( + moment(start), + moment(end), + ); +} + +export function getDateRangeLabel(value) { + return DATE_RANGE_LABELS[ value ]; +} + +export function getDateRangeFromValue(value) { + switch (value) { + case DATE_RANGE_VALUES.LAST_30_MINUTES: + return moment.range( + moment().startOf('hour').subtract(30, 'minutes'), + moment().startOf('hour'), + ); + case DATE_RANGE_VALUES.TODAY: + return moment.range( + moment().startOf('day'), + moment().endOf('day'), + ); + case DATE_RANGE_VALUES.YESTERDAY: + return moment.range( + moment().subtract(1, 'days').startOf('day'), + moment().subtract(1, 'days').endOf('day'), + ); + case DATE_RANGE_VALUES.LAST_7_DAYS: + return moment.range( + moment().subtract(7, 'days').startOf('day'), + moment().endOf('day'), + ); + case DATE_RANGE_VALUES.LAST_30_DAYS: + return moment.range( + moment().subtract(30, 'days').startOf('day'), + moment().endOf('day'), + ); + case DATE_RANGE_VALUES.THIS_MONTH: + return moment().range('month'); + case DATE_RANGE_VALUES.LAST_MONTH: + return moment().subtract(1, 'months').range('month'); + case DATE_RANGE_VALUES.THIS_YEAR: + return moment().range('year'); + case DATE_RANGE_VALUES.CUSTOM_RANGE: + return moment.range( + moment(), + moment(), + ); + } + return null; +} + +/** + * Check if the given date is today/yesterday else return in specified format. + * @param {Date} date Date to be cheked. + * @param {String} format Returning date format. + * @return {String} Formated date string. + */ +export const checkForRecent = (date, format) => { + const d = new Date(); + // Today + if (date.hasSame(d, 'day')) return 'Today'; + + // Yesterday + if (date.hasSame(d.setDate(d.getDate() - 1), 'day')) return 'Yesterday'; + + // Formatted + return date.toFormat(format); +}; diff --git a/frontend/app/dev/components/CrashReactAppButton.js b/frontend/app/dev/components/CrashReactAppButton.js new file mode 100644 index 000000000..3008a59bd --- /dev/null +++ b/frontend/app/dev/components/CrashReactAppButton.js @@ -0,0 +1,13 @@ +import React, { useState } from 'react'; + +export default function CrashReactAppButton() { + const [buttonText, setButtonText] = useState("Crush The App"); + return ( + <button + style={{background:'red', color: 'white',border:"1px solid teal"}} + onClick={()=>{ setButtonText(undefined)}} + > + {`${buttonText} (${buttonText.length})`} + </button> + ); +} \ No newline at end of file diff --git a/frontend/app/dev/components/EvalErrorBtn.js b/frontend/app/dev/components/EvalErrorBtn.js new file mode 100644 index 000000000..3d3564284 --- /dev/null +++ b/frontend/app/dev/components/EvalErrorBtn.js @@ -0,0 +1,16 @@ +import React from 'react'; + +function throwEvalError() { + eval('var a = [];a[100].doSomething()'); +} + +export default function EvalErrorBtn() { + return ( + <button + onClick={throwEvalError} + style={{background:'teal', color: 'white' }} + > + {"Make Eval Error"} + </button> + ); +} \ No newline at end of file diff --git a/frontend/app/dev/components/EventErrorButton.js b/frontend/app/dev/components/EventErrorButton.js new file mode 100644 index 000000000..1a9ae28d4 --- /dev/null +++ b/frontend/app/dev/components/EventErrorButton.js @@ -0,0 +1,12 @@ +import React from 'react'; + +export default function EventErrorButton() { + return ( + <button + onClick={()=>{ thingThatShouldNotBeDefined.unexistingProperty['0']() }} + style={{background:'orange', color: 'white',border:"1px solid teal"}} + > + {"Make Event Error"} + </button> + ); +} \ No newline at end of file diff --git a/frontend/app/dev/components/InternalErrorButton.js b/frontend/app/dev/components/InternalErrorButton.js new file mode 100644 index 000000000..388a79302 --- /dev/null +++ b/frontend/app/dev/components/InternalErrorButton.js @@ -0,0 +1,16 @@ + +function sendWrongEvent() { + const a = {}; + a.a = a; +} + +export default function InternalErrorButton() { + return ( + <button + onClick={sendWrongEvent} + style={{background:'maroon', color: 'white'}} + > + {"Crash OpenReplay Tracker"} + </button> + ); +} \ No newline at end of file diff --git a/frontend/app/dev/components/MemoryCrushButton.js b/frontend/app/dev/components/MemoryCrushButton.js new file mode 100644 index 000000000..04ecede4a --- /dev/null +++ b/frontend/app/dev/components/MemoryCrushButton.js @@ -0,0 +1,20 @@ +import React from 'react'; +import appStore from 'App/store'; + +function doHeavyStuffAAAA() { + let superHeavyString = ""; + for (var i = 0; i < 100000; i++) { + superHeavyString += JSON.stringify(appStore.getState()) + } +} + +export default function MemoryCrushButton() { + return ( + <button + style={{background:'darkgreen', color: 'purple'}} + onClick={doHeavyStuffAAAA} + > + {"Eat Memory" } + </button> + ); +} \ No newline at end of file diff --git a/frontend/app/dev/components/PromiseErrorButton.js b/frontend/app/dev/components/PromiseErrorButton.js new file mode 100644 index 000000000..1a3040ec6 --- /dev/null +++ b/frontend/app/dev/components/PromiseErrorButton.js @@ -0,0 +1,16 @@ +import React from 'react'; + +function fetchWrong() { + return fetch('/lalka_sasai').then(resp => resp.json()); +} + +export default function PromiseErrorButton() { + return ( + <button + onClick={fetchWrong} + style={{background:'purple', color: 'white'}} + > + {"Zatrollit' lalku"} + </button> + ); +} \ No newline at end of file diff --git a/frontend/app/dev/components/index.js b/frontend/app/dev/components/index.js new file mode 100644 index 000000000..c2ca6df42 --- /dev/null +++ b/frontend/app/dev/components/index.js @@ -0,0 +1,28 @@ +import React, { useState } from 'react'; +import CrashReactAppButton from './CrashReactAppButton'; +import EventErrorButton from './EventErrorButton'; +import MemoryCrushButton from './MemoryCrushButton'; +import PromiseErrorButton from './PromiseErrorButton'; +import EvalErrorBtn from './EvalErrorBtn'; +import InternalErrorButton from './InternalErrorButton'; +import { options } from "../console"; + +export default function ErrorGenPanel() { + const [show, setShow] = useState(false); + if (window.ENV.PRODUCTION && !options.enableCrash) return null; + return ( + <div style={{ position: 'relative' }}> + <button style={{ background: 'coral', height: '100%' }} onClick={() => setShow(!show)}>Show buttons</button> + { show && + <div style={{ position: 'absolute', display:'flex', flexDirection: 'column' }}> + <CrashReactAppButton/> + <EventErrorButton/> + <MemoryCrushButton/> + <PromiseErrorButton/> + <EvalErrorBtn/> + <InternalErrorButton/> + </div> + } + </div> + ); +} \ No newline at end of file diff --git a/frontend/app/dev/console.js b/frontend/app/dev/console.js new file mode 100644 index 000000000..e3a4da618 --- /dev/null +++ b/frontend/app/dev/console.js @@ -0,0 +1,6 @@ +export const options = { + enableCrash: false, + logStuff: false, +} + +window.__OPENREPLAY_DEV_TOOLS = options; \ No newline at end of file diff --git a/frontend/app/duck/.eslintrc b/frontend/app/duck/.eslintrc new file mode 100644 index 000000000..271db542f --- /dev/null +++ b/frontend/app/duck/.eslintrc @@ -0,0 +1,5 @@ +{ + "rules": { + "complexity": 0 + } +} diff --git a/frontend/app/duck/ReducerModule.ts b/frontend/app/duck/ReducerModule.ts new file mode 100644 index 000000000..c80c65a37 --- /dev/null +++ b/frontend/app/duck/ReducerModule.ts @@ -0,0 +1,55 @@ + +redux -> other storage ::<< Entities + Lists + relations <|> methods:: crud. request declaration -> request realisation with middleware -< (uses) MODEL + + + +!request declaration + + + +action/request formatter => ReducerModule Fabrique => + + +class ReducerModule { + _ns = "common" + _switch = {} + _n = 0 + + constructor(namespace) { + this._ns = namespace + } + + /** + Action: state => newState | { reduce: state, action => newState, creator: () => {objects to action} } + */ + actions(actns): this { + Object.keys(actns).map(key => { + const type = `${this._namespace}/${key.toUpperCase()}`; + this._switch[ type ] = actns[ key ]; + }); + return this; + } + + requests(reqsts): this { + Object.keys(reqsts).map(key => { + const type = `${this._namespace}/${key.toUpperCase()}`; + this._switch[ type ] = actns[ key ]; + }); + return this; + } + + get actionTypes() { + + } + + get actionCreators() { + + } + + get reducer() { + return (state, action = {}) => { + const reduce = this._switch[ action.type ]; + return reduce ? reduce(state, action) : state; + } + } +} \ No newline at end of file diff --git a/frontend/app/duck/alerts.js b/frontend/app/duck/alerts.js new file mode 100644 index 000000000..b93ff5878 --- /dev/null +++ b/frontend/app/duck/alerts.js @@ -0,0 +1,15 @@ +import Alert from 'Types/alert'; +import crudDuckGenerator from './tools/crudDuck'; + +const idKey = 'alertId'; +const crudDuck = crudDuckGenerator('alert', Alert, { idKey: idKey }); +export const { fetchList, init, edit, remove } = crudDuck.actions; + +export function save(instance) { + return { + types: crudDuck.actionTypes.SAVE.toArray(), + call: client => client.put( instance[idKey] ? `/alerts/${ instance[idKey] }` : '/alerts', instance.toData()), + }; +} + +export default crudDuck.reducer; diff --git a/frontend/app/duck/announcements.js b/frontend/app/duck/announcements.js new file mode 100644 index 000000000..3a7612ee7 --- /dev/null +++ b/frontend/app/duck/announcements.js @@ -0,0 +1,45 @@ +import { List, Map } from 'immutable'; +import Announcement from 'Types/announcement'; +import { RequestTypes } from './requestStateCreator'; + +import { mergeReducers } from './funcTools/tools'; +import { createRequestReducer } from './funcTools/request'; +import { + createCRUDReducer, + getCRUDRequestTypes, + createFetchList +} from './funcTools/crud'; + +const name = 'announcement'; +const idKey = 'id'; + +const SET_LAST_READ = new RequestTypes('announcement/SET_LAST_READ'); + +const initialState = Map({ + list: List() +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case SET_LAST_READ.SUCCESS: + return state.update('list', (list) => list.map(i => ({...i.toJS(), viewed: true }))); + } + return state; +}; + +export function setLastRead() { + return { + types: SET_LAST_READ.toArray(), + call: client => client.get(`/announcements/view`), + }; +} + +export const fetchList = createFetchList(name); + +export default mergeReducers( + reducer, + createCRUDReducer(name, Announcement, idKey), + createRequestReducer({ + ...getCRUDRequestTypes(name), + }), +); \ No newline at end of file diff --git a/frontend/app/duck/assignments.js b/frontend/app/duck/assignments.js new file mode 100644 index 000000000..c6c7d3cda --- /dev/null +++ b/frontend/app/duck/assignments.js @@ -0,0 +1,121 @@ +import { List, Map, Set } from 'immutable'; +import Assignment from 'Types/session/assignment'; +import Activity from 'Types/session/activity'; +import withRequestState, { RequestTypes } from './requestStateCreator'; +import { createListUpdater, createItemInListUpdater } from './funcTools/tools'; +import { editType, initType } from './funcTools/crud/types'; +import { createInit, createEdit } from './funcTools/crud'; + +const idKey = 'id'; +const name = 'assignment'; +const listUpdater = createListUpdater(idKey); + +const FETCH_PROJECTS = new RequestTypes('asignment/FETCH_PROJECTS'); +const FETCH_META = new RequestTypes('asignment/FETCH_META'); +const FETCH_ASSIGNMENTS = new RequestTypes('asignment/FETCH_ASSIGNMENTS'); +const FETCH_ASSIGNMENT = new RequestTypes('asignment/FETCH_ASSIGNMENT'); +const ADD_ACTIVITY = new RequestTypes('asignment/ADD_ACTIVITY'); +const ADD_MESSAGE = new RequestTypes('asignment/ADD_MESSAGE'); +const EDIT = editType(name); +const INIT = initType(name); + +const initialState = Map({ + list: List(), + instance: Assignment(), + activeIssue: Assignment(), + issueTypes: List(), + issueTypeIcons: Set(), + users: List(), + projects: List(), + projectsFetched: false +}); + +const reducer = (state = initialState, action = {}) => { + const users = state.get('users'); + var issueTypes = [] + switch (action.type) { + case INIT: + action.instance.issueType = issueTypes.length > 0 ? issueTypes[0].id : ''; + return state.set('instance', Assignment(action.instance)); + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + case FETCH_PROJECTS.SUCCESS: + return state.set('projects', List(action.data)).set('projectsFetched', true); + case FETCH_ASSIGNMENTS.SUCCESS: + return state.set('list', List(action.data).map(Assignment)); + case FETCH_ASSIGNMENT.SUCCESS: + return state.set('activeIssue', Assignment({ ...action.data, users})); + case FETCH_META.SUCCESS: + issueTypes = action.data.issueTypes; + var issueTypeIcons = {} + for (var i =0; i < issueTypes.length; i++) { + issueTypeIcons[issueTypes[i].id] = issueTypes[i].iconUrl + } + return state.set('issueTypes', List(issueTypes)) + .set('users', List(action.data.users)) + .set('issueTypeIcons', issueTypeIcons) + case ADD_ACTIVITY.SUCCESS: + const instance = Assignment(action.data); + return listUpdater(state, instance); + case ADD_MESSAGE.SUCCESS: + const user = users.filter(user => user.id === action.data.author).first(); + const activity = Activity({ type: 'message', user, ...action.data,}); + return state.updateIn([ 'activeIssue', 'activities' ], list => list.push(activity)); + default: + return state; + } +}; + +export default withRequestState({ + fetchProjects: FETCH_PROJECTS, + fetchMeta: FETCH_META, + fetchAssignments: FETCH_ASSIGNMENTS, + addActivity: ADD_ACTIVITY, + fetchAssignment: FETCH_ASSIGNMENT, + addMessage: ADD_MESSAGE +}, reducer); + +export const init = createInit(name); +export const edit = createEdit(name); + +export function fetchProjects(sessionId) { + return { + types: FETCH_PROJECTS.toArray(), + call: client => client.get(`/integrations/issues/list_projects`) + }; +} + +export function fetchMeta(projectId) { + return { + types: FETCH_META.toArray(), + call: client => client.get(`/integrations/issues/${projectId}`) + } +} + +export function fetchAssignments(sessionId) { + return { + types: FETCH_ASSIGNMENTS.toArray(), + call: client => client.get(`/sessions2/${ sessionId }/assign`) + } +} + +export function fetchAssigment(sessionId, id) { + return { + types: FETCH_ASSIGNMENT.toArray(), + call: client => client.get(`/sessions2/${ sessionId }/assign/${ id }`) + } +} + +export function addActivity(sessionId, params) { + return { + types: ADD_ACTIVITY.toArray(), + call: client => client.post(`/sessions2/${ sessionId }/assign/projects/${params.projectId}`, params.toCreate()), + } +} + +export function addMessage(sessionId, assignmentId, params) { + return { + types: ADD_MESSAGE.toArray(), + call: client => client.post(`/sessions2/${ sessionId }/assign/${ assignmentId }/comment`, params), + } +} \ No newline at end of file diff --git a/frontend/app/duck/components/index.js b/frontend/app/duck/components/index.js new file mode 100644 index 000000000..5c45d0c43 --- /dev/null +++ b/frontend/app/duck/components/index.js @@ -0,0 +1,11 @@ +import { combineReducers } from 'redux-immutable'; + +import targetDefiner from './targetDefiner'; +import resultsModal from './resultsModal'; +import player from './player'; + +export default combineReducers({ + targetDefiner, + resultsModal, + player, +}); diff --git a/frontend/app/duck/components/player.js b/frontend/app/duck/components/player.js new file mode 100644 index 000000000..4a7f7c42e --- /dev/null +++ b/frontend/app/duck/components/player.js @@ -0,0 +1,81 @@ +import { Map } from 'immutable'; + +export const NONE = 0; +export const CONSOLE = 1; +export const NETWORK = 2; +export const STACKEVENTS = 3; +export const STORAGE = 4; +export const PROFILER = 5; +export const PERFORMANCE = 6; +export const GRAPHQL = 7; +export const FETCH = 8; +export const EXCEPTIONS = 9; +export const LONGTASKS = 10; + +const TOGGLE_FULLSCREEN = 'player/TOGGLE_FS'; +const TOGGLE_BOTTOM_BLOCK = 'player/SET_BOTTOM_BLOCK'; +const HIDE_HINT = 'player/HIDE_HINT'; + +const initialState = Map({ + fullscreen: false, + bottomBlock: NONE, + hiddenHints: Map({ + storage: localStorage.getItem('storageHideHint'), + stack: localStorage.getItem('stackHideHint') + }), +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case TOGGLE_FULLSCREEN: + const { flag } = action + return state.update('fullscreen', fs => typeof flag === 'boolean' ? flag : !fs); + case TOGGLE_BOTTOM_BLOCK: + const { bottomBlock } = action; + if (state.get('bottomBlock') !== bottomBlock && bottomBlock !== NONE) { + } + return state.update('bottomBlock', bb => bb === bottomBlock ? NONE : bottomBlock); + case HIDE_HINT: + const { name } = action; + localStorage.setItem(`${name}HideHint`, true); + return state + .setIn([ "hiddenHints", name ], true) + .set('bottomBlock', NONE); + + } + return state; +}; + +export default reducer; + +export function toggleFullscreen(flag) { + console.log("a",flag) + return { + type: TOGGLE_FULLSCREEN, + flag, + }; +} +export function fullscreenOff() { + return toggleFullscreen(false); +} +export function fullscreenOn() { + return toggleFullscreen(true); +} + +export function toggleBottomBlock(bottomBlock = NONE) { + return { + bottomBlock, + type: TOGGLE_BOTTOM_BLOCK, + }; +} + +export function closeBottomBlock() { + return toggleBottomBlock(); +} + +export function hideHint(name) { + return { + name, + type: HIDE_HINT, + } +} \ No newline at end of file diff --git a/frontend/app/duck/components/resultsModal.js b/frontend/app/duck/components/resultsModal.js new file mode 100644 index 000000000..28b4abe72 --- /dev/null +++ b/frontend/app/duck/components/resultsModal.js @@ -0,0 +1,54 @@ +import { List, Map } from 'immutable'; +import Run from 'Types/run'; +import withRequestState, { RequestTypes } from 'Duck/requestStateCreator'; + +const OPEN = 'resultsModal/OPEN'; +const CLOSE = 'resultsModal/CLOSE'; +const FETCH = new RequestTypes('resultsModal/FETCH'); + +const initialState = Map({ + results: Run(), + open: false, +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case OPEN: + return state.set('open', true).set('results', action.results); + case CLOSE: + return state.set('open', false); + case FETCH.REQUEST: + return state.set( + 'results', + Run(), + ).set('open', true); + case FETCH.SUCCESS: + return state.set( + 'results', + Run(action.data), + ).set('open', true); + } + return state; +}; + +export default withRequestState(FETCH, reducer); + +export function open(results) { + return { + type: OPEN, + results, + }; +} + +export function close() { + return { + type: CLOSE, + }; +} + +export function fetchResults(runId) { + return { + types: FETCH.toArray(), + call: client => client.get(`/runs/${ runId }`), + }; +} diff --git a/frontend/app/duck/components/targetDefiner.js b/frontend/app/duck/components/targetDefiner.js new file mode 100644 index 000000000..9f28e8c5c --- /dev/null +++ b/frontend/app/duck/components/targetDefiner.js @@ -0,0 +1,73 @@ +import { Map } from 'immutable'; +import Target from 'Types/target'; +import TargetCustom from 'Types/targetCustom'; +import withRequestState, { RequestTypes } from 'Duck/requestStateCreator'; + +const EDIT = 'targetDefiner/EDIT'; +const SHOW = 'targetDefiner/SHOW'; +const HIDE = 'targetDefiner/HIDE'; +const TOGGLE_INSPECTOR_MODE = 'targetDefiner/TOGGLE_INSPECTOR_MODE'; + +const initialState = Map({ + isDisplayed: false, + target: Target(), + inspectorMode: false, +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case EDIT: + return state.setIn([ 'target', 'label' ], action.label); + case SHOW: + const target = action.target && !action.target.isCustom + ? Target(action.target) + : TargetCustom(action.target); + return state + .set('isDisplayed', true) + .set('target', target) + .set('inspectorMode', false); + case HIDE: + return state + .set('isDisplayed', false) + .set('target', Target()) + case TOGGLE_INSPECTOR_MODE: + const inspectorMode = action.flag !== undefined + ? action.flag + : !state.get('inspectorMode'); + let returnState = state.set('inspectorMode', inspectorMode); + if (inspectorMode) { + returnState = returnState.set('isDisplayed', false).set('target', Target()); + } + return returnState; + } + return state; +}; + +export default reducer; + +export function show(target) { + return { + type: SHOW, + target, + }; +} + +export function hide() { + return { + type: HIDE, + }; +} + +export function edit(label) { + return { + type: EDIT, + label, + }; +} + +export function toggleInspectorMode(flag) { + return { + type: TOGGLE_INSPECTOR_MODE, + flag, + }; +} diff --git a/frontend/app/duck/config.js b/frontend/app/duck/config.js new file mode 100644 index 000000000..a445e3f50 --- /dev/null +++ b/frontend/app/duck/config.js @@ -0,0 +1,61 @@ +import { Map } from 'immutable'; +import { saveType, fetchType, editType } from './funcTools/crud/types'; +import { mergeReducers, success, array } from './funcTools/tools'; +import { createRequestReducer } from './funcTools/request'; + +const name = 'config' + +const FETCH = fetchType(name); +const SAVE = saveType(name); +const EDIT = editType(name); + +const FETCH_SUCCESS = success(FETCH); +const SAVE_SUCCESS = success(SAVE); + +const initialState = Map({ + options: { + weeklyReport: false + }, +}); + +const reducer = (state = initialState, action = {}) => { + switch(action.type) { + case FETCH_SUCCESS: + return state.set('options', action.data) + case SAVE_SUCCESS: + return state + case EDIT: + return state.set('options', action.config) + default: + return state; + } +} + +export const fetch = () => { + return { + types: array(FETCH), + call: client => client.get(`/config/weekly_report`), + } +} + +export const save = (config) => { + return { + types: array(SAVE), + call: client => client.post(`/config/weekly_report`, config), + } +} + +export const edit = (config) => { + return { + type: EDIT, + config + } +} + +export default mergeReducers( + reducer, + createRequestReducer({ + fetchRequest: FETCH, + saveRequest: SAVE, + }), +) \ No newline at end of file diff --git a/frontend/app/duck/customField.js b/frontend/app/duck/customField.js new file mode 100644 index 000000000..c9b9607da --- /dev/null +++ b/frontend/app/duck/customField.js @@ -0,0 +1,94 @@ +import { List, Map } from 'immutable'; +import CustomField from 'Types/customField'; +import { fetchListType, saveType, editType, initType, removeType } from './funcTools/crud/types'; +import { createItemInListUpdater, mergeReducers, success, array } from './funcTools/tools'; +import { createEdit, createInit } from './funcTools/crud'; +import { createRequestReducer } from './funcTools/request'; + +const name = "integration/variable"; +const idKey = 'index'; +const itemInListUpdater = createItemInListUpdater(idKey); + +const FETCH_LIST = fetchListType(name); +const SAVE = saveType(name); +const UPDATE = saveType(name); +const EDIT = editType(name); +const REMOVE = removeType(name); +const INIT = initType(name); +const FETCH_SOURCES = fetchListType('integration/sources'); + +const FETCH_SUCCESS = success(FETCH_LIST); +const SAVE_SUCCESS = success(SAVE); +const UPDATE_SUCCESS = success(UPDATE); +const REMOVE_SUCCESS = success(REMOVE); +const FETCH_SOURCES_SUCCESS = success(FETCH_SOURCES); + +// const defaultMeta = [{key: 'user_id', index: 0}, {key: 'user_anonymous_id', index: 0}]; +const initialState = Map({ + list: List([{key: 'user_id'}, {key: 'user_anonymous_id'}]), + instance: CustomField(), + sources: List(), +}); + +const reducer = (state = initialState, action = {}) => { + switch(action.type) { + case FETCH_SUCCESS: + return state.set('list', List(action.data).map(CustomField)) //.concat(defaultMeta)) + case FETCH_SOURCES_SUCCESS: + return state.set('sources', List(action.data.map(({ value, ...item}) => ({label: value, key: value, ...item}))).map(CustomField)) + case SAVE_SUCCESS: + case UPDATE_SUCCESS: + return state.update('list', itemInListUpdater(CustomField(action.data))) + case REMOVE_SUCCESS: + return state.update('list', list => list.filter(item => item.index !== action.index)); + case INIT: + return state.set('instance', CustomField(action.instance)); + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + default: + return state; + } +} + +export const edit = createEdit(name); +export const init = createInit(name); + +export const fetchList = (siteId) => { + return { + types: array(FETCH_LIST), + call: client => client.get(siteId ? `/${siteId}/metadata` : '/metadata'), + } +} + +export const fetchSources = () => { + return { + types: array(FETCH_SOURCES), + call: client => client.get('/integration/sources'), + } +} + +export const save = (siteId, instance) => { + const url = instance.exists() + ? `/${siteId}/metadata/${instance.index}` + : `/${siteId}/metadata`; + return { + types: array(instance.exists() ? SAVE : UPDATE), + call: client => client.post(url, instance.toData()), + } +} + +export const remove = (siteId, index) => { + return { + types: array(REMOVE), + call: client => client.delete(`/${siteId}/metadata/${index}`), + index, + } +} + +export default mergeReducers( + reducer, + createRequestReducer({ + fetchRequest: FETCH_LIST, + saveRequest: SAVE, + }), +) \ No newline at end of file diff --git a/frontend/app/duck/dashboard.js b/frontend/app/duck/dashboard.js new file mode 100644 index 000000000..a99f985e3 --- /dev/null +++ b/frontend/app/duck/dashboard.js @@ -0,0 +1,228 @@ +import { List, Map, getIn } from 'immutable'; +import { + WIDGET_LIST, + WIDGET_MAP, + WIDGET_KEYS, +} from 'Types/dashboard'; +import Period, { LAST_24_HOURS, LAST_7_DAYS } from 'Types/app/period'; +import { ALL } from 'Types/app/platform'; +import { createRequestReducer } from './funcTools/request'; +import { mergeReducers, success, array } from './funcTools/tools'; +import { RequestTypes } from 'Duck/requestStateCreator'; + +const SET_PERIOD = 'dashboard/SET_PERIOD'; +const SET_PLATFORM = 'dashboard/SET_PLATFORM'; +const SET_SHOW_ALERTS = 'dashboard/SET_SHOW_ALERTS'; +const SET_COMPARING = 'dashboard/SET_COMPARING'; +const SET_FILTERS = 'dashboard/SET_FILTERS'; +const REMOVE_FILTER = 'dashboard/REMOVE_FILTER'; +const CLEAR_FILTERS = 'dashboard/CLEAR_FILTERS'; +const FETCH_PERFORMANCE_SEARCH = 'dashboard/FETCH_PERFORMANCE_SEARCH'; +const FETCH_PERFORMANCE_SEARCH_SUCCESS = success(FETCH_PERFORMANCE_SEARCH); +const ON_BOARD = new RequestTypes('plan/ON_BOARD'); + +const FETCH_META_OPTIONS = 'dashboard/FETCH_META_OPTIONS'; +const FETCH_META_OPTIONS_SUCCESS = success(FETCH_META_OPTIONS); + +export const FETCH_WIDGET_TYPES = {}; +WIDGET_KEYS.forEach(key => { + FETCH_WIDGET_TYPES[ key ] = `dashboard/FETCH_WIDGET-${ key }-`; //workaround TODO + FETCH_WIDGET_TYPES[ '_' + key ] = `dashboard/FETCH_WIDGET-${ '_' + key }-`; //workaround TODO +}); +const FETCH_WIDGET_SUCCESS_LIST = WIDGET_KEYS.map(key => success(FETCH_WIDGET_TYPES[ key ])).concat(WIDGET_KEYS.map(key => success(FETCH_WIDGET_TYPES[ '_' + key ]))); + +const widgetInitialStates = {}; +WIDGET_LIST.forEach(({ key, dataWrapper }) => { + widgetInitialStates[ key ] = dataWrapper(); + widgetInitialStates[ '_' + key ] = dataWrapper(); +}); + +const initialState = Map({ + ...widgetInitialStates, + period: Period({ rangeName: LAST_7_DAYS }), + periodCompare: Period({ rangeName: LAST_7_DAYS }), + filters: List(), + filtersCompare: List(), + platform: ALL, + performanceChart: [], + showAlerts: false, + comparing: false, + metaOptions: [], + boarding: List(), + boardingCompletion: 0, +}); + +const getValue = ({ avgPageLoadTime, avgRequestLoadTime, avgImageLoadTime }) => avgPageLoadTime || avgRequestLoadTime || avgImageLoadTime; + +const getCountry = item => { + switch(item.location) { + case 'us-east-2': + case 'us-east-1': + return { + userCountry: 'US', + avg: Math.round(item.avg) + }; + case 'europe-west1-d': + return { + userCountry: 'EU', + avg: Math.round(item.avg) + }; + default: + return ''; + } +} + +const reducer = (state = initialState, action = {}) => { + let isCompare; + if (FETCH_WIDGET_SUCCESS_LIST.includes(action.type)) { + const key = action.type.split('-')[ 1 ]; + const _key = key.startsWith('_') ? key.replace('_', '') : key; + const dataWrapper = WIDGET_LIST.find(w => w.key === _key).dataWrapper; + return state.set(action.compare ? key : key, dataWrapper(action.data, action.period)); + } + switch (action.type) { + case SET_PERIOD: + return state.set(action.compare ? 'periodCompare' : 'period', Period(action.period)); + case SET_PLATFORM: + return state.set("platform", action.platform); + case FETCH_PERFORMANCE_SEARCH_SUCCESS: + const timestamps = List(getIn(action.data, [ 0, "chart" ])).map(({ timestamp }) => ({ timestamp })); + const chart = List(action.data) + .reduce((zippedChartData, resource, index) => zippedChartData + .zipWith((chartPoint, resourcePoint) => ({ + ...chartPoint, + [ `resource${ index }` ]: getValue(resourcePoint), + }), List(resource.chart)), + timestamps + ) + .toJS(); + return state.set('performanceChart', formatChartTime(chart, state.get("period"))); + case SET_SHOW_ALERTS: + return state.set('showAlerts', action.state); + case SET_COMPARING: + return state.set('comparing', action.status) + .set('filtersCompare', List()).set('periodCompare', state.get("period")); + case SET_FILTERS: + isCompare = action.key === 'compare'; + return state.update(isCompare ? 'filtersCompare' : 'filters', list => list.push(action.filter)) + case REMOVE_FILTER: + isCompare = action.key === 'compare'; + return state.update( + isCompare ? 'filtersCompare' : 'filters', + list => list.filter(filter => filter.key !== action.filterKey) + ); + case CLEAR_FILTERS: + isCompare = action.key === 'compare'; + return state.set(isCompare ? 'filtersCompare' : 'filters', List()); + + case FETCH_META_OPTIONS_SUCCESS: + return state.set('metaOptions', action.data.map(i => ({ ...i, icon: 'id-card', placeholder: 'Search for ' + i.name}))); + + case ON_BOARD.SUCCESS: + const tasks = List(action.data); + const completion = tasks.filter(task => task.done).size * 100 / tasks.size; + return state.set('boarding', tasks).set('boardingCompletion', Math.trunc(completion)); + } + return state; +}; + +export default mergeReducers( + reducer, + createRequestReducer({ + fetchWidget: FETCH_WIDGET_TYPES, + performanceSearchRequest: FETCH_PERFORMANCE_SEARCH, + }), +); + +export function setPeriod(compare, period) { + return { + type: SET_PERIOD, + compare, + period, + } +} + +export function setPlatform(platform) { + return { + type: SET_PLATFORM, + platform, + }; +} + +export function setComparing(status) { + return { + type: SET_COMPARING, + status, + }; +} + +export function setFilters(key, filter) { + return { + type: SET_FILTERS, + key, + filter + }; +} + +export function removeFilter(key, filterKey) { + return { + type: REMOVE_FILTER, + key, + filterKey + }; +} + +export function clearFilters(key) { + return { + type: CLEAR_FILTERS, + key + }; +} + + +const toUnderscore = s => s.split(/(?=[A-Z])/).join('_').toLowerCase(); +export function fetchWidget(widgetKey, period, platform, _params, filters) { + let path = `/dashboard/${ toUnderscore(widgetKey) }`; + const widget = WIDGET_MAP[widgetKey]; + const params = period.toTimestamps(); + params.filters = filters ? + filters.map(f => ({key: f.key, value: f.value ? f.value : f.text})).toJS() : []; + // if (platform !== ALL) { + // params.platform = platform; + // } + + return { + types: array(FETCH_WIDGET_TYPES[ _params.compare ? '_' + widgetKey : widgetKey ]), + call: client => client.post(path, {...params, ..._params}), + period, + compare: _params && _params.compare + }; +} + +export function fetchPerformanseSearch(params) { + return { + types: array(FETCH_PERFORMANCE_SEARCH), + call: client => client.post('/dashboard/performance/search', params), + }; +} + +export function setShowAlerts(state) { + return { + type: SET_SHOW_ALERTS, + state, + } +} + +export function fetchMetadataOptions() { + return { + types: array(FETCH_META_OPTIONS), + call: client => client.get('/dashboard/metadata'), + }; +} + +export function getOnboard() { + return { + types: ON_BOARD.toArray(), + call: client => client.get('/boarding'), + } +} diff --git a/frontend/app/duck/environments.js b/frontend/app/duck/environments.js new file mode 100644 index 000000000..8356c4281 --- /dev/null +++ b/frontend/app/duck/environments.js @@ -0,0 +1,7 @@ +import Environment from 'Types/environment'; +import crudDuckGenerator from './tools/crudDuck'; + +const crudDuck = crudDuckGenerator('environment', Environment); +export const { fetchList, fetch, init, edit, save, remove } = crudDuck.actions; + +export default crudDuck.reducer; diff --git a/frontend/app/duck/errors.js b/frontend/app/duck/errors.js new file mode 100644 index 000000000..3f0793103 --- /dev/null +++ b/frontend/app/duck/errors.js @@ -0,0 +1,168 @@ +import { List, Map } from 'immutable'; +import { clean as cleanParams } from 'App/api_client'; +import ErrorInfo, { RESOLVED, UNRESOLVED, IGNORED } from 'Types/errorInfo'; +import { createFetch, fetchListType, fetchType } from './funcTools/crud'; +import { createRequestReducer, ROOT_KEY } from './funcTools/request'; +import { array, request, success, failure, createListUpdater, mergeReducers } from './funcTools/tools'; + +const name = "error"; +const idKey = "errorId"; + +const FETCH_LIST = fetchListType(name); +const FETCH = fetchType(name); +const FETCH_NEW_ERRORS_COUNT = fetchType('errors/FETCH_NEW_ERRORS_COUNT'); +const RESOLVE = "errors/RESOLVE"; +const UNRESOLVE = "errors/UNRESOLVE"; +const IGNORE = "errors/IGNORE"; +const MERGE = "errors/MERGE"; +const TOGGLE_FAVORITE = "errors/TOGGLE_FAVORITE"; +const FETCH_TRACE = "errors/FETCH_TRACE"; + +function chartWrapper(chart = []) { + return chart.map(point => ({ ...point, count: Math.max(point.count, 0) })); +} + +const updateItemInList = createListUpdater(idKey); +const updateInstance = (state, instance) => state.getIn([ "instance", idKey ]) === instance[ idKey ] + ? state.mergeIn([ "instance" ], instance) + : state; + +const initialState = Map({ + totalCount: 0, + list: List(), + instance: ErrorInfo(), + instanceTrace: List(), + stats: Map(), + sourcemapUploaded: true +}); + + +function reducer(state = initialState, action = {}) { + let updError; + switch (action.type) { + case success(FETCH): + return state.set("instance", ErrorInfo(action.data)); + case success(FETCH_TRACE): + return state.set("instanceTrace", List(action.data.trace)).set('sourcemapUploaded', action.data.sourcemapUploaded); + case success(FETCH_LIST): + const { data } = action; + return state + .set("totalCount", data ? data.total : 0) + .set("list", List(data && data.errors).map(ErrorInfo) + .filter(e => e.parentErrorId == null) + .map(e => e.update("chart", chartWrapper))); + case success(RESOLVE): + updError = { errorId: action.id, status: RESOLVED }; + return updateItemInList(updateInstance(state, updError), updError); + case success(UNRESOLVE): + updError = { errorId: action.id, status: UNRESOLVED }; + return updateItemInList(updateInstance(state, updError), updError); + case success(IGNORE): + updError = { errorId: action.id, status: IGNORED }; + return updateItemInList(updateInstance(state, updError), updError); + case success(TOGGLE_FAVORITE): + return state.mergeIn([ "instance" ], { favorite: !state.getIn([ "instance", "favorite" ]) }) + case success(MERGE): + const ids = action.ids.slice(1); + return state.update("list", list => list.filter(e => !ids.includes(e.errorId))); + case success(FETCH_NEW_ERRORS_COUNT): + return state.set('stats', action.data); + + } + return state; +} + +export default mergeReducers( + reducer, + createRequestReducer({ + [ ROOT_KEY ]: FETCH_LIST, + fetch: FETCH, + fetchTrace: FETCH_TRACE, + resolve: RESOLVE, + unresolve: UNRESOLVE, + ignore: IGNORE, + merge: MERGE, + toggleFavorite: TOGGLE_FAVORITE, + }), +); + + +export function fetch(id) { + return { + id, + types: array(FETCH), + call: c => c.get(`/errors/${id}`), + } +} + +export function fetchTrace(id) { + return { + id, + types: array(FETCH_TRACE), + call: c => c.get(`/errors/${id}/sourcemaps`), + } +} + +export function fetchList(params = {}, clear = false) { + return { + types: array(FETCH_LIST), + call: client => client.post('/errors/search', params), + clear, + params: cleanParams(params), + }; +} + +export function fetchBookmarks() { + return { + types: array(FETCH_LIST), + call: client => client.post('/errors/search?favorite', {}) + } +} + +export function resolve(id) { + return { + types: array(RESOLVE), + id, + call: client => client.get(`/errors/${ id }/solve`), + } +} + +export function unresolve(id) { + return { + types: array(UNRESOLVE), + id, + call: client => client.get(`/errors/${ id }/unsolve`), + } +} + +export function ignore(id) { + return { + types: array(IGNORE), + id, + call: client => client.get(`/errors/${ id }/ignore`), + } +} + +export function merge(ids) { + return { + types: array(MERGE), + ids, + call: client => client.post(`/errors/merge`, { errors: ids }), + } +} + +export function toggleFavorite(id) { + return { + types: array(TOGGLE_FAVORITE), + id, + call: client => client.get(`/errors/${ id }/favorite`), + } +} + +export function fetchNewErrorsCount(params = {}) { + return { + types: array(FETCH_NEW_ERRORS_COUNT), + call: client => client.get(`/errors/stats`, params), + } +} + diff --git a/frontend/app/duck/events.js b/frontend/app/duck/events.js new file mode 100644 index 000000000..000bd24b7 --- /dev/null +++ b/frontend/app/duck/events.js @@ -0,0 +1,81 @@ +import { List, Map, Set } from 'immutable'; +import withRequestState, { RequestTypes } from 'Duck/requestStateCreator'; +import Event from 'Types/filter/event'; +import CustomFilter from 'Types/filter/customFilter'; +import { KEYS } from 'Types/filter/customFilter'; +import logger from 'App/logger'; +import { countries } from 'App/constants'; +import { getRE } from 'App/utils'; + +const FETCH_LIST = new RequestTypes('events/FETCH_LIST'); +const TOGGLE_SELECT = 'events/TOGGLE_SELECT'; +const SET_SELECTED = 'events/SET_SELECTED'; + +const countryOptions = Object.keys(countries).map(c => ({filterKey: KEYS.USER_COUNTRY, label: KEYS.USER_COUNTRY, type: KEYS.USER_COUNTRY, value: c, actualValue: countries[c], isFilter: true })); + +const initialState = Map({ + list: List(), + store: Set(), + + // replace? + selected: Set(), +}); + +const filterKeys = ['METADATA', KEYS.USERID, KEYS.USER_COUNTRY, KEYS.USER_BROWSER, KEYS.USER_OS, KEYS.USER_DEVICE, KEYS.REFERRER] + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case FETCH_LIST.SUCCESS: { + const regCountry = getRE(action.params.q, 'i'); + const countryOptionsFiltered = List(countryOptions).filter(({ actualValue }) => regCountry.test(actualValue)).take(5); + + const eventList = List(action.data).concat(countryOptionsFiltered).map(item => ( + filterKeys.includes(item.type) ? + CustomFilter({...item, isFilter: true }) : + Event({...item, key: item.type, filterKey: item.type, label: item.type}) ) + ); + + return state + .set('list', eventList) + .update('store', store => store.concat(eventList)); + } + // TODO: use ids. or make a set-hoc? + case TOGGLE_SELECT: { + const { event, flag } = action; + const shouldBeInSet = typeof flag === 'boolean' + ? flag + : !state.get('selected').contains(event); + return state.update('selected', set => (shouldBeInSet + ? set.add(event) + : set.remove(event))); + } + case SET_SELECTED: + return state.set('selected', Set(action.events)); + } + return state; +}; + +export default withRequestState(FETCH_LIST, reducer); + +export function fetchList(params) { + return { + types: FETCH_LIST.toArray(), + call: client => client.get('/events/search', params), + params, + }; +} + +export function toggleSelect(event, flag) { + return { + type: TOGGLE_SELECT, + event, + flag, + }; +} + +export function setSelected(events) { + return { + type: SET_SELECTED, + events, + }; +} diff --git a/frontend/app/duck/filters.js b/frontend/app/duck/filters.js new file mode 100644 index 000000000..a06a0b6bc --- /dev/null +++ b/frontend/app/duck/filters.js @@ -0,0 +1,370 @@ +import { fromJS, List, Map, Set } from 'immutable'; +import { errors as errorsRoute, isRoute } from "App/routes"; +import Filter from 'Types/filter'; +import SavedFilter from 'Types/filter/savedFilter'; +import Event, { TYPES } from 'Types/filter/event'; +import CustomFilter, { KEYS } from 'Types/filter/customFilter'; +import withRequestState, { RequestTypes } from './requestStateCreator'; +import { fetchList as fetchSessionList } from './sessions'; +import { fetchList as fetchErrorsList } from './errors'; +import logger from 'App/logger'; + +const ERRORS_ROUTE = errorsRoute(); + +const FETCH_LIST = new RequestTypes('filters/FETCH_LIST'); +const FETCH_FILTER_OPTIONS = new RequestTypes('filters/FETCH_FILTER_OPTIONS'); +const SET_FILTER_OPTIONS = 'filters/SET_FILTER_OPTIONS'; +const SAVE = new RequestTypes('filters/SAVE'); +const REMOVE = new RequestTypes('filters/REMOVE'); + +const SET_SEARCH_QUERY = 'filters/SET_SEARCH_QUERY'; +const SET_ACTIVE = 'filters/SET_ACTIVE'; +const SET_ACTIVE_KEY = 'filters/SET_ACTIVE_KEY'; +const APPLY = 'filters/APPLY'; +const ADD_CUSTOM_FILTER = 'filters/ADD_CUSTOM_FILTER'; +const REMOVE_CUSTOM_FILTER = 'filters/REMOVE_CUSTOM_FILTER'; +const RESET_KEY = 'filters/RESET_KEY'; +const ADD_EVENT = 'filters/ADD_EVENT'; +const EDIT_EVENT = 'filters/EDIT_EVENT'; +const REMOVE_EVENT = 'filters/REMOVE_EVENT'; +const MOVE_EVENT = 'filters/MOVE_EVENT'; +const CLEAR_EVENTS = 'filters/CLEAR_EVENTS'; +const TOGGLE_FILTER_MODAL = 'filters/TOGGLE_FILTER_MODAL'; +const ADD_ATTRIBUTE = 'filters/ADD_ATTRIBUTE'; +const EDIT_ATTRIBUTE = 'filters/EDIT_ATTRIBUTE'; +const REMOVE_ATTRIBUTE = 'filters/REMOVE_ATTRIBUTE'; +const SET_ACTIVE_FLOW = 'filters/SET_ACTIVE_FLOW'; + +const initialState = Map({ + activeFilter: null, + list: List(), + appliedFilter: Filter(), + activeFilterKey: null, + saveModalOpen: false, + customFilters: Map(), + searchQuery: '', + activeFlow: null, + filterOptions: Map({ + USEROS: Set(), + USERBROWSER: Set(), + USERDEVICE: Set(), + REFERRER: Set(), + USERCOUNTRY: Set(), + PLATFORM: Set([ + {label: 'Platform', type: KEYS.PLATFORM, key: KEYS.PLATFORM, value: 'desktop', isFilter: true}, + {label: 'Platform', type: KEYS.PLATFORM, key: KEYS.PLATFORM, value: 'mobile', isFilter: true}, + {label: 'Platform', type: KEYS.PLATFORM, key: KEYS.PLATFORM, value: 'tablet', isFilter: true}, + ]), + }), +}); + +let hasFilterOptions = false; + +const updateList = (state, instance) => state.update('list', (list) => { + const index = list.findIndex(item => item.filterId === instance.filterId); + return (index >= 0 + ? list.mergeIn([ index ], instance) + : list.push(instance) + ); +}); + +const reducer = (state = initialState, action = {}) => { + let optionsMap = null; + switch (action.type) { + case FETCH_FILTER_OPTIONS.SUCCESS: + optionsMap = state.getIn(['filterOptions', action.key]).map(i => i.value).toJS(); + return state.mergeIn(['filterOptions', action.key], Set(action.data.filter(i => !optionsMap.includes(i.value)))); + case SET_FILTER_OPTIONS: + optionsMap = state.getIn(['filterOptions', action.key]); + optionsMap = optionsMap ? optionsMap.filter(i => i !== undefined).map(i => i.value).toJS() : [] + return state.mergeIn(['filterOptions', action.key], Set(action.filterOption.filter(i => !optionsMap.includes(i.value)))); + case FETCH_LIST.SUCCESS: + const flows = List(action.data).map(SavedFilter) + let _state = state.set('list', flows) + + if (!hasFilterOptions) { + const tmp = {} + flows.forEach(i => { + i.filter.filters.forEach(f => { + if (f.type && f.value && f.value.length > 0) { + tmp[f.type] = tmp[f.type] ? tmp[f.type].concat(f.value) : f.value + } + }) + }); + + Object.keys(tmp).forEach(f => { + const options = List(tmp[f]).map(i => ({type: i, value: i})) // TODO should get the unique items + _state = _state.mergeIn(['filterOptions', f], options); + }) + } + hasFilterOptions = true + return _state; + case SAVE.SUCCESS: + return updateList(state, SavedFilter(action.data)) + .set('saveModalOpen', false); + case REMOVE.SUCCESS: + return state.update( + 'list', + list => list + .filter(filter => filter.filterId !== action.id), + ).set('activeFilter', null); + case SET_ACTIVE: + return state.set('activeFilter', action.filter); + case SET_ACTIVE_FLOW: + return state.set('activeFlow', action.flow); + case SET_ACTIVE_KEY: + return state.set('activeFilterKey', action.filterKey); + case APPLY: + return action.fromUrl + ? state.set('appliedFilter', + Filter(action.filter) + .set('events', state.getIn([ 'appliedFilter', 'events' ])) + ) + : state.mergeIn([ 'appliedFilter' ], action.filter); + case ADD_CUSTOM_FILTER: + return state.update('customFilters', vars => vars.set(action.filter, action.value)); + case REMOVE_CUSTOM_FILTER: + return state.update('customFilters', vars => vars.remove(action.filterKey)); + case RESET_KEY: + if (action.key === 'rangeValue') { + return state + .removeIn([ 'appliedFilter', 'rangeValue' ]) + .removeIn([ 'appliedFilter', 'startDate' ]) + .removeIn([ 'appliedFilter', 'endDate' ]); + } else if (action.key === 'duration') { + return state + .removeIn([ 'appliedFilter', 'minDuration' ]) + .removeIn([ 'appliedFilter', 'maxDuration' ]); + } + return state.removeIn([ 'appliedFilter', action.key ]); + case ADD_EVENT: + // const eventValue = action.event.type === TYPES.INPUT ? (action.event.target ? action.event.target.label : '') : action.event.value; + const eventValue = action.event.value; + const event = Event(action.event).set('value', eventValue); + if (action.index >= 0) // replacing an event + return state.setIn([ 'appliedFilter', 'events', action.index ], event) + else + return state.updateIn([ 'appliedFilter', 'events' ], list => action.single + ? List([ event ]) + : list.push(event)); + case REMOVE_EVENT: + return state.removeIn([ 'appliedFilter', 'events', action.index ]); + case EDIT_EVENT: + return state.mergeIn([ 'appliedFilter', 'events', action.index], action.filter); + case TOGGLE_FILTER_MODAL: + return state.set('saveModalOpen', action.show); + case MOVE_EVENT: + const { fromI, toI } = action; + return state + .updateIn([ 'appliedFilter', 'events' ], list => + list.remove(fromI).insert(toI, list.get(fromI))); + case CLEAR_EVENTS: + return state.setIn([ 'appliedFilter', 'events' ], List()) + .setIn([ 'appliedFilter', 'filters' ], List()) + .set('searchQuery', ''); + + case ADD_ATTRIBUTE: + const filter = CustomFilter(action.filter); + + if (action.index >= 0) // replacing the filter + return state.setIn([ 'appliedFilter', 'filters', action.index], filter); + else + return state.updateIn([ 'appliedFilter', 'filters'], filters => filters.push(filter)); + + case EDIT_ATTRIBUTE: + return state.setIn([ 'appliedFilter', 'filters', action.index, action.key ], action.value ); + case REMOVE_ATTRIBUTE: + return state.removeIn([ 'appliedFilter', 'filters', action.index ]); + case SET_SEARCH_QUERY: + return state.set('searchQuery', action.query); + default: + return state; + } +}; + +export default withRequestState({ + _: [ REMOVE ], + fetchListRequest: FETCH_LIST, + saveRequest: SAVE, + fetchFilterOptions: FETCH_FILTER_OPTIONS, +}, reducer); + +const eventMap = ({value, searchType, key, operator, source, custom}) => ({value, type: searchType, key, operator, source, custom}); +const filterMap = ({value, type, key, operator, source, custom }) => ({value: Array.isArray(value) ? value: [value], custom, type, key, operator, source}); +const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => { + dispatch(actionCreator(...args)); + const appliedFilters = getState().getIn([ 'filters', 'appliedFilter' ]); + const filter = appliedFilters + .update('events', list => list.map(event => event.set('value', event.value || '*')).map(eventMap)) + .set('strict', true) // Temp backend issue + .toJS(); + filter.filters = getState().getIn([ 'filters', 'appliedFilter', 'filters' ]) + .map(filterMap).toJS(); + + // Hello AGILE! + return isRoute(ERRORS_ROUTE, window.location.pathname) + ? dispatch(fetchErrorsList(filter)) + : dispatch(fetchSessionList(filter)); +} + +export function editAttribute(index, key, value) { + return { + type: EDIT_ATTRIBUTE, + index, + key, + value, + }; +} + +export function addAttribute(filter, index) { + return { + type: ADD_ATTRIBUTE, + filter, + index + }; +} + +export function removeAttribute(index) { + return { + type: REMOVE_ATTRIBUTE, + index, + }; +} + +export function fetchList(range) { + return { + types: FETCH_LIST.toArray(), + call: client => client.get(`/flows${range ? '?range_value=' + range : ''}`), + }; +} + +export function fetchFilterOptions(filter, q) { + return { + types: FETCH_FILTER_OPTIONS.toArray(), + call: client => client.get('/sessions/filters/search', { q, type: filter.type }), + key: filter.key + }; +} + +export function setFilterOption(key, filterOption) { + return { + type: SET_FILTER_OPTIONS, + key, + filterOption + } +} + +export function save(instance) { + return { + types: SAVE.toArray(), + call: client => client.post('/filters', instance.toData()), + instance, + }; +} + +export function remove(id) { + return { + types: REMOVE.toArray(), + call: client => client.delete(`/filters/${ id }`), + id, + }; +} + +export function setActive(filter) { + return { + type: SET_ACTIVE, + filter, + }; +} + +export function setActiveFlow(flow) { + return { + type: SET_ACTIVE_FLOW, + flow, + }; +} + +export function setActiveKey(filterKey) { + return { + type: SET_ACTIVE_KEY, + filterKey, + }; +} + +export const addCustomFilter = reduceThenFetchResource((filter, value) => ({ + type: ADD_CUSTOM_FILTER, + filter, + value, +})); + +export const removeCustomFilter = reduceThenFetchResource(filterKey => ({ + type: REMOVE_CUSTOM_FILTER, + filterKey, +})); + +export const applyFilter = reduceThenFetchResource((filter, fromUrl=false) => ({ + type: APPLY, + filter, + fromUrl, +})); + +export const applySavedFilter = reduceThenFetchResource((filter, fromUrl=false) => ({ + type: APPLY, + filter, + fromUrl, +})); + +export const resetFilterKey = reduceThenFetchResource(key => ({ + type: RESET_KEY, + key, +})); + +export const clearEvents = reduceThenFetchResource(() => ({ + type: CLEAR_EVENTS, +})); + +export function addEvent(event, single = false, index) { + return { + type: ADD_EVENT, + event, + single, + index + }; +} + +export function removeEvent(index) { + return { + type: REMOVE_EVENT, + index, + }; +} + +export function moveEvent(fromI, toI) { + return { + type: MOVE_EVENT, + fromI, + toI, + }; +} + +export function editEvent(index, filter) { + return { + type: EDIT_EVENT, + index, + filter + }; +} + +export function toggleFilterModal(show) { + return { + type: TOGGLE_FILTER_MODAL, + show, + }; +} + +export function setSearchQuery(query) { + return { + type: SET_SEARCH_QUERY, + query + } +} \ No newline at end of file diff --git a/frontend/app/duck/funcTools/crud/actions.js b/frontend/app/duck/funcTools/crud/actions.js new file mode 100644 index 000000000..a6e64f4e2 --- /dev/null +++ b/frontend/app/duck/funcTools/crud/actions.js @@ -0,0 +1,77 @@ +import { + initType, + editType, + fetchType, + fetchToListType, + fetchListType, + saveType, + removeType, +} from './types'; +import { + array +} from '../tools'; + +const pluralise = name => `${ name }s`; + +export const createInit = name => instance => ({ + type: initType(name), + instance, +}); + +export const createFetch = (name, endpoint = id => `/${ pluralise(name) }/${ id }` ) => { + const fetchTypeArray = array(fetchType(name)); + const fetchToListTypeArray = array(fetchToListType(name)); + return (id, options = { thenInit: true }) => (dispatch, getState) => { + const itemInList = getState().getIn([ name, 'list' ]).find(item => item[ idKey ] === id); + if (!itemInList || !itemInList.isComplete()) { // name of func? + return dispatch({ + types: options.thenInit ? fetchTypeArray : fetchToListTypeArray, + call: client => client.get(endpoint(id)), + }); + } + if (options.thenInit) dispatch(createInit(name)(itemInList)); + return Promise.resolve(); + }; +}; + +export const createFetchList = (name, endpoint = `/${ pluralise(name) }`) => { + const types = array(fetchListType(name)); + return params => ({ + types, + call: client => client.get(endpoint, params), + }); +}; + +export const createEdit = (name) => { + const type = editType(name); + return instance => ({ + type, + instance, + }); +}; + +export const createSave = (name, endpoint = `/${ pluralise(name) }`) => { + const types = array(saveType(name)); + return instance => ({ + types, + call: client => client.put(endpoint, instance.toData()), + }); +}; + +export const createUpdate = (name, endpoint = id => `/${ pluralise(name) }/${id}`) => { + const types = array(saveType(name)); + return instance => ({ + types, + call: client => client.put(endpoint(instance.id), instance.toData()), + id: instance.id, + }); +}; + +export const createRemove = (name, endpoint = id => `/${ pluralise(name) }/${ id }`) => { + const types = array(removeType(name)); + return id => ({ + types, + call: client => client.delete(endpoint(id)), + id, + }); +}; \ No newline at end of file diff --git a/frontend/app/duck/funcTools/crud/index.js b/frontend/app/duck/funcTools/crud/index.js new file mode 100644 index 000000000..3e9920a71 --- /dev/null +++ b/frontend/app/duck/funcTools/crud/index.js @@ -0,0 +1,3 @@ +export * from './actions'; +export * from './reducer'; +export * from './types'; \ No newline at end of file diff --git a/frontend/app/duck/funcTools/crud/reducer.js b/frontend/app/duck/funcTools/crud/reducer.js new file mode 100644 index 000000000..44dc3781c --- /dev/null +++ b/frontend/app/duck/funcTools/crud/reducer.js @@ -0,0 +1,66 @@ +import { Map, List } from 'immutable'; +import { + initType, + fetchType, + fetchListType, + fetchToListType, + saveType, + editType, + removeType, +} from './types'; +import { + success, + createItemInListUpdater, +} from '../tools'; + + +export const getCRUDRequestTypes = name => ({ + _: fetchListType(name), + fetchList: fetchListType(name), + fetchToList: fetchToListType(name), + save: saveType(name), + remove: removeType(name), + fetch: fetchType(name), +}); + +export const getCRUDInitialState = fromJS => Map({ + list: List(), + instance: fromJS(), +}); +export const createCRUDReducer = (name, fromJS = r => r, idKey = `${ name }Id`) => { + const itemInListUpdater = createItemInListUpdater(idKey); + const initialState = getCRUDInitialState(fromJS); + const FETCH_SUCCESS = success(fetchType(name)); + const FETCH_LIST_SUCCESS = success(fetchListType(name)); + const FETCH_TO_LIST_SUCCESS = success(fetchToListType(name)); + const INIT = initType(name); + const SAVE_SUCCESS = success(saveType(name)); + const EDIT = editType(name); + const REMOVE_SUCCESS = success(removeType(name)); + return (state = initialState, action = {}) => { + switch (action.type) { + case FETCH_LIST_SUCCESS: + // TODO: use OreredMap by id & merge; + return state.set('list', List(action.data).map(fromJS)); + case FETCH_TO_LIST_SUCCESS: + return updateList(state, fromJS(action.data)); + case INIT: + return state.set('instance', fromJS(action.instance)); + case SAVE_SUCCESS: + case FETCH_SUCCESS: { + const instance = fromJS(action.data); + return state + .update('list', itemInListUpdater(instance)) + .set('instance', instance); + } + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + case REMOVE_SUCCESS: + return state + .update('list', list => list.filter(item => item[ idKey ] !== action.id)) + .updateIn([ 'instance', idKey ], id => (id === action.id ? '' : id)); + default: + return state; + } + }; +} diff --git a/frontend/app/duck/funcTools/crud/types.js b/frontend/app/duck/funcTools/crud/types.js new file mode 100644 index 000000000..98fa57596 --- /dev/null +++ b/frontend/app/duck/funcTools/crud/types.js @@ -0,0 +1,9 @@ +import { RequestType } from '../request'; + +export const initType = name => `${ name }/INIT`; +export const editType = name => `${ name }/EDIT`; +export const fetchType = name => new RequestType(`${ name }/FETCH`); +export const fetchToListType = name => new RequestType(`${ name }/FETCH_TO_LIST`); +export const fetchListType = name => new RequestType(`${ name }/FETCH_LIST`); +export const saveType = name => new RequestType(`${ name }/SAVE`); +export const removeType = name => new RequestType(`${ name }/REMOVE`); \ No newline at end of file diff --git a/frontend/app/duck/funcTools/index.js b/frontend/app/duck/funcTools/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/app/duck/funcTools/list/actions.js b/frontend/app/duck/funcTools/list/actions.js new file mode 100644 index 000000000..eb6c88a8b --- /dev/null +++ b/frontend/app/duck/funcTools/list/actions.js @@ -0,0 +1,13 @@ +import { + editInListType, +} from './types'; + +export const createEditInList = (name) => { + const type = editInListType(name); + return item => ({ + type, + item, + }); +}; + +export { createFetchList } from '../crud'; \ No newline at end of file diff --git a/frontend/app/duck/funcTools/list/index.js b/frontend/app/duck/funcTools/list/index.js new file mode 100644 index 000000000..3e9920a71 --- /dev/null +++ b/frontend/app/duck/funcTools/list/index.js @@ -0,0 +1,3 @@ +export * from './actions'; +export * from './reducer'; +export * from './types'; \ No newline at end of file diff --git a/frontend/app/duck/funcTools/list/reducer.js b/frontend/app/duck/funcTools/list/reducer.js new file mode 100644 index 000000000..c63f75721 --- /dev/null +++ b/frontend/app/duck/funcTools/list/reducer.js @@ -0,0 +1,29 @@ +import { Map, List } from 'immutable'; +import { + fetchListType, + editInListType, +} from './types'; +import { success } from '../tools'; + + +const listInitialState = Map({ + list: List(), +}); + +export const getListInitialState = () => listInitialState; + +export const createListReducer = (name, fromJS = r => r, idKey = `${ name }Id`) => { + const FETCH_LIST_SUCCESS = success(fetchListType(name)); + const EDIT_IN_LIST = editInListType(name); + return (state = listInitialState, action = {}) => { + switch (action.type) { + case FETCH_LIST_SUCCESS: + return state.set('list', List(action.data).map(fromJS)); + case EDIT_IN_LIST: + const itemIndex = state.get('list').findIndex(item => item[ idKey ] === action.item[ idKey ]) + return state.mergeIn([ 'list', itemIndex ], action.item); + default: + return state; + } + }; +} diff --git a/frontend/app/duck/funcTools/list/types.js b/frontend/app/duck/funcTools/list/types.js new file mode 100644 index 000000000..02e72f7e8 --- /dev/null +++ b/frontend/app/duck/funcTools/list/types.js @@ -0,0 +1,4 @@ +export const editInListType = name => `${ name }/EDIT_IN_LIST`; +export const removeFromListType = name => `${ name }/REMOVE_FROM_LIST`; + +export { fetchListType } from '../crud'; \ No newline at end of file diff --git a/frontend/app/duck/funcTools/request/RequestType.js b/frontend/app/duck/funcTools/request/RequestType.js new file mode 100644 index 000000000..68048b5ef --- /dev/null +++ b/frontend/app/duck/funcTools/request/RequestType.js @@ -0,0 +1,14 @@ +export default class RequestType extends String { + get request() { + return `${ this }_REQUEST`; + } + get success() { + return `${ this }_SUCCESS`; + } + get failure() { + return `${ this }_FAILURE`; + } + get array() { + return [ this.request, this.success, this.failure ]; + } +} \ No newline at end of file diff --git a/frontend/app/duck/funcTools/request/index.js b/frontend/app/duck/funcTools/request/index.js new file mode 100644 index 000000000..858c33f8e --- /dev/null +++ b/frontend/app/duck/funcTools/request/index.js @@ -0,0 +1,2 @@ +export * from './reducer'; +export * from './types'; \ No newline at end of file diff --git a/frontend/app/duck/funcTools/request/reducer.js b/frontend/app/duck/funcTools/request/reducer.js new file mode 100644 index 000000000..4840d4b3f --- /dev/null +++ b/frontend/app/duck/funcTools/request/reducer.js @@ -0,0 +1,89 @@ +import { List, Map } from 'immutable'; +import { RequestType } from './types'; +import { request, success, failure } from '../tools'; // + +export const ROOT_KEY = '_'; +const defaultReducer = (state = Map()) => state; + + +const simpleRequestInitialState = Map({ + loading: false, + errors: null, +}); + +const getKeys = types => Object.keys(types).filter(key => key !== ROOT_KEY); + +export function getRequestInitialState(types) { + if (typeof types === 'string' || Array.isArray(types)) { + return simpleRequestInitialState; + } + let initialState = Map(); + if (types[ ROOT_KEY ]) { + initialState = getRequestInitialState(types[ ROOT_KEY ]); + } + return getKeys(types).reduce( + (accumState, key) => accumState.set(key, getRequestInitialState(types[ key ])), + initialState, + ); +} + +function createSimpleRequestReducer(types, reducer) { + const typesArray = Array.isArray(types) ? types : [ types ]; + const requestEvents = typesArray.map(t => t.request || request(t)); // back compat. + const successEvents = typesArray.map(t => t.success || success(t)); + const failureEvents = typesArray.map(t => t.failure || failure(t)); + + let loadingCounter = 0; + + return (state, action = {}) => { + if (state === undefined) { + if (typeof reducer === "function") { // flow? + state = reducer(state, action).merge(simpleRequestInitialState); + } else { + state = simpleRequestInitialState; + } + } + if (requestEvents.includes(action.type)) { + loadingCounter += 1; + return state.set('loading', loadingCounter > 0).set('errors', null); + } + if (successEvents.includes(action.type)) { + loadingCounter -= 1; + return state.set('loading', loadingCounter > 0).set('errors', null); + } + if (failureEvents.includes(action.type)) { + loadingCounter -= 1; + return state.set('loading', loadingCounter > 0).set('errors', List(action.errors)); + } + return state; + }; +}; + +/** + * @types: RequestTypes - array or single + * or object like {'state1': RequestTypes, 'state2': [RequestTypes] ... } + * */ +export function createRequestReducer(types, reducer = defaultReducer) { + if (typeof types === 'string' || types instanceof RequestType || Array.isArray(types)) { + return createSimpleRequestReducer(types); + } + + const keys = getKeys(types); + const reducers = {}; + keys.map((key) => { reducers[ key ] = createRequestReducer(types[ key ]); }); + + let rootReducer = typeof reducer === 'function' ? reducer : defaultReducer; + // TODO: remove ROOT_KEY logic + if (types[ ROOT_KEY ]) { + rootReducer = createRequestReducer(types[ ROOT_KEY ], rootReducer); + } + return (state, action = {}) => { + state = rootReducer(state, action); + keys.map((key) => { + state = state.update(key, subState => reducers[ key ](subState, action)); + }); + return state; + }; +}; + + diff --git a/frontend/app/duck/funcTools/request/types.js b/frontend/app/duck/funcTools/request/types.js new file mode 100644 index 000000000..3976af497 --- /dev/null +++ b/frontend/app/duck/funcTools/request/types.js @@ -0,0 +1 @@ +export { default as RequestType } from './RequestType'; \ No newline at end of file diff --git a/frontend/app/duck/funcTools/tools.js b/frontend/app/duck/funcTools/tools.js new file mode 100644 index 000000000..e2be77371 --- /dev/null +++ b/frontend/app/duck/funcTools/tools.js @@ -0,0 +1,38 @@ +import { Map } from 'immutable'; + +export function mergeReducers(...reducers) { + const initialState = reducers + .reduce((accumState, reducer) => accumState.merge(reducer()), Map()); + return (state = initialState, action) => + reducers.reduce((accumState, reducer) => reducer(accumState, action), state); +} + +export function createListUpdater(idKey, listName = 'list') { + return (state, instance) => state.update(listName, (list) => { + const index = list.findIndex(item => item[ idKey ] === instance[ idKey ]); + return (index >= 0 + ? list.mergeIn([ index ], instance) + : list.push(instance) + ); + }); +} + +export function createItemInListUpdater(idKey = 'id', shouldAdd = true) { + return instance => + list => { + const index = list.findIndex(item => item[ idKey ] === instance[ idKey ]); + return index >= 0 + ? list.mergeIn([ index ], instance) + : (shouldAdd ? list.push(instance) : list); + } +} + +export function createItemInListFilter(idKey = 'id') { + return id => + list => list.filter(item => item[ idKey ] !== id) +} + +export const request = type => `${ type }_REQUEST`; +export const success = type => `${ type }_SUCCESS`; +export const failure = type => `${ type }_FAILURE`; +export const array = type => [ request(type), success(type), failure(type) ]; diff --git a/frontend/app/duck/funcTools/types.js b/frontend/app/duck/funcTools/types.js new file mode 100644 index 000000000..4897e4dfc --- /dev/null +++ b/frontend/app/duck/funcTools/types.js @@ -0,0 +1,3 @@ +export * from './crud/types'; +export * from './list/types'; +export * from './request/types'; diff --git a/frontend/app/duck/funnelFilters.js b/frontend/app/duck/funnelFilters.js new file mode 100644 index 000000000..294ba2039 --- /dev/null +++ b/frontend/app/duck/funnelFilters.js @@ -0,0 +1,378 @@ +import { fromJS, List, Map, Set } from 'immutable'; +import { errors as errorsRoute, isRoute } from "App/routes"; +import Filter from 'Types/filter'; +import SavedFilter from 'Types/filter/savedFilter'; +import Event, { TYPES } from 'Types/filter/event'; +import CustomFilter from 'Types/filter/customFilter'; +import withRequestState, { RequestTypes } from './requestStateCreator'; +import { fetchList as fetchSessionList } from './sessions'; +import { fetchList as fetchErrorsList } from './errors'; +import { fetch as fetchFunnel, fetchInsights, fetchIssuesFiltered, fetchSessionsFiltered } from './funnels'; +import logger from 'App/logger'; + +const ERRORS_ROUTE = errorsRoute(); + +const FETCH_LIST = new RequestTypes('funnelFilters/FETCH_LIST'); +const FETCH_FILTER_OPTIONS = new RequestTypes('funnelFilters/FETCH_FILTER_OPTIONS'); +const SET_FILTER_OPTIONS = 'funnelFilters/SET_FILTER_OPTIONS'; +const SAVE = new RequestTypes('funnelFilters/SAVE'); +const REMOVE = new RequestTypes('funnelFilters/REMOVE'); + +const RESET = 'funnelFilters/RESET'; +const SET_SEARCH_QUERY = 'funnelFilters/SET_SEARCH_QUERY'; +const SET_ACTIVE = 'funnelFilters/SET_ACTIVE'; +const SET_ACTIVE_KEY = 'funnelFilters/SET_ACTIVE_KEY'; +const APPLY = 'funnelFilters/APPLY'; +const ADD_CUSTOM_FILTER = 'funnelFilters/ADD_CUSTOM_FILTER'; +const REMOVE_CUSTOM_FILTER = 'funnelFilters/REMOVE_CUSTOM_FILTER'; +const RESET_KEY = 'funnelFilters/RESET_KEY'; +const ADD_EVENT = 'funnelFilters/ADD_EVENT'; +const EDIT_EVENT = 'funnelFilters/EDIT_EVENT'; +const REMOVE_EVENT = 'funnelFilters/REMOVE_EVENT'; +const MOVE_EVENT = 'funnelFilters/MOVE_EVENT'; +const CLEAR_EVENTS = 'funnelFilters/CLEAR_EVENTS'; +const TOGGLE_FILTER_MODAL = 'funnelFilters/TOGGLE_FILTER_MODAL'; +const ADD_ATTRIBUTE = 'funnelFilters/ADD_ATTRIBUTE'; +const EDIT_ATTRIBUTE = 'funnelFilters/EDIT_ATTRIBUTE'; +const REMOVE_ATTRIBUTE = 'funnelFilters/REMOVE_ATTRIBUTE'; +const SET_ACTIVE_FLOW = 'funnelFilters/SET_ACTIVE_FLOW'; + +const SET_INITIAL_FILTER = 'funnelFilters/SET_INITIAL_FILTER'; + +const initialState = Map({ + activeFilter: null, + list: List(), + appliedFilter: Filter(), + activeFilterKey: null, + saveModalOpen: false, + customFilters: Map(), + searchQuery: '', + activeFlow: null, + filterOptions: Map({ + USEROS: Set(), + USERBROWSER: Set(), + USERDEVICE: Set(), + REFERRER: Set(), + USERCOUNTRY: Set(), + }), +}); + +let hasFilterOptions = false; + +const updateList = (state, instance) => state.update('list', (list) => { + const index = list.findIndex(item => item.filterId === instance.filterId); + return (index >= 0 + ? list.mergeIn([ index ], instance) + : list.push(instance) + ); +}); + +const reducer = (state = initialState, action = {}) => { + let optionsMap = null; + switch (action.type) { + case FETCH_FILTER_OPTIONS.SUCCESS: + // return state.mergeIn(['filterOptions', action.key], fromJS(action.data).map(item => ({text: item, value: item}))); + optionsMap = state.getIn(['filterOptions', action.key]).map(i => i.value).toJS(); + return state.mergeIn(['filterOptions', action.key], Set(action.data.filter(i => !optionsMap.includes(i.value)))); + case SET_FILTER_OPTIONS: + // optionsMap = state.getIn(['filterOptions', action.key]); + // optionsMap = optionsMap ? optionsMap.map(i => i.value).toJS() : [] + // return state.mergeIn(['filterOptions', action.key], Set(action.filterOption.filter(i => !optionsMap.includes(i.value)))); + const tmp = {} + let _state = state; + action.filters.forEach(f => { + if (f.type && f.value && f.value.length > 0) { + tmp[f.type] = tmp[f.type] ? tmp[f.type].concat(f.value) : f.value + } + }) + Object.keys(tmp).forEach(f => { + const options = List(tmp[f]).map(i => ({type: i, value: i})) // TODO should get the unique items + _state = _state.mergeIn(['filterOptions', f], options); + }) + + return _state; + case FETCH_LIST.SUCCESS: + return state; + case SAVE.SUCCESS: + return updateList(state, SavedFilter(action.data)) + .set('saveModalOpen', false); + case REMOVE.SUCCESS: + return state.update( + 'list', + list => list + .filter(filter => filter.filterId !== action.id), + ).set('activeFilter', null); + case SET_ACTIVE: + return state.set('activeFilter', action.filter); + case SET_ACTIVE_FLOW: + return state.set('activeFlow', action.flow); + case SET_ACTIVE_KEY: + return state.set('activeFilterKey', action.filterKey); + case APPLY: + return action.fromUrl + ? state.set('appliedFilter', + Filter(action.filter) + .set('events', state.getIn([ 'appliedFilter', 'events' ])) + ) + : state.mergeIn([ 'appliedFilter' ], action.filter); + case ADD_CUSTOM_FILTER: + return state.update('customFilters', vars => vars.set(action.filter, action.value)); + case REMOVE_CUSTOM_FILTER: + return state.update('customFilters', vars => vars.remove(action.filterKey)); + case RESET_KEY: + if (action.key === 'rangeValue') { + return state + .removeIn([ 'appliedFilter', 'rangeValue' ]) + .removeIn([ 'appliedFilter', 'startDate' ]) + .removeIn([ 'appliedFilter', 'endDate' ]); + } else if (action.key === 'duration') { + return state + .removeIn([ 'appliedFilter', 'minDuration' ]) + .removeIn([ 'appliedFilter', 'maxDuration' ]); + } + return state.removeIn([ 'appliedFilter', action.key ]); + case ADD_EVENT: + const eventValue = action.event.value; + const event = Event(action.event).set('value', eventValue); + if (action.index >= 0) // replacing an event + return state.setIn([ 'appliedFilter', 'events', action.index ], event) + else + return state.updateIn([ 'appliedFilter', 'events' ], list => action.single + ? List([ event ]) + : list.push(event)); + case REMOVE_EVENT: + return state.removeIn([ 'appliedFilter', 'events', action.index ]); + case EDIT_EVENT: + return state.mergeIn([ 'appliedFilter', 'events', action.index], action.filter); + case TOGGLE_FILTER_MODAL: + return state.set('saveModalOpen', action.show); + case MOVE_EVENT: + const { fromI, toI } = action; + return state + .updateIn([ 'appliedFilter', 'events' ], list => + list.remove(fromI).insert(toI, list.get(fromI))); + case CLEAR_EVENTS: + return state.setIn([ 'appliedFilter', 'events' ], List()) + .setIn([ 'appliedFilter', 'filters' ], List()) + .set('searchQuery', ''); + + case ADD_ATTRIBUTE: + const filter = CustomFilter(action.filter); + + if (action.index >= 0) // replacing the filter + return state.setIn([ 'appliedFilter', 'filters', action.index], filter); + else + return state.updateIn([ 'appliedFilter', 'filters'], filters => filters.push(filter)); + case EDIT_ATTRIBUTE: + return state.setIn([ 'appliedFilter', 'filters', action.index, action.key ], action.value ); + case REMOVE_ATTRIBUTE: + return state.removeIn([ 'appliedFilter', 'filters', action.index ]); + case SET_SEARCH_QUERY: + return state.set('searchQuery', action.query); + case RESET: + return state.set('appliedFilter', Filter({})) + default: + return state; + } +}; + +export default withRequestState({ + _: [ REMOVE ], + fetchListRequest: FETCH_LIST, + saveRequest: SAVE, + fetchFilterOptions: FETCH_FILTER_OPTIONS, +}, reducer); + +const eventMap = ({value, type, key, operator, source, custom}) => ({value, type, key, operator, source, custom}); +const filterMap = ({value, type, key, operator, source, custom }) => ({value: Array.isArray(value) ? value: [value], custom, type, key, operator, source}); +const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => { + const action = actionCreator(...args); + dispatch(action); + const appliedFilters = getState().getIn([ 'funnelFilters', 'appliedFilter' ]); + const filter = appliedFilters + .update('events', list => list.map(event => event.set('value', event.value || '*')).map(eventMap)) + .toJS(); + + filter.filters = getState().getIn([ 'funnelFilters', 'appliedFilter', 'filters' ]) + .map(filterMap).toJS(); + + if (action.funnelId) { + dispatch(fetchFunnel(action.funnelId)) + dispatch(fetchInsights(action.funnelId, filter)) + dispatch(fetchIssuesFiltered(action.funnelId, filter)) + dispatch(fetchSessionsFiltered(action.funnelId, filter)) + } +} + +export function editAttribute(index, key, value) { + return { + type: EDIT_ATTRIBUTE, + index, + key, + value, + }; +} + +export function addAttribute(filter, index) { + return { + type: ADD_ATTRIBUTE, + filter, + index + }; +} + +export function removeAttribute(index) { + return { + type: REMOVE_ATTRIBUTE, + index, + }; +} + +export function fetchList(range) { + return { + types: FETCH_LIST.toArray(), + call: client => client.get(`/funnels`), + }; +} + +export function fetchFilterOptions(filter, q) { + return { + types: FETCH_FILTER_OPTIONS.toArray(), + call: client => client.get('/sessions/filters/search', { q, type: filter.type }), + key: filter.key + }; +} + +export function setFilterOptions(filters) { + return { + type: SET_FILTER_OPTIONS, + filters + } +} + +export function save(instance) { + return { + types: SAVE.toArray(), + call: client => client.post('/filters', instance.toData()), + instance, + }; +} + +export function remove(id) { + return { + types: REMOVE.toArray(), + call: client => client.delete(`/filters/${ id }`), + id, + }; +} + +export function setActive(filter) { + return { + type: SET_ACTIVE, + filter, + }; +} + +export function setActiveFlow(flow) { + return { + type: SET_ACTIVE_FLOW, + flow, + }; +} + +export function setActiveKey(filterKey) { + return { + type: SET_ACTIVE_KEY, + filterKey, + }; +} + +export const addCustomFilter = reduceThenFetchResource((filter, value) => ({ + type: ADD_CUSTOM_FILTER, + filter, + value, +})); + +export const removeCustomFilter = reduceThenFetchResource(filterKey => ({ + type: REMOVE_CUSTOM_FILTER, + filterKey, +})); + +export const applyFilter = reduceThenFetchResource((filter, funnelId, fromUrl=false) => ({ + type: APPLY, + filter, + funnelId, + fromUrl, +})); + +export const setInitialFilters = () => (dispatch, getState) => { + return dispatch({ + type: APPLY, + filter: getState().getIn(['funnels', 'instance', 'filter']) + }) +} + +export const applySavedFilter = reduceThenFetchResource((filter, fromUrl=false) => ({ + type: APPLY, + filter, + fromUrl, +})); + +export const resetFilterKey = reduceThenFetchResource(key => ({ + type: RESET_KEY, + key, +})); + +export const clearEvents = reduceThenFetchResource(() => ({ + type: CLEAR_EVENTS, +})); + +export function addEvent(event, single = false, index) { + return { + type: ADD_EVENT, + event, + single, + index + }; +} + +export const removeEvent = reduceThenFetchResource((index, funnelId) => ({ + type: REMOVE_EVENT, + index, + funnelId +})); + +export function moveEvent(fromI, toI) { + return { + type: MOVE_EVENT, + fromI, + toI, + }; +} + +export const editEvent = reduceThenFetchResource((index, filter, funnelId) => ({ + type: EDIT_EVENT, + index, + filter, + funnelId +})) + +export function toggleFilterModal(show) { + return { + type: TOGGLE_FILTER_MODAL, + show, + }; +} + +export function setSearchQuery(query) { + return { + type: SET_SEARCH_QUERY, + query + } +} + +export function resetFunnelFilters() { + return { + type: RESET + } +} \ No newline at end of file diff --git a/frontend/app/duck/funnels.js b/frontend/app/duck/funnels.js new file mode 100644 index 000000000..4e591237c --- /dev/null +++ b/frontend/app/duck/funnels.js @@ -0,0 +1,403 @@ +import { List, Map } from 'immutable'; +import Funnel from 'Types/funnel'; +import FunnelIssue from 'Types/funnelIssue'; +import Session from 'Types/session'; +import { fetchListType, fetchType, saveType, editType, initType, removeType } from './funcTools/crud/types'; +import { createItemInListUpdater, mergeReducers, success, array } from './funcTools/tools'; +import { createRequestReducer } from './funcTools/request'; +import { getDateRangeFromValue } from 'App/dateRange'; +import { LAST_7_DAYS } from 'Types/app/period'; + +const name = 'funnel'; +const idKey = 'funnelId'; +const itemInListUpdater = createItemInListUpdater(idKey); + +const FETCH_LIST = fetchListType('funnel/FETCH_LIST'); +const FETCH_ISSUES = fetchType('funnel/FETCH_ISSUES'); +const FETCH_ISSUE = fetchType('funnel/FETCH_ISSUE'); +const FETCH_ISSUE_TYPES = fetchType('funnel/FETCH_ISSUE_TYPES'); +const FETCH_SESSIONS = fetchType('funnel/FETCH_SESSIONS'); +const FETCH = fetchType('funnel/FETCH'); +const FETCH_INSIGHTS = fetchType('funnel/FETCH_INSIGHTS'); +const SAVE = saveType('funnel/SAVE'); +const UPDATE = saveType('funnel/UPDATE'); +const EDIT = editType('funnel/EDIT'); +const REMOVE = removeType('funnel/REMOVE'); +const INIT = initType('funnel/INIT'); +const SET_NAV_REF = 'funnels/SET_NAV_REF' + +const RESET_FUNNEL = 'funnels/RESET_FUNNEL' +const APPLY_FILTER = 'funnels/APPLY_FILTER' +const APPLY_ISSUE_FILTER = 'funnels/APPLY_ISSUE_FILTER' +const REMOVE_ISSUE_FILTER = 'funnels/REMOVE_ISSUE_FILTER' +const SET_ACTIVE_STAGES = 'funnels/SET_ACTIVE_STAGES' +const SET_SESSIONS_SORT = 'funnels/SET_SESSIONS_SORT' +const BLINK = 'funnels/BLINK' + +const RESET_ISSUE = 'funnles/RESET_ISSUE' + +const FETCH_LIST_SUCCESS = success(FETCH_LIST); +const FETCH_ISSUES_SUCCESS = success(FETCH_ISSUES); +const FETCH_ISSUE_SUCCESS = success(FETCH_ISSUE); +const FETCH_ISSUE_TYPES_SUCCESS = success(FETCH_ISSUE_TYPES); +const FETCH_SESSIONS_SUCCESS = success(FETCH_SESSIONS); +const FETCH_SUCCESS = success(FETCH); +const FETCH_INSIGHTS_SUCCESS = success(FETCH_INSIGHTS); +const SAVE_SUCCESS = success(SAVE); +const UPDATE_SUCCESS = success(UPDATE); +const REMOVE_SUCCESS = success(REMOVE); + +const range = getDateRangeFromValue(LAST_7_DAYS); +const defaultDateFilters = { + events: [], + rangeValue: LAST_7_DAYS, + startDate: range.start.unix() * 1000, + endDate: range.end.unix() * 1000 +} + +const initialState = Map({ + list: List(), + instance: Funnel(), + insights: Funnel(), + issues: List(), + issue: FunnelIssue(), + issuesTotal: 0, + sessionsTotal: 0, + sessions: List(), + activeStages: List(), + funnelFilters: defaultDateFilters, + sessionsSort: Map({ order: "desc", sort: "newest" }), + issueFilters: Map({ + filters: List(), + sort: { order: "desc", sort: "lostConversions" } + }), + sessionFilters: defaultDateFilters, + navRef: null, + issueTypes: List(), + blink: true +}); + +const reducer = (state = initialState, action = {}) => { + switch(action.type) { + case BLINK: + return state.set('blink', action.state); + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + case INIT: + return state.set('instance', Funnel(action.instance)) + case FETCH_LIST_SUCCESS: + return state.set('list', List(action.data).map(Funnel)) + case FETCH_ISSUES_SUCCESS: + return state + .set('issues', List(action.data.issues.significant).map(FunnelIssue)) + .set('criticalIssuesCount', action.data.issues.criticalIssuesCount) + case FETCH_SESSIONS_SUCCESS: + return state + .set('sessions', List(action.data.sessions).map(Session)) + .set('total', action.data.total) + case FETCH_ISSUE_SUCCESS: + return state + .set('issue', FunnelIssue(action.data.issue)) + .set('sessions', List(action.data.sessions.sessions).map(Session)) + .set('sessionsTotal', action.data.sessions.total) + case RESET_ISSUE: + return state.set('isses', FunnelIssue()) + .set('sections', List()) + .set('sessionsTotal', 0); + case FETCH_SUCCESS: + const funnel = Funnel(action.data); + return state.set('instance', funnel) + case FETCH_ISSUE_TYPES_SUCCESS: + const tmpMap = {}; + action.data.forEach(element => { + tmpMap[element.type] = element.title + }); + return state + .set('issueTypes', List(action.data.map(({ type, title }) => ({ text: title, value: type })))) + .set('issueTypesMap', tmpMap); + case FETCH_INSIGHTS_SUCCESS: + let stages = []; + if (action.isRefresh) { + const activeStages = state.get('activeStages'); + console.log('test', activeStages); + const oldInsights = state.get('insights'); + const lastStage = action.data.stages[action.data.stages.length - 1] + const lastStageIndex = activeStages.toJS()[1]; + stages = oldInsights.stages.map((stage, i) => { + stage.dropDueToIssues = lastStageIndex === i ? lastStage.dropDueToIssues : 0; + return stage; + }); + return state.set('insights', Funnel({ totalDropDueToIssues: action.data.totalDropDueToIssues, stages, activeStages: activeStages.toJS() })); + } else { + stages = action.data.stages.map((stage, i) => { + stage.dropDueToIssues = 0; + return stage; + }); + return state.set('insights', Funnel({ ...action.data, stages })) + } + case SAVE_SUCCESS: + case UPDATE_SUCCESS: + return state.update('list', itemInListUpdater(CustomField(action.data))) + case REMOVE_SUCCESS: + return state.update('list', list => list.filter(item => item.index !== action.index)); + case INIT: + return state.set('instance', Funnel(action.instance)); + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + case APPLY_FILTER: + return state.mergeIn([ action.filterType ], Array.isArray(action.filter) ? action.filter : Map(action.filter)); + case APPLY_ISSUE_FILTER: + return state.mergeIn(['issueFilters'], action.filter) + case REMOVE_ISSUE_FILTER: + return state.updateIn(['issueFilters', 'filters'], list => list.filter(item => item !== action.errorType)) + case SET_ACTIVE_STAGES: + return state.set('activeStages', List(action.stages)) + case SET_NAV_REF: + return state.set('navRef', action.navRef); + case SET_SESSIONS_SORT: + const comparator = (s1, s2) => { + let diff = s1[ action.sortKey ] - s2[ action.sortKey ]; + diff = diff === 0 ? s1.startedAt - s2.startedAt : diff; + return action.sign * diff; + }; + return state + .update('sessions', list => list.sort(comparator)) + .set('sessionsSort', { sort: action.sort, sign: action.sign }); + case RESET_FUNNEL: + return state + .set('instance', Funnel()) + .set('activeStages', List()) + .set('issuesSort', Map({})) + .set('funnelFilters', defaultDateFilters) + .set('insights', Funnel()) + .set('issues', List()) + .set('sessions', List()); + default: + return state; + } +} + +export const fetchList = (range) => { + return { + types: array(FETCH_LIST), + call: client => client.get(`/funnels`), + } +} + +export const fetch = (funnelId, params) => (dispatch, getState) => { + return dispatch({ + types: array(FETCH), + call: client => client.get(`/funnels/${funnelId}`, params) + }); +} + +const eventMap = ({value, type, key, operator, source, custom}) => ({value, type, key, operator, source, custom}); +const filterMap = ({value, type, key, operator, source, custom }) => ({value: Array.isArray(value) ? value: [value], custom, type, key, operator, source}); + +function getParams(params, state) { + const appliedFilters = state.getIn([ 'funnelFilters', 'appliedFilter' ]); + const filter = appliedFilters + .update('events', list => list.map(event => event.set('value', event.value || '*')).map(eventMap)) + .toJS(); + + filter.filters = state.getIn([ 'funnelFilters', 'appliedFilter', 'filters' ]) + .map(filterMap).toJS(); + + return {...filter, ...params }; +} + +export const fetchInsights = (funnelId, params = {}, isRefresh = false) => (dispatch, getState) => { + return dispatch({ + types: array(FETCH_INSIGHTS), + call: client => client.post(`/funnels/${funnelId}/insights`, getParams(params, getState())), + isRefresh + }) +} + + +export const fetchFiltered = (funnelId, params) => (dispatch, getState) => { + return dispatch({ + types: array(FETCH), + call: client => client.post(`/funnels/${funnelId}`, params), + }) +} + +export const fetchIssuesFiltered = (funnelId, params) => (dispatch, getState) => { + return dispatch({ + types: array(FETCH_ISSUES), + call: client => client.post(`/funnels/${funnelId}/issues`, getParams(params, getState())), + }) +} + +export const fetchSessionsFiltered = (funnelId, params) => (dispatch, getState) => { + return dispatch({ + types: array(FETCH_SESSIONS), + call: client => client.post(`/funnels/${funnelId}/sessions`, getParams(params, getState())), + }) +} + +export const fetchIssue = (funnelId, issueId, params) => (dispatch, getState) => { + const filters = getState().getIn([ 'funnelFilters', 'appliedFilter' ]); + const _params = { ...filters.toData(), ...params }; + return dispatch({ + types: array(FETCH_ISSUE), + call: client => client.post(`/funnels/${funnelId}/issues/${issueId}/sessions`, _params), + }) +} + +export const fetchIssues = (funnelId, params) => { + return { + types: array(FETCH_ISSUES), + call: client => client.get(`/funnels/${funnelId}/issues`, params), + } +} + +export const fetchSessions = (funnelId, params) => { + return { + types: array(FETCH_SESSIONS), + call: client => client.get(`/funnels/${funnelId}/sessions`, params), + } +} + +export const fetchIssueTypes = () => { + return { + types: array(FETCH_ISSUE_TYPES), + call: client => client.get(`/funnels/issue_types`), + } +} + +export const save = (instance) => { + const url = instance.exists() + ? `/funnels/${ instance[idKey] }` + : `/funnels`; + + return { + types: array(instance.exists() ? SAVE : UPDATE), + call: client => client.post(url, instance.toData()), + } +} + +export const updateFunnelFilters = (funnelId, filter) => { + return { + types: array(UPDATE), + call: client => client.post(`/funnels/${funnelId}`, { filter }), + } +} + +export const remove = (index) => { + return { + types: array(REMOVE), + call: client => client.delete(`/funnels/${index}`), + index, + } +} + +export const applyFilter = (filterType='funnelFilters', filter) => { + return { + type: APPLY_FILTER, + filter, + filterType, + } +}; + +export const applyIssueFilter = (filter) => { + return { + type: APPLY_ISSUE_FILTER, + filter + } +}; + +export const removeIssueFilter = errorType => { + return { + type: REMOVE_ISSUE_FILTER, + errorType, + } +}; + +export const setActiveStages = (stages, filters, funnelId, forceRrefresh = false) => (dispatch, getState) => { + dispatch({ + type: SET_ACTIVE_STAGES, + stages, + }) + + if (stages.length === 2) { + const filter = {...filters.toData(), firstStage: stages[0] + 1, lastStage: stages[1] + 1 }; + dispatch(fetchIssuesFiltered(funnelId, filter)) + dispatch(fetchInsights(funnelId, filter, true)); + dispatch(fetchSessionsFiltered(funnelId, filter)); + } else if (forceRrefresh) { + const filter = {...filters.toData()}; + dispatch(fetchIssuesFiltered(funnelId, filter)) + dispatch(fetchInsights(funnelId, filter)); + dispatch(fetchSessionsFiltered(funnelId, filter)); + } +}; + +export const edit = instance => { + return { + type: EDIT, + instance, + } +}; + +export const init = instance => { + return { + type: INIT, + instance, + } +}; + +export const setNavRef = ref => { + return { + type: SET_NAV_REF, + navRef: ref + } +}; + +export const resetIssue = () => { + return { + type: RESET_ISSUE, + } +} + +export const resetFunnel = () => { + return { + type: RESET_FUNNEL, + } +} + +export const setSessionsSort = (sortKey, sign = 1) => { + return { + type: SET_SESSIONS_SORT, + sortKey, + sign + } +} + +export const blink = (state = true) => { + return { + type: BLINK, + state + } +} + +export const refresh = (funnelId) => (dispatch, getState) => { + dispatch(fetch(funnelId)) + dispatch(fetchInsights(funnelId)) + dispatch(fetchIssuesFiltered(funnelId, {})) + dispatch(fetchSessionsFiltered(funnelId, {})) +} + +export default mergeReducers( + reducer, + createRequestReducer({ + fetchRequest: FETCH, + fetchListRequest: FETCH_LIST, + fetchInsights: FETCH_INSIGHTS, + fetchIssueRequest: FETCH_ISSUE, + saveRequest: SAVE, + updateRequest: UPDATE, + fetchIssuesRequest: FETCH_ISSUES, + fetchSessionsRequest: FETCH_SESSIONS, + }), +) \ No newline at end of file diff --git a/frontend/app/duck/index.js b/frontend/app/duck/index.js new file mode 100644 index 000000000..53771ca04 --- /dev/null +++ b/frontend/app/duck/index.js @@ -0,0 +1,71 @@ +import { combineReducers } from 'redux-immutable'; + +import jwt from './jwt'; +import user from './user'; +import sessions from './sessions'; +import issues from './issues'; +import assignments from './assignments'; +import target from './target'; +import targetCustom from './targetCustom'; +import runs from './runs'; +import filters from './filters'; +import funnelFilters from './funnelFilters'; +import tests from './tests'; +import steps from './steps'; +import schedules from './schedules'; +import events from './events'; +import environments from './environments'; +import variables from './variables'; +import templates from './templates'; +import alerts from './alerts'; +import notifications from './notifications'; +import dashboard from './dashboard'; +import components from './components'; +import sources from './sources'; +import members from './member'; +import site from './site'; +import customFields from './customField'; +import webhooks from './webhook'; +import integrations from './integrations'; +import watchdogs from './watchdogs'; +import rehydrate from './rehydrate'; +import announcements from './announcements'; +import errors from './errors'; +import funnels from './funnels'; +import config from './config'; + +export default combineReducers({ + jwt, + user, + sessions, + issues, + assignments, + target, + targetCustom, + runs, + filters, + funnelFilters, + tests, + steps, + schedules, + events, + environments, + variables, + templates, + alerts, + notifications, + dashboard, + components, + members, + site, + customFields, + webhooks, + watchdogs, + rehydrate, + announcements, + errors, + funnels, + config, + ...integrations, + ...sources, +}); diff --git a/frontend/app/duck/integrations/actions.js b/frontend/app/duck/integrations/actions.js new file mode 100644 index 000000000..4bffda55c --- /dev/null +++ b/frontend/app/duck/integrations/actions.js @@ -0,0 +1,39 @@ +import { array } from '../funcTools/tools'; +import { fetchListType, saveType, editType, initType, removeType } from '../funcTools/types'; + +export function fetchList(name) { + return { + types: fetchListType(name).array, + call: client => client.get(`/integrations/${ name }`), + name + }; +} + +export function save(name, siteId, instance) { + return { + types: saveType(name).array, + call: client => client.post( (siteId ? `/${siteId}` : '') + `/integrations/${ name }`, instance.toData()), + }; +} + +export function edit(name, instance) { + return { + type: editType(name), + instance, + }; +} + +export function init(name, instance) { + return { + type: initType(name), + instance, + }; +} + +export function remove(name, siteId) { + return { + types: removeType(name).array, + call: client => client.delete((siteId ? `/${siteId}` : '') + `/integrations/${ name }`), + siteId, + }; +} \ No newline at end of file diff --git a/frontend/app/duck/integrations/index.js b/frontend/app/duck/integrations/index.js new file mode 100644 index 000000000..5e439675d --- /dev/null +++ b/frontend/app/duck/integrations/index.js @@ -0,0 +1,33 @@ +import SentryConfig from 'Types/integrations/sentryConfig'; +import DatadogConfig from 'Types/integrations/datadogConfig'; +import StackdriverConfig from 'Types/integrations/stackdriverConfig'; +import RollbarConfig from 'Types/integrations/rollbarConfig'; +import NewrelicConfig from 'Types/integrations/newrelicConfig'; +import BugsnagConfig from 'Types/integrations/bugsnagConfig'; +import CloudWatch from 'Types/integrations/cloudwatchConfig'; +import ElasticsearchConfig from 'Types/integrations/elasticsearchConfig'; +import SumoLogicConfig from 'Types/integrations/sumoLogicConfig'; +import JiraConfig from 'Types/integrations/jiraConfig'; +import GithubConfig from 'Types/integrations/githubConfig'; +import IssueTracker from 'Types/integrations/issueTracker'; +import slack from './slack'; + +import { createIntegrationReducer } from './reducer' + +export default { + sentry: createIntegrationReducer("sentry", SentryConfig), + datadog: createIntegrationReducer("datadog", DatadogConfig), + stackdriver: createIntegrationReducer("stackdriver", StackdriverConfig), + rollbar: createIntegrationReducer("rollbar", RollbarConfig), + newrelic: createIntegrationReducer("newrelic", NewrelicConfig), + bugsnag: createIntegrationReducer("bugsnag", BugsnagConfig), + cloudwatch: createIntegrationReducer("cloudwatch", CloudWatch), + elasticsearch: createIntegrationReducer("elasticsearch", ElasticsearchConfig), + sumologic: createIntegrationReducer("sumologic", SumoLogicConfig), + jira: createIntegrationReducer("jira", JiraConfig), + issues: createIntegrationReducer("issues", IssueTracker), + github: createIntegrationReducer("github", GithubConfig), + slack, +}; + +export * from './actions'; diff --git a/frontend/app/duck/integrations/reducer.js b/frontend/app/duck/integrations/reducer.js new file mode 100644 index 000000000..166bb661e --- /dev/null +++ b/frontend/app/duck/integrations/reducer.js @@ -0,0 +1,48 @@ +import { List, Map } from 'immutable'; +import { createRequestReducer } from '../funcTools/request'; +import { fetchListType, saveType, removeType, editType, initType } from '../funcTools/types'; +import { createItemInListUpdater } from '../funcTools/tools'; + +const idKey = 'siteId'; +const itemInListUpdater = createItemInListUpdater(idKey); + +export const createIntegrationReducer = (name, Config) => { + const FETCH_LIST = fetchListType(name); + const SAVE = saveType(name); + const REMOVE = removeType(name); + const EDIT = editType(name); + const INIT = initType(name); + + const initialState = Map({ + instance: Config(), + list: List(), + fetched: false, + issuesFetched: false + }); + const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case FETCH_LIST.success: + return state.set('list', Array.isArray(action.data) ? + List(action.data).map(Config) : List([new Config(action.data)])).set(action.name + 'Fetched', true); + case SAVE.success: + const config = Config(action.data); + return state + .update('list', itemInListUpdater(config)) + .set('instance', config); + case REMOVE.success: + return state + .update('list', list => list.filter(site => site.siteId !== action.siteId)) + .set('instance', Config()) + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + case INIT: + return state.set('instance', Config(action.instance)); + } + return state; + }; + return createRequestReducer({ + fetchRequest: FETCH_LIST, + saveRequest: SAVE, + removeRequest: REMOVE, + }, reducer); +} diff --git a/frontend/app/duck/integrations/slack.js b/frontend/app/duck/integrations/slack.js new file mode 100644 index 000000000..1d59bc16b --- /dev/null +++ b/frontend/app/duck/integrations/slack.js @@ -0,0 +1,80 @@ +import { Map, List } from 'immutable'; +import withRequestState, { RequestTypes } from 'Duck/requestStateCreator'; +import Config from 'Types/integrations/slackConfig'; +import { createItemInListUpdater } from '../funcTools/tools'; + +const SAVE = new RequestTypes('slack/SAVE'); +const REMOVE = new RequestTypes('slack/REMOVE'); +const FETCH_LIST = new RequestTypes('slack/FETCH_LIST'); +const EDIT = 'slack/EDIT'; +const INIT = 'slack/INIT'; +const idKey = 'webhookId'; +const itemInListUpdater = createItemInListUpdater(idKey); + +const initialState = Map({ + instance: Config(), + list: List(), +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case FETCH_LIST.SUCCESS: + return state.set('list', List(action.data).map(Config)); + case SAVE.SUCCESS: + const config = Config(action.data); + return state + .update('list', itemInListUpdater(config)) + .set('instance', config); + case REMOVE.SUCCESS: + return state + .update('list', list => list.filter(item => item.webhookId !== action.id)) + .set('instance', Config()) + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + case INIT: + return state.set('instance', Config(action.instance)); + } + return state; +}; + +export default withRequestState({ + fetchRequest: FETCH_LIST, + saveRequest: SAVE, + removeRequest: REMOVE, +}, reducer); + +export function fetchList() { + return { + types: FETCH_LIST.toArray(), + call: client => client.get('/integrations/slack/channels'), + }; +} + +export function save(instance) { + return { + types: SAVE.toArray(), + call: client => client.post(`/integrations/slack`, instance.toData()), + }; +} + +export function edit(instance) { + return { + type: EDIT, + instance, + }; +} + +export function init(instance) { + return { + type: INIT, + instance, + }; +} + +export function remove(id) { + return { + types: REMOVE.toArray(), + call: client => client.delete(`/integrations/slack/${id}`), + id, + }; +} \ No newline at end of file diff --git a/frontend/app/duck/issues.js b/frontend/app/duck/issues.js new file mode 100644 index 000000000..fcd6d9584 --- /dev/null +++ b/frontend/app/duck/issues.js @@ -0,0 +1,130 @@ +import Assignment from 'Types/session/assignment'; +import Activity from 'Types/session/activity'; +import { List, Map, Set } from 'immutable'; +import withRequestState, { RequestTypes } from 'Duck/requestStateCreator'; +import { createListUpdater, createItemInListUpdater } from './funcTools/tools'; +import { editType, initType } from './funcTools/crud/types'; +import { createInit, createEdit } from './funcTools/crud'; + +const idKey = 'id'; +const name = 'assignment'; +const listUpdater = createListUpdater(idKey); +const itemInListUpdater = createItemInListUpdater(idKey); + +const FETCH_ASSIGNMENTS = new RequestTypes('asignment/FETCH_ASSIGNMENTS'); +const FETCH_ISSUE = new RequestTypes('asignment/FETCH_ISSUE'); +const FETCH_PROJECTS = new RequestTypes('asignment/FETCH_PROJECTS'); +const FETCH_META = new RequestTypes('asignment/FETCH_META'); +const ADD_ACTIVITY = new RequestTypes('asignment/ADD_ACTIVITY'); +const ADD_MESSAGE = new RequestTypes('asignment/ADD_MESSAGE'); +const EDIT = editType(name); +const INIT = initType(name); +const RESET_ACTIVE_ISSUE = 'assignment/RESET_ACTIVE_ISSUE'; + +const initialState = Map({ + list: List(), + instance: Assignment(), + activeIssue: Assignment(), + issueTypes: List(), + issueTypeIcons: Set(), + users: List(), + projects: List() +}); + +let issueTypes = []; + +const reducer = (state = initialState, action = {}) => { + const users = state.get('users'); + switch (action.type) { + case FETCH_PROJECTS.SUCCESS: + return state.set('projects', List(action.data)); + case FETCH_ASSIGNMENTS.SUCCESS: + return state.set('list', List(action.data).map(Assignment)); + case ADD_ACTIVITY.SUCCESS: + const instance = Assignment(action.data); + return listUpdater(state, instance); + case FETCH_META.SUCCESS: + issueTypes = action.data.issueTypes; + var issueTypeIcons = {} + for (var i =0; i < issueTypes.length; i++) { + issueTypeIcons[issueTypes[i].id] = issueTypes[i].iconUrl + } + return state.set('issueTypes', List(issueTypes)) + .set('users', List(action.data.users)) + .set('issueTypeIcons', issueTypeIcons) + case FETCH_ISSUE.SUCCESS: + return state.set('activeIssue', Assignment({ ...action.data, users})); + case RESET_ACTIVE_ISSUE: + return state.set('activeIssue', Assignment()); + case ADD_MESSAGE.SUCCESS: + const user = users.filter(user => user.id === action.data.author).first(); + const activity = Activity({ type: 'message', user, ...action.data,}); + return state.updateIn([ 'activeIssue', 'activities' ], list => list.push(activity)); + case INIT: + action.instance.issueType = issueTypes.length > 0 ? issueTypes[0].id : ''; + return state.set('instance', Assignment(action.instance)); + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + default: + return state; + } +}; + +export default withRequestState({ + fetchListRequest: FETCH_ASSIGNMENTS, + addActivityRequest: ADD_ACTIVITY, + fetchIssueRequest: FETCH_ISSUE, + addMessageRequest: ADD_MESSAGE, + fetchProjectsRequest: FETCH_PROJECTS +}, reducer); + +export const init = createInit(name); +export const edit = createEdit(name); + +export function fetchAssignments(sessionId) { + return { + types: FETCH_ASSIGNMENTS.toArray(), + call: client => client.get(`/sessions2/${ sessionId }/assign`) + } +} + +export function resetActiveIsue() { + return { + type: RESET_ACTIVE_ISSUE + } +} + +export function fetchProjects() { + return { + types: FETCH_PROJECTS.toArray(), + call: client => client.get(`/integrations/issues/list_projects`) + } +} + +export function fetchIssue(sessionId, id) { + return { + types: FETCH_ISSUE.toArray(), + call: client => client.get(`/sessions2/${ sessionId }/assign/jira/${ id }`) + } +} + +export function fetchMeta(projectId) { + return { + types: FETCH_META.toArray(), + call: client => client.get(`/integrations/issues/${projectId}`) + } +} + +export function addActivity(sessionId, params) { + return { + types: ADD_ACTIVITY.toArray(), + call: client => client.post(`/sessions2/${ sessionId }/assign`, params.toCreate()), + } +} + +export function addMessage(sessionId, assignmentId, params) { + return { + types: ADD_MESSAGE.toArray(), + call: client => client.post(`/sessions2/${ sessionId }/assign/${ assignmentId }/comment`, params), + } +} \ No newline at end of file diff --git a/frontend/app/duck/jwt.js b/frontend/app/duck/jwt.js new file mode 100644 index 000000000..946dcaa6a --- /dev/null +++ b/frontend/app/duck/jwt.js @@ -0,0 +1,12 @@ +export const UPDATE = 'jwt/UPDATE'; +export const DELETE = 'jwt/DELETE'; + +export default (state = null, action = {}) => { + switch (action.type) { + case UPDATE: + return action.data; + case DELETE: + return null; + } + return state; +}; diff --git a/frontend/app/duck/member.js b/frontend/app/duck/member.js new file mode 100644 index 000000000..94e2f4e2f --- /dev/null +++ b/frontend/app/duck/member.js @@ -0,0 +1,16 @@ +import Member from 'Types/member'; +import crudDuckGenerator from './tools/crudDuck'; + +const crudDuck = crudDuckGenerator('client/member', Member, { idKey: 'id' }); +export const { + fetchList, init, edit, remove, +} = crudDuck.actions; + +export function save(instance) { + return { + types: crudDuck.actionTypes.SAVE.toArray(), + call: client => client.put( instance.id ? `/client/members/${ instance.id }` : '/client/members', instance.toData()), + }; +} + +export default crudDuck.reducer; diff --git a/frontend/app/duck/notifications.js b/frontend/app/duck/notifications.js new file mode 100644 index 000000000..129349792 --- /dev/null +++ b/frontend/app/duck/notifications.js @@ -0,0 +1,63 @@ +import { List, Map } from 'immutable'; +import Notification from 'Types/notification'; +import { mergeReducers, success, array, request, createListUpdater } from './funcTools/tools'; +import { createRequestReducer } from './funcTools/request'; +import { + createCRUDReducer, + getCRUDRequestTypes, + createFetchList, +} from './funcTools/crud'; + +const name = 'notification'; +const idKey = 'notificationId'; +const SET_VIEWED = 'notifications/SET_VIEWED'; +const CLEAR_ALL = 'notifications/CLEAR_ALL'; +const SET_VIEWED_SUCCESS = success(SET_VIEWED); +const CLEAR_ALL_SUCCESS = success(CLEAR_ALL); + +const listUpdater = createListUpdater(idKey); + +const initialState = Map({ + list: List(), +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case SET_VIEWED_SUCCESS: + if (!action.data) return state; + const item = state.get('list').find(item => item[ idKey ] === action.id) + return listUpdater(state, Notification({...item.toJS(), createdAt: item.createdAt.ts, viewed: true })); + case CLEAR_ALL_SUCCESS: + if (!action.data) return state; + return state.update('list', list => list.map(l => Notification({...l.toJS(), createdAt: l.createdAt.ts, viewed: true }))) + } + return state; +}; + +export const fetchList = createFetchList(name); + +export default mergeReducers( + reducer, + createCRUDReducer(name, Notification, idKey), + createRequestReducer({ + setViewed: SET_VIEWED, + clearAll: CLEAR_ALL, + ...getCRUDRequestTypes(name), + }), +); + +export function setViewed(id) { + return { + types: array(SET_VIEWED), + call: client => client.get(`/notifications/${ id }/view`), + id, + }; +} + +export function clearAll(params) { + return { + types: array(CLEAR_ALL), + call: client => client.post('/notifications/view', params), + }; +} + diff --git a/frontend/app/duck/rehydrate.js b/frontend/app/duck/rehydrate.js new file mode 100644 index 000000000..4dd424ba4 --- /dev/null +++ b/frontend/app/duck/rehydrate.js @@ -0,0 +1,54 @@ +import { List, Map } from 'immutable'; +import RehydrateJob from 'Types/rehydrateJob'; + +import { mergeReducers, success, array } from './funcTools/tools'; +import { createRequestReducer } from './funcTools/request'; +import { + createCRUDReducer, + getCRUDRequestTypes, + createFetchList, + createInit, + createEdit, + createRemove, + createSave, +} from './funcTools/crud'; + +const name = 'rehydration'; +const idKey = 'rehydrationId'; + + +const SET_ACTIVE_TAB = 'steps/SET_ACTIVE_TAB'; + +const initialState = Map({ + activeJob: Map(), + list: List() +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case SET_ACTIVE_TAB: + return state.set('activeJob', RehydrateJob(action.instance)); + } + return state; +}; + +export function setActiveTab(instance) { + return { + type: SET_ACTIVE_TAB, + instance, + }; +} + +export const fetchList = createFetchList(name); +export const init = createInit(name); +export const edit = createEdit(name); +export const save = createSave(name); +export const remove = createRemove(name); + +export default mergeReducers( + reducer, + createCRUDReducer(name, RehydrateJob, idKey), + createRequestReducer({ + ...getCRUDRequestTypes(name), + }), +); \ No newline at end of file diff --git a/frontend/app/duck/requestStateCreator.js b/frontend/app/duck/requestStateCreator.js new file mode 100644 index 000000000..fdac31e43 --- /dev/null +++ b/frontend/app/duck/requestStateCreator.js @@ -0,0 +1,80 @@ +import { List, Map } from 'immutable'; + +export class RequestTypes { + constructor(type) { + this.REQUEST = `${ type }_REQUEST`; + this.SUCCESS = `${ type }_SUCCESS`; + this.FAILURE = `${ type }_FAILURE`; + } + toArray() { + return [ this.REQUEST, this.SUCCESS, this.FAILURE ]; + } +} + +const defaultReducer = (state = Map()) => state; +const initialState = Map({ + loading: false, + errors: null, +}); + +const addRequestState = ( + types, + reducer = defaultReducer, +) => { + const typesArray = Array.isArray(types) ? types : [ types ]; + const requestEvents = typesArray.map(a => a.REQUEST); + const successEvents = typesArray.map(a => a.SUCCESS); + const failureEvents = typesArray.map(a => a.FAILURE); + + let loadingCounter = 0; + + return (inputState, action = {}) => { + let state = reducer(inputState, action); + // initialization + state = inputState ? state : state.merge(initialState); + + if (requestEvents.includes(action.type)) { + loadingCounter += 1; + return state.set('loading', loadingCounter > 0).set('errors', null); + } + if (successEvents.includes(action.type)) { + loadingCounter -= 1; + return state.set('loading', loadingCounter > 0).set('errors', null); + } + if (failureEvents.includes(action.type)) { + loadingCounter -= 1; + return state.set('loading', loadingCounter > 0).set('errors', List(action.errors)); + } + return state; + }; +}; + +// TODO: Errors + +/** + * @types: RequestTypes - array or single + * or object like {'state1': RequestTypes, 'state2': [RequestTypes] ... } + * @reducer: wrapped reducer + * */ +export default ( + types, + reducer = defaultReducer, +) => { + if (types instanceof RequestTypes || types instanceof Array) { + return addRequestState(types, reducer); + } + + const keys = Object.keys(types).filter(key => key !== '_'); + const reducers = {}; + keys.map((key) => { reducers[ key ] = addRequestState(types[ key ]); }); + + const actualReducer = types._ ? addRequestState(types._, reducer) : reducer; + + return (inputState, action = {}) => { + let state = actualReducer(inputState, action); + keys.map((key) => { + state = state.update(key, subState => reducers[ key ](subState, action)); + }); + return state; + }; +}; diff --git a/frontend/app/duck/runs.js b/frontend/app/duck/runs.js new file mode 100644 index 000000000..30b8051ac --- /dev/null +++ b/frontend/app/duck/runs.js @@ -0,0 +1,7 @@ +import Run from 'Types/run'; +import crudDuckGenerator from './tools/crudDuck'; + +const crudDuck = crudDuckGenerator('run', Run); +export const { fetchList, fetch, init, edit, save, remove } = crudDuck.actions; + +export default crudDuck.reducer; diff --git a/frontend/app/duck/schedules.js b/frontend/app/duck/schedules.js new file mode 100644 index 000000000..3f13e9188 --- /dev/null +++ b/frontend/app/duck/schedules.js @@ -0,0 +1,14 @@ +import Schedule from 'Types/schedule'; +import crudDuckGenerator from './tools/crudDuck'; + +const crudDuck = crudDuckGenerator('scheduler', Schedule); +export const { fetchList, fetch, init, edit, remove } = crudDuck.actions; + +export function save(instance) { // TODO: fix the crudDuckGenerator + return { + types: crudDuck.actionTypes.SAVE.toArray(), + call: client => client.post(`/schedulers${!!instance.schedulerId ? '/' + instance.schedulerId : '' }`, instance), + }; +} + +export default crudDuck.reducer; diff --git a/frontend/app/duck/sessions.js b/frontend/app/duck/sessions.js new file mode 100644 index 000000000..34340e282 --- /dev/null +++ b/frontend/app/duck/sessions.js @@ -0,0 +1,271 @@ +import { List, Map } from 'immutable'; +import Session from 'Types/session'; +import ErrorStack from 'Types/session/errorStack'; +import Watchdog, { getSessionWatchdogTypes } from 'Types/watchdog'; +import { clean as cleanParams } from 'App/api_client'; +import withRequestState, { RequestTypes } from './requestStateCreator'; +import { getRE } from 'App/utils'; + + +const INIT = 'sessions/INIT'; + +const FETCH_LIST = new RequestTypes('sessions/FETCH_LIST'); +const FETCH = new RequestTypes('sessions/FETCH'); +const FETCH_FAVORITE_LIST = new RequestTypes('sessions/FETCH_FAVORITE_LIST'); +const TOGGLE_FAVORITE = new RequestTypes('sessions/TOGGLE_FAVORITE'); +const FETCH_ERROR_STACK = new RequestTypes('sessions/FETCH_ERROR_STACK'); +const SORT = 'sessions/SORT'; +const REDEFINE_TARGET = 'sessions/REDEFINE_TARGET'; +const SET_TIMEZONE = 'sessions/SET_TIMEZONE'; +const SET_EVENT_QUERY = 'sessions/SET_EVENT_QUERY'; + +const SET_ACTIVE_TAB = 'sessions/SET_ACTIVE_TAB'; + +const initialState = Map({ + list: List(), + current: Session(), + total: 0, + keyMap: Map(), + wdTypeCount: Map(), + favoriteList: List(), + activeTab: Watchdog({name: 'All', type: 'all' }), + timezone: 'local', + errorStack: List(), + eventsIndex: [], + sourcemapUploaded: true, + filteredEvents: null +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case INIT: + return state.set('current', Session(action.session)); + case FETCH_LIST.REQUEST: + return action.clear + ? state + .set('list', List()) + : state; + case FETCH_ERROR_STACK.SUCCESS: + return state.set('errorStack', List(action.data.trace).map(ErrorStack)).set('sourcemapUploaded', action.data.sourcemapUploaded) + case FETCH_LIST.SUCCESS: + const { sessions, total } = action.data; + const list = List(sessions).map(Session); + + const { params } = action; + const eventProperties = { + eventCount: 0, + eventTypes: [], + dateFilter: params.rangeValue, + filterKeys: Object.keys(params) + .filter(key => ![ 'custom', 'startDate', 'endDate', 'strict', 'key', 'events', 'rangeValue' ].includes(key)), + returnedCount: list.size, + totalSearchCount: total, + }; + if (Array.isArray(params.events)) { + eventProperties.eventCount = params.events.length; + params.events.forEach(({ type }) => { + if (!eventProperties.eventTypes.includes(type)) { + eventProperties.eventTypes.push(type); + } + }) + } + + const keyMap = {} + list.forEach(s => { + s.issueTypes.forEach(k => { + if(keyMap[k]) + keyMap[k] += 1 + else + keyMap[k] = 1; + }) + }) + + const wdTypeCount = {} + try{ + list.forEach(s => { + getSessionWatchdogTypes(s).forEach(wdtp => { + wdTypeCount[wdtp] = wdTypeCount[wdtp] ? wdTypeCount[wdtp] + 1 : 1; + }) + }) + } catch(e) { + + } + + return state + .set('list', list) + .set('total', total) + .set('keyMap', keyMap) + .set('wdTypeCount', wdTypeCount); + case SET_EVENT_QUERY: { + const events = state.get('current').events; + const query = action.filter.query; + // const filter = action.filter.filter; + const searchRe = getRE(query, 'i'); + let filteredEvents = query ? events.filter(e => searchRe.test(e.url) || searchRe.test(e.value) || searchRe.test(e.label)) : null; + + // if (filter) { + // filteredEvents = filteredEvents ? filteredEvents.filter(e => e.type === filter) : events.filter(e => e.type === filter); + // } + return state.set('filteredEvents', filteredEvents) + } + case FETCH.SUCCESS: { + // TODO: more common.. or TEMP + const events = action.filter.events; + // const filters = action.filter.filters; + const current = state.get('list').find(({ sessionId }) => sessionId === action.data.sessionId) || Session(); + const session = Session(action.data); + + const matching = []; + + events.forEach(({ key, operator, value }) => { + session.events.forEach((e, index) => { + if (key === e.type) { + const val = (e.type === 'LOCATION' ? e.url : e.value); + if (operator === 'is' && value === val) { + matching.push(index); + } + if (operator === 'contains' && val.includes(value)) { + matching.push(index); + } + } + }) + }) + return state.set('current', current.merge(session)).set('eventsIndex', matching); + } + case FETCH_FAVORITE_LIST.SUCCESS: + return state + .set('favoriteList', List(action.data).map(Session)); + case TOGGLE_FAVORITE.SUCCESS: { + const id = action.session.sessionId; + const wasInFavorite = state + .get('favoriteList').findIndex(({ sessionId }) => sessionId === id) > -1; + return state + .update('list', list => list + .map(session => (session.sessionId === id + ? session.set('favorite', !wasInFavorite) + : session))) + .update('favoriteList', list => (wasInFavorite + ? list.filter(({ sessionId }) => sessionId !== id) + : list.push(action.session.set('favorite', true)))) + .update('current', session => (session.sessionId === id + ? session.set('favorite', !wasInFavorite) + : session)); + } + case SORT: { + const comparator = (s1, s2) => { + let diff = s1[ action.sortKey ] - s2[ action.sortKey ]; + diff = diff === 0 ? s1.startedAt - s2.startedAt : diff; + return action.sign * diff; + }; + return state + .update('list', list => list.sort(comparator)) + .update('favoriteList', list => list.sort(comparator)); + } + case REDEFINE_TARGET: { + // TODO: update for list + const { + label, + path, + } = action.target; + return state.updateIn([ 'current', 'events' ], list => + list.map(event => (event.target && event.target.path === path + ? event.setIn([ 'target', 'label' ], label) + : event))); + } + case SET_ACTIVE_TAB: + return state.set('activeTab', action.tab); + case SET_TIMEZONE: + return state.set('timezone', action.timezone) + default: + return state; + } +}; + +export default withRequestState({ + _: [ FETCH, FETCH_LIST ], + fetchFavoriteListRequest: FETCH_FAVORITE_LIST, + toggleFavoriteRequest: TOGGLE_FAVORITE, + fetchErrorStackList: FETCH_ERROR_STACK, +}, reducer); + +function init(session) { + return { + type: INIT, + session, + } +} + +export function fetchList(params = {}, clear = false) { + return { + types: FETCH_LIST.toArray(), + call: client => client.post('/sessions/search2', params), + clear, + params: cleanParams(params), + }; +} + +export function fetchErrorStackList(sessionId, errorId) { + return { + types: FETCH_ERROR_STACK.toArray(), + call: client => client.get(`/sessions2/${ sessionId }/errors/${ errorId }/sourcemaps`) + }; +} + +export const fetch = (sessionId) => (dispatch, getState) => { + dispatch({ + types: FETCH.toArray(), + call: client => client.get(`/sessions2/${ sessionId }`), + filter: getState().getIn([ 'filters', 'appliedFilter' ]) + }); +} + +export function toggleFavorite(session) { + return { + types: TOGGLE_FAVORITE.toArray(), + call: client => client.get(`/sessions2/${ session.sessionId }/favorite`), + session, + }; +} + +export function fetchFavoriteList() { + return { + types: FETCH_FAVORITE_LIST.toArray(), + call: client => client.get('/sessions2/favorite'), + }; +} + +export function sort(sortKey, sign = 1, listName = 'list') { + return { + type: SORT, + sortKey, + sign, + listName, + }; +} + +export function redefineTarget(target) { + return { + type: REDEFINE_TARGET, + target, + }; +} + +export const setActiveTab = (tab) => ({ + type: SET_ACTIVE_TAB, + tab +}) + +export function setTimezone(timezone) { + return { + type: SET_TIMEZONE, + timezone, + }; +} + +export function setEventFilter(filter) { + return { + type: SET_EVENT_QUERY, + filter + } +} + diff --git a/frontend/app/duck/site.js b/frontend/app/duck/site.js new file mode 100644 index 000000000..e5783b147 --- /dev/null +++ b/frontend/app/duck/site.js @@ -0,0 +1,90 @@ +import Site from 'Types/site'; +import GDPR from 'Types/site/gdpr'; +import { + mergeReducers, + createItemInListUpdater, + success, + array +} from './funcTools/tools'; +import { + createCRUDReducer, + getCRUDRequestTypes, + createFetchList, + createInit, + createEdit, + createRemove, + createUpdate, + createSave, +} from './funcTools/crud'; +import { createRequestReducer } from './funcTools/request'; +import { Map, List, fromJS } from "immutable"; + +const name = 'project'; +const idKey = 'id'; +const itemInListUpdater = createItemInListUpdater(idKey) + +const EDIT_GDPR = 'sites/EDIT_GDPR'; +const SAVE_GDPR = 'sites/SAVE_GDPR'; +const FETCH_GDPR = 'sites/FETCH_GDPR'; +const FETCH_GDPR_SUCCESS = success(FETCH_GDPR); +const SAVE_GDPR_SUCCESS = success(SAVE_GDPR); + +const initialState = Map({ + list: List(), + instance: fromJS(), + remainingSites: undefined, +}); + +const reducer = (state = initialState, action = {}) => { + switch(action.type) { + case EDIT_GDPR: + return state.mergeIn([ 'instance', 'gdpr' ], action.gdpr); + case FETCH_GDPR_SUCCESS: + return state.mergeIn([ 'instance', 'gdpr' ], action.data); + case SAVE_GDPR_SUCCESS: + const gdpr = GDPR(action.data); + return state.update('list', itemInListUpdater({ + [ idKey ] : state.getIn([ 'instance', idKey ]), + gdpr, + })).setIn([ 'instance', 'gdpr' ], gdpr); + } + return state; +}; + +export function editGDPR(gdpr) { + return { + type: EDIT_GDPR, + gdpr, + }; +} + +export function fetchGDPR(siteId) { + return { + types: array(FETCH_GDPR), + call: client => client.get(`/${ siteId }/gdpr`), + } +} + +export function saveGDPR(siteId, gdpr) { + return { + types: array(SAVE_GDPR), + call: client => client.post(`/${ siteId }/gdpr`, gdpr.toData()), + }; +} + +export const fetchList = createFetchList(name); +export const init = createInit(name); +export const edit = createEdit(name); +export const save = createSave(name); +export const update = createUpdate(name); +export const remove = createRemove(name); + +export default mergeReducers( + reducer, + createCRUDReducer(name, Site, idKey), + createRequestReducer({ + saveGDPR: SAVE_GDPR, + ...getCRUDRequestTypes(name), + }), +); + diff --git a/frontend/app/duck/sources/index.js b/frontend/app/duck/sources/index.js new file mode 100644 index 000000000..66203d13a --- /dev/null +++ b/frontend/app/duck/sources/index.js @@ -0,0 +1,24 @@ +import { fromJS, Map, List } from 'immutable'; +import listSourceCreator, { getAction } from './listSourceCreator'; + + +const filtersFromJS = data => fromJS(data) + .update('USERDEVICE', list => list.filter(value => value !== "")) + .update('FID0', list => list.filter(value => value !== "")) + +export default { + values: listSourceCreator('values', '/events/values', ({ value }) => value), + selectors: listSourceCreator('selectors', '/events/selectors', ({ targetSelector }) => targetSelector), + filterValues: listSourceCreator('filterValues', '/sessions/filters', filtersFromJS, true, Map({ + USEROS: List(), + USERBROWSER: List(), + USERDEVICE: List(), + FID0: List(), + REFERRER: List(), + USERCOUNTRY: List(), + })), +}; + +export function fetch(name, params) { + return getAction(name, params); +} diff --git a/frontend/app/duck/sources/listSourceCreator.js b/frontend/app/duck/sources/listSourceCreator.js new file mode 100644 index 000000000..a82473f20 --- /dev/null +++ b/frontend/app/duck/sources/listSourceCreator.js @@ -0,0 +1,39 @@ +import { List, Map } from 'immutable'; +import withRequestState, { RequestTypes } from 'Duck/requestStateCreator'; + +const actionMap = {}; + +export default ( + name, + endpoint, + fromJS = a => a, + convertFromRoot = false, + customInitialState = Map({ list: List() }), +) => { + const initialState = customInitialState || Map({ + list: List(), + }); + + const FETCH_LIST = new RequestTypes(`${ name }/FETCH_LIST`); + + actionMap[ name ] = params => ({ + types: FETCH_LIST.toArray(), + call: client => client.get(endpoint, params), + }); + + const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case FETCH_LIST.SUCCESS: + return convertFromRoot + ? state.merge(fromJS(action.data)) + : state.set('list', List(action.data).map(fromJS).toSet().toList()); // ?? + } + return state; + }; + + return withRequestState(FETCH_LIST, reducer); +}; + +export function getAction(name, params) { + return actionMap[ name ](params); +} diff --git a/frontend/app/duck/steps.js b/frontend/app/duck/steps.js new file mode 100644 index 000000000..8855792e0 --- /dev/null +++ b/frontend/app/duck/steps.js @@ -0,0 +1,78 @@ +import { List, Map } from 'immutable'; +import { RequestTypes } from 'Duck/requestStateCreator'; +import Step from 'Types/step'; +import Event from 'Types/filter/event'; +import { getRE } from 'App/utils'; +import Test from 'Types/appTest'; +import { countries } from 'App/constants'; +import { KEYS } from 'Types/filter/customFilter'; + +const countryOptions = Object.keys(countries).map(c => ({filterKey: KEYS.USER_COUNTRY, label: KEYS.USER_COUNTRY, type: KEYS.USER_COUNTRY, value: c, actualValue: countries[c], isFilter: true })); + +const INIT = 'steps/INIT'; +const EDIT = 'steps/EDIT'; + +const SET_TEST = 'steps/SET_TEST'; +const FETCH_LIST = new RequestTypes('steps/FETCH_LIST'); + +const initialState = Map({ + list: List(), + test: Test(), + instance: Step(), + editingIndex: null, +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case FETCH_LIST.SUCCESS: { + console.log(action); + return state.set('list', List(action.data).map(i => { + const type = i.type === 'navigate' ? i.type : 'location'; + return {...i, type: type.toUpperCase()} + })) + } + case INIT: + return state + .set('instance', Step(action.instance)) + .set('editingIndex', action.index) + .set('test', Test()); + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + case SET_TEST: + return state.set('test', Test(action.test)); + } + return state; +}; + +export default reducer; + +export function init(instance, index) { + return { + type: INIT, + instance, + index, + }; +} + +export function edit(instance) { + return { + type: EDIT, + instance, + }; +} + +export function setTest(test) { + return { + type: SET_TEST, + test, + }; +} + + +export function fetchList(params) { + return { + types: FETCH_LIST.toArray(), + call: client => client.get('/tests/steps/search', params), + params, + }; +} diff --git a/frontend/app/duck/target.js b/frontend/app/duck/target.js new file mode 100644 index 000000000..b1f0e337b --- /dev/null +++ b/frontend/app/duck/target.js @@ -0,0 +1,33 @@ +import { Map } from 'immutable'; +import Target from 'Types/target'; +import { RequestTypes } from 'Duck/requestStateCreator'; +import crudDuckGenerator from 'Duck/tools/crudDuck'; +import { reduceDucks } from 'Duck/tools'; + +const FETCH_DEFINED = new RequestTypes('targets/FETCH_DEFINED'); + +const initialState = Map({ + definedPercent: 0, +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case FETCH_DEFINED.SUCCESS: + return state.set( + 'definedPercent', + Math.round((action.data.labeled / action.data.total) * 100), + ); + } + return state; +}; + +const crudDuck = crudDuckGenerator('target', Target); +export const { fetchList, init, edit, save, remove } = crudDuck.actions; +export default reduceDucks(crudDuck, { initialState, reducer }).reducer; + +export function fetchDefinedTargetsCount() { + return { + types: FETCH_DEFINED.toArray(), + call: client => client.get('/targets/count'), + }; +} diff --git a/frontend/app/duck/targetCustom.js b/frontend/app/duck/targetCustom.js new file mode 100644 index 000000000..fd63ed657 --- /dev/null +++ b/frontend/app/duck/targetCustom.js @@ -0,0 +1,13 @@ +import { Map } from 'immutable'; +import TargetCustom from 'Types/targetCustom'; +import crudDuckGenerator from 'Duck/tools/crudDuck'; +import { reduceDucks } from 'Duck/tools'; + + +const crudDuck = crudDuckGenerator('customTarget', TargetCustom, { endpoints: { + fetchList: '/targets_temp', + save: '/targets_temp', + remove: '/targets_temp', +}}); +export const { fetchList, init, edit, save, remove } = crudDuck.actions; +export default crudDuck.reducer; diff --git a/frontend/app/duck/templates.js b/frontend/app/duck/templates.js new file mode 100644 index 000000000..b4ad9c9cc --- /dev/null +++ b/frontend/app/duck/templates.js @@ -0,0 +1,13 @@ +import Template from 'Types/template'; +import crudDuckGenerator from './tools/crudDuck'; + +const crudDuck = crudDuckGenerator( + 'template', Template, + { endpoints: { fetchList: '/templates' } }, +); + +export const { + fetchList, fetch, init, edit, save, remove, +} = crudDuck.actions; + +export default crudDuck.reducer; diff --git a/frontend/app/duck/tests/index.js b/frontend/app/duck/tests/index.js new file mode 100644 index 000000000..eda7edc43 --- /dev/null +++ b/frontend/app/duck/tests/index.js @@ -0,0 +1,186 @@ +import { List, Map, Set } from 'immutable'; +import Test from 'Types/appTest'; +import stepFromJS from 'Types/step'; +import crudDuckGenerator from 'Duck/tools/crudDuck'; +import { reduceDucks } from 'Duck/tools'; +import runsDuck from './runs'; +import Run from 'Types/run'; + +const sampleRun = Run({"runId":8,"testId":7,"name":"test import","createdAt":1601481986264,"createdBy":283,"starter":"on-demand","state":"failed","steps":[{"label":"Open URL","order":0,"title":"navigate","status":"passed","startedAt":1601647536513,"finishedAt":1601647546211,"screenshot":"https://parrot-tests.s3.eu-central-1.amazonaws.com/115/7/8/screenshots/1601647546211.jpg","executionTime":9698},{"label":"Open URL","order":1,"title":"Visit OpenReplay","status":"passed","startedAt":1601647548354,"finishedAt":1601647556991,"screenshot":"https://parrot-tests.s3.eu-central-1.amazonaws.com/115/7/8/screenshots/1601647556991.jpg","executionTime":8637},{"info":"Unhandled promise rejection: TimeoutError: waiting for selector \"[name=\"email\"]\" failed: timeout 30000ms exceeded","input":"failed","label":"Send Keys to Element","order":2,"title":"input","status":"failed","startedAt":1601647559091,"finishedAt":1601647589099,"screenshot":"https://parrot-tests.s3.eu-central-1.amazonaws.com/115/7/8/screenshots/1601647589099.jpg","executionTime":30008}],"browser":"chrome","meta":{"startedAt":1601487715818},"location":"FR","startedAt":1601647524205,"finishedAt":1601647591217,"network":[{"url":"http://yahoo.fr/","method":"GET","duration":1760,"requestID":"769C483871CB3D35DF4BB1CD7D3258C4","timestamp":1601647537533,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null,"response":{"data":[{"key":"user_id","index":1},{"key":"virtual_number","index":2}]}},{"url":"http://fr.yahoo.com/","method":"GET","duration":1112,"requestID":"769C483871CB3D35DF4BB1CD7D3258C4","timestamp":1601647539293,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null,"payload":{"data":[{"key":"user_id","index":1},{"key":"virtual_number","index":2}]}},{"url":"https://fr.yahoo.com/","method":"GET","duration":1204,"requestID":"769C483871CB3D35DF4BB1CD7D3258C4","timestamp":1601647540405,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null},{"url":"https://guce.yahoo.com/consent?brandType=eu&gcrumb=bxFB6Ac&lang=fr-FR&done=https%3A%2F%2Ffr.yahoo.com%2F","method":"GET","duration":1173,"requestID":"769C483871CB3D35DF4BB1CD7D3258C4","timestamp":1601647541609,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null},{"url":"https://consent.yahoo.com/v2/collectConsent?sessionId=3_cc-session_fab600d0-8323-4b52-88c1-5698e6288f48","method":"GET","duration":1169,"requestID":"769C483871CB3D35DF4BB1CD7D3258C4","timestamp":1601647542782,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64)AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null},{"url":"https://s.yimg.com/oa/build/css/site-ltr-b1aa14b0.css","method":"GET","duration":1179,"requestID":"56.2","timestamp":1601647543958,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://consent.yahoo.com/","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_p_bestfit_frontpage.png","method":"GET","duration":1189,"requestID":"56.3","timestamp":1601647543959,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://consent.yahoo.com/","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"https://s.yimg.com/oa/build/js/site-ee81be05.js","method":"GET","duration":1194,"requestID":"56.5","timestamp":1601647543961,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://consent.yahoo.com/","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_w_bestfit_frontpage.png","method":"GET","duration":1189,"requestID":"56.4","timestamp":1601647543961,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://consent.yahoo.com/","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"https://s.yimg.com/oa/build/images/fr-FR-home_11f60c18d02223c8.jpeg","method":"GET","duration":1068,"requestID":"56.7","timestamp":1601647545141,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://s.yimg.com/oa/build/css/site-ltr-b1aa14b0.css","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"http://yahoo.fr/","method":"GET","duration":1312,"requestID":"7CA8FE6239B07643872BF48C30D639D3","timestamp":1601647549363,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null},{"url":"http://fr.yahoo.com/","method":"GET","duration":1005,"requestID":"7CA8FE6239B07643872BF48C30D639D3","timestamp":1601647550675,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null},{"url":"https://fr.yahoo.com/","method":"GET","duration":1037,"requestID":"7CA8FE6239B07643872BF48C30D639D3","timestamp":1601647551680,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null},{"url":"https://guce.yahoo.com/consent?brandType=eu&gcrumb=ESjhlqw&lang=fr-FR&done=https%3A%2F%2Ffr.yahoo.com%2F","method":"GET","duration":1045,"requestID":"7CA8FE6239B07643872BF48C30D639D3","timestamp":1601647552717,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null},{"url":"https://consent.yahoo.com/v2/collectConsent?sessionId=3_cc-session_3b367c91-9f88-498b-96a5-728947dda245","method":"GET","duration":1115,"requestID":"7CA8FE6239B07643872BF48C30D639D3","timestamp":1601647553762,"requestHeaders":{"cookie":"key1=myvalue1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36","upgrade-insecure-requests":"1"},"responseHeaders":null},{"url":"https://s.yimg.com/oa/build/css/site-ltr-b1aa14b0.css","method":"GET","duration":1052,"requestID":"56.14","timestamp":1601647554885,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://consent.yahoo.com/","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_p_bestfit_frontpage.png","method":"GET","duration":1060,"requestID":"56.15","timestamp":1601647554886,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://consent.yahoo.com/","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"https://s.yimg.com/oa/build/js/site-ee81be05.js","method":"GET","duration":1065,"requestID":"56.17","timestamp":1601647554886,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://consent.yahoo.com/","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"https://s.yimg.com/rz/p/yahoo_frontpage_en-US_s_f_w_bestfit_frontpage.png","method":"GET","duration":1063,"requestID":"56.16","timestamp":1601647554886,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://consent.yahoo.com/","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null},{"url":"https://s.yimg.com/oa/build/images/fr-FR-home_11f60c18d02223c8.jpeg","method":"GET","duration":1046,"requestID":"56.19","timestamp":1601647555944,"requestHeaders":{"cookie":"key1=myvalue1","referer":"https://s.yimg.com/oa/build/css/site-ltr-b1aa14b0.css","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.0 Safari/537.36"},"responseHeaders":null}],"environmentId":null,"tenantId":115,"consoleLogs":[{"_type":"warning","_text":"A cookie associated with a resource at http://openreplay.com/ was set with `SameSite=None` but without `Secure`. It has been blocked, as Chrome now only delivers cookies marked `SameSite=None` if they are also marked `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5633521622188032.","_args":[],"_location":{"url":"https://app.openreplay.com/"},"timestamp":1602089840909},{"_type":"warning","_text":"A cookie associated with a resource at http://app.openreplay.com/ was set with `SameSite=None` but without `Secure`. It has been blocked, as Chrome now only delivers cookies marked `SameSite=None` if they are also marked `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5633521622188032.","_args":[],"_location":{"url":"https://app.openreplay.com/"},"timestamp":1602089840918}]}); + +const ADD_STEPS = 'tests/ADD_STEPS'; +const MOVE_STEP = 'tests/MOVE_STEP'; +const REMOVE_STEP = 'tests/REMOVE_STEP'; +const COPY_STEP = 'tests/COPY_STEP'; +const EDIT_STEP = 'tests/EDIT_STEP'; +const TOGGLE_STEP = 'tests/TOGGLE_STEP'; +const ADD_TAG = 'tests/ADD_TAG'; +const REMOVE_TAG = 'tests/REMOVE_TAG'; +const TOGGLE_TAG = 'tests/TOGGLE_TAG'; +const SET_MODIFIED = 'tests/SET_MODIFIED'; +const SET_QUERY = 'tests/SET_QUERY'; + +const MOVE_TEST = 'tests/MOVE_TEST'; + +const initialState = Map({ + tags: Set(), + query: '', + modified: false, + sampleRun: sampleRun, +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case SET_MODIFIED: + return state.set('modified', action.state); + case SET_QUERY: + return state.set('query', action.query); + case ADD_STEPS: + // TODO check frameworks + return state + .updateIn([ 'instance', 'steps' ], list => list.concat(action.steps.map(stepFromJS))).set('modified', true); + case MOVE_STEP: { + const { fromI, toI } = action; + return state + .updateIn([ 'instance', 'steps' ], list => + list.remove(fromI).insert(toI, list.get(fromI))).set('modified', true); + } + case REMOVE_STEP: + return state.removeIn([ 'instance', 'steps', action.index ]).set('modified', true); + case COPY_STEP: { + // Use fromJS to make another key. + const copiedStep = stepFromJS(state + .getIn([ 'instance', 'steps', action.index ]) + .set('imported', false)); + return state + .updateIn([ 'instance', 'steps' ], steps => + steps.insert(action.index + 1, copiedStep)).set('modified', true); + } + case EDIT_STEP: + return state.mergeIn([ 'instance', 'steps', action.index ], action.step).set('modified', true); + case TOGGLE_STEP: + return state.updateIn([ 'instance', 'steps', action.index, 'isDisabled' ], isDisabled => !isDisabled).set('modified', true); + case ADD_TAG: + return state.updateIn([ 'instance', 'tags' ], tags => tags.add(action.tag)).set('modified', true); + case REMOVE_TAG: + return state.updateIn([ 'instance', 'tags' ], tags => tags.remove(action.tag)).set('modified', true); + case TOGGLE_TAG: { + const { tag, flag } = action; + const adding = typeof flag === 'boolean' + ? flag + : !state.hasIn([ 'tags', tag ]); + return state.update('tags', tags => (adding + ? tags.add(tag) + : tags.remove(tag))); + } + case MOVE_TEST: { + const { fromI, toI } = action; + return state + .updateIn([ 'list' ], list => + list.remove(fromI).insert(toI, list.get(fromI))); + } + } + return state; +}; + +const crudDuck = crudDuckGenerator('test', Test); +export const { fetchList, fetch, init, edit, save, remove } = crudDuck.actions; +export { runTest, stopRun, checkRun, generateTest, stopAllRuns, resetErrors } from './runs'; +export default reduceDucks(crudDuck, { reducer, initialState }, runsDuck).reducer; + +export function addSteps(stepOrSteps) { + const steps = Array.isArray(stepOrSteps) || List.isList(stepOrSteps) + ? stepOrSteps + : [ stepOrSteps ]; + return { + type: ADD_STEPS, + steps, + }; +} + +export function moveStep(fromI, toI) { + return { + type: MOVE_STEP, + fromI, + toI, + }; +} + +export function removeStep(index) { + return { + type: REMOVE_STEP, + index, + }; +} + +export function copyStep(index) { + return { + type: COPY_STEP, + index, + }; +} + +export function editStep(index, step) { + return { + type: EDIT_STEP, + index, + step, + }; +} + +export function setModified(state) { + return { + type: SET_MODIFIED, + state, + }; +} + +export function toggleStep(index) { + return { + type: TOGGLE_STEP, + index, + }; +} + +export const addTag = (tag) => (dispatch) => { + return new Promise((resolve) => { + dispatch({ + type: ADD_TAG, + tag, + }) + resolve() + }) +} + +export const removeTag = (tag) => (dispatch) => { + return new Promise((resolve) => { + dispatch({ + type: REMOVE_TAG, + tag, + }); + resolve() + }) +} + +export function toggleTag(tag, flag) { + return { + type: TOGGLE_TAG, + tag, + flag, + }; +} + +export function setQuery(query) { + return { + type: SET_QUERY, + query + }; +} + +export function moveTest(fromI, toI) { + return { + type: MOVE_TEST, + fromI, + toI, + }; +} diff --git a/frontend/app/duck/tests/runs.js b/frontend/app/duck/tests/runs.js new file mode 100644 index 000000000..19aed0fd0 --- /dev/null +++ b/frontend/app/duck/tests/runs.js @@ -0,0 +1,118 @@ +import { Map } from 'immutable'; +import Test from 'Types/appTest'; +import Run, { RUNNING, STOPPED } from 'Types/run'; +import requestDuckGenerator, { RequestTypes } from 'Duck/tools/requestDuck'; +import { reduceDucks } from 'Duck/tools'; + +const GEN_TEST = new RequestTypes('tests/GEN_TEST'); +const RUN_TEST = new RequestTypes('tests/RUN_TEST'); +const STOP_RUN = new RequestTypes('tests/STOP_RUN'); +const STOP_ALL_RUNS = new RequestTypes('tests/STOP_ALL_RUNS'); +const CHECK_RUN = new RequestTypes('tests/CHECK_RUN'); +const RESET_ERRORS = 'tests/RESET_ERRORS'; + +const updateRunInTest = run => (test) => { + const runIndex = test.runHistory + .findLastIndex(({ runId }) => run.runId === runId); + return runIndex === -1 + ? test.update('runHistory', list => list.push(run)) + : test.mergeIn([ 'runHistory', runIndex ], run); +}; + +const updateRun = (state, testId, run) => { + const testIndex = state.get('list').findIndex(test => test.testId === testId); + if (testIndex === -1) return state; + const updater = updateRunInTest(run); + return state + .updateIn([ 'list', testIndex ], updater) + .updateIn([ 'instance' ], test => (test.testId === testId + ? updater(test) + : test)); +}; + +const initialState = Map({}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case GEN_TEST.SUCCESS: + return state.set('instance', Test(action.data).set('generated', true)); + case RUN_TEST.SUCCESS: { + const test = state.get('list').find(({ testId }) => testId === action.testId); + const run = Run({ + runId: action.data.id, state: RUNNING, testId: action.testId, name: test.name + }); + return updateRun(state, action.testId, run); + } + case STOP_RUN.SUCCESS: { + const { testId, runId } = action; + return updateRun(state, testId, { runId, state: STOPPED }); + } + case STOP_ALL_RUNS.SUCCESS: + return state.update('list', list => list.map(test => { + test.runHistory.map(run => run.state === RUNNING ? run.set('state', STOPPED) : run.state); + return test; + })).setIn(['runRequest', 'errors'], null); + case CHECK_RUN.SUCCESS: + return updateRun(state, action.testId, Run(action.data)); + case RESET_ERRORS: + return state.setIn(['runRequest', 'errors'], null); + } + return state; +}; + +const requestDuck = requestDuckGenerator({ + runRequest: RUN_TEST, + stopRunRequest: STOP_RUN, + stopAllRunsRequest: STOP_ALL_RUNS, + genTestRequest: GEN_TEST, +}); + +export default reduceDucks({ reducer, initialState }, requestDuck); + + +export function generateTest(sessionId, params) { + return { + types: GEN_TEST.toArray(), + call: client => client.post(`/sessions2/${ sessionId }/gentest`, params), + }; +} + + +export function runTest(testId, params) { + return { + testId, + types: RUN_TEST.toArray(), + call: client => client.post(`/tests/${ testId }/execute`, params), + }; +} + +export function stopRun(testId, runId) { + return { + runId, + testId, + types: STOP_RUN.toArray(), + call: client => client.get(`/runs/${ runId }/stop`), + }; +} + +export function stopAllRuns() { + return { + types: STOP_ALL_RUNS.toArray(), + call: client => client.get(`/runs/all/stop`), + }; +} + +export function resetErrors() { + return { + type: RESET_ERRORS, + } +} + +export function checkRun(testId, runId) { + return { + runId, + testId, + types: CHECK_RUN.toArray(), + call: client => client.get(`/runs/${ runId }`), + }; +} diff --git a/frontend/app/duck/tools/crudDuck.js b/frontend/app/duck/tools/crudDuck.js new file mode 100644 index 000000000..d095c12da --- /dev/null +++ b/frontend/app/duck/tools/crudDuck.js @@ -0,0 +1,208 @@ +import { Map, List } from 'immutable'; + +import requestDuckGenerator, { RequestTypes } from './requestDuck'; + +function getActionTypes(name) { + return { + FETCH_LIST: new RequestTypes(`${ name }/FETCH_LIST`), + FETCH: new RequestTypes(`${ name }/FETCH`), + FETCH_IN_LIST: new RequestTypes(`${ name }/FETCH_IN_LIST`), + REMOVE: new RequestTypes(`${ name }/REMOVE`), + SAVE: new RequestTypes(`${ name }/SAVE`), + INIT: `${ name }/INIT`, + EDIT: `${ name }/EDIT`, + }; +} + +function getListUpdater(idKey) { + return (state, instance) => state.update('list', (list) => { + const index = list.findIndex(item => item[ idKey ] === instance[ idKey ]); + return (index >= 0 + ? list.mergeIn([ index ], instance) + : list.push(instance) + ); + }); +} + +function getInitialState(fromJS) { + return Map({ + list: List(), + instance: fromJS(), + }); +} + +function getDefaultEndpoints(namePl) { + return { + fetch: { + method: 'GET', + endpoint: id => `/${ namePl }/${ id }`, + }, + fetchList: { + method: 'GET', + endpoint: `/${ namePl }`, + }, + save: { + method: 'PUT', + endpoint: `/${ namePl }`, + }, + remove: { + method: 'DELETE', + endpoint: id => `/${ namePl }/${ id }`, + }, + }; +} + +const defaultReducer = (state = Map()) => state; + +export default function generate( + name, + fromJS = r => r, + options = {}, +) { + const { + endpoints = {}, + customReducer = defaultReducer, + idKey = `${ name }Id`, + } = options; + const namePl = `${ name }s`; + + const defaultEndpoints = getDefaultEndpoints(namePl); + + function getCallFn(key, arg2) { + let method; + let endpoint; + const e = !!endpoints && endpoints[ key ]; + const eType = typeof e; + if (eType === 'string' || eType === 'function') { + ({ method } = defaultEndpoints[ key ]); + endpoint = e; + } else if (eType === 'object' && e !== null) { // TODO: more general + ({ method, endpoint } = e); + } else { + ({ method, endpoint } = defaultEndpoints[ key ]); + } + + const methodName = method.toLowerCase(); + const endpointString = typeof endpoint === 'function' + ? endpoint(arg2) + : endpoint; + const params = typeof arg2 === 'object' && arg2; + return client => client[ methodName ](endpointString, params); + } + /* ======================================= */ + + /* Action types */ + const actionTypes = getActionTypes(name); + const { + FETCH_LIST, + FETCH, + FETCH_IN_LIST, + REMOVE, + SAVE, + INIT, + EDIT, + } = actionTypes; + /* ============ */ + + const updateList = getListUpdater(idKey); + const initialState = getInitialState(fromJS); + + const reducer = (argState, action = {}) => { + let state = customReducer(argState, action); + // initialization + state = argState ? state : state.merge(initialState); + + switch (action.type) { + case FETCH_LIST.SUCCESS: + // TODO: use OreredMap by id & merge; + return state.set('list', List(action.data).map(fromJS)); + case FETCH_IN_LIST.SUCCESS: + return updateList(state, fromJS(action.data)); + case INIT: + return state.set('instance', fromJS(action.instance)); + case SAVE.SUCCESS: + const instance = fromJS(action.data); + return updateList(state, instance).set('instance', instance); + case FETCH.SUCCESS: { + const instance = fromJS(action.data); + return updateList(state, instance).set('instance', instance); + } + case EDIT: + return state.mergeIn([ 'instance' ], action.instance); + case REMOVE.SUCCESS: + return state + .update('list', list => list.filter(item => item[ idKey ] !== action.id)) + .updateIn([ 'instance', idKey ], id => (id === action.id ? '' : id)); + default: + return state; + } + }; + + const actions = { + + fetch: (id, options = { thenInit: true }) => (dispatch, getState) => { + const itemInList = getState().getIn([ namePl, 'list' ]).find(item => item[ idKey ] === id); + if (!itemInList || !itemInList.isComplete()) { // name of func? + return dispatch({ + types: options.thenInit ? FETCH.toArray() : FETCH_IN_LIST.toArray(), + call: getCallFn('fetch', id), + }); + } + if (options.thenInit) dispatch(actions.init(itemInList)); + return Promise.resolve(); + }, + + fetchList(params) { + return { + types: FETCH_LIST.toArray(), + call: getCallFn('fetchList', params), + }; + }, + + init(instance) { + return { + type: INIT, + instance, + }; + }, + + edit(instance) { + return { + type: EDIT, + instance, + }; + }, + + save(instance) { + return { + types: SAVE.toArray(), + call: getCallFn('save', instance.toData()), + instance, + }; + }, + + remove(id) { + return { + types: REMOVE.toArray(), + call: getCallFn('remove', id), + id, + }; + }, + + }; + + const requestDuck = requestDuckGenerator({ + _: FETCH_LIST, + inListRequest: FETCH_IN_LIST, + fetchRequest: FETCH, + saveRequest: SAVE, + removeRequest: REMOVE, + }, reducer); + + return { + actions, + reducer: requestDuck.reducer, + actionTypes, + initialState: initialState.merge(requestDuck.initialState), + }; +} diff --git a/frontend/app/duck/tools/index.js b/frontend/app/duck/tools/index.js new file mode 100644 index 000000000..b93a9c026 --- /dev/null +++ b/frontend/app/duck/tools/index.js @@ -0,0 +1,19 @@ +import { Map } from 'immutable'; + +export function reduceReducers(...args) { + const initialState = args[ args.length - 1 ]; + const reducers = args.slice(0, -1); + return (state = initialState, action) => + reducers.reduce((accumState, reducer) => reducer(accumState, action), state); +} + +export function reduceDucks(...ducks) { + const accumulatedInitialState = ducks + .reduce((accumState, { initialState }) => accumState.merge(initialState), Map()); + const accumulatedReducer = (state = accumulatedInitialState, action) => + ducks.reduce((accumState, { reducer }) => reducer(accumState, action), state); + return { + initialState: accumulatedInitialState, + reducer: accumulatedReducer, + }; +} diff --git a/frontend/app/duck/tools/requestDuck.js b/frontend/app/duck/tools/requestDuck.js new file mode 100644 index 000000000..fe0f7a209 --- /dev/null +++ b/frontend/app/duck/tools/requestDuck.js @@ -0,0 +1,93 @@ +import { List, Map } from 'immutable'; + +const ROOT_KEY = '_'; +const defaultReducer = (state = Map()) => state; +const defaultInitialState = Map({ + loading: false, + errors: null, +}); + +export class RequestTypes { + constructor(type) { + this.REQUEST = `${ type }_REQUEST`; + this.SUCCESS = `${ type }_SUCCESS`; + this.FAILURE = `${ type }_FAILURE`; + } + toArray() { + return [ this.REQUEST, this.SUCCESS, this.FAILURE ]; + } +} + +function simpleRequestDuck ( + types, + customReducer = defaultReducer, +) { + const typesArray = Array.isArray(types) ? types : [ types ]; + const requestEvents = typesArray.map(a => a.REQUEST); + const successEvents = typesArray.map(a => a.SUCCESS); + const failureEvents = typesArray.map(a => a.FAILURE); + + let loadingCounter = 0; + + const reducer = (inputState, action = {}) => { + let state = customReducer(inputState, action); + state = inputState ? state : state.merge(defaultInitialState); + + if (requestEvents.includes(action.type)) { + loadingCounter += 1; + return state.set('loading', loadingCounter > 0).set('errors', null); + } + if (successEvents.includes(action.type)) { + loadingCounter -= 1; + return state.set('loading', loadingCounter > 0).set('errors', null); + } + if (failureEvents.includes(action.type)) { + loadingCounter -= 1; + return state.set('loading', loadingCounter > 0).set('errors', List(action.errors)); + } + return state; + }; + + return { reducer, initialState: defaultInitialState }; +}; + +// TODO: Errors + +/** + * @types: RequestTypes - array or single + * or object like {'state1': RequestTypes, 'state2': [RequestTypes] ... } + * @reducer: wrapped reducer + * */ +export default function requestDuck( + types, + customReducer = defaultReducer, +) { + if (types instanceof RequestTypes || types instanceof Array) { + return simpleRequestDuck(types, customReducer); + } + + const keys = Object.keys(types).filter(key => key !== ROOT_KEY); + const ducks = {}; + keys.map((key) => { ducks[ key ] = simpleRequestDuck(types[ key ]); }); + + let initialState = Map(); + let actualReducer = customReducer; + if (types[ ROOT_KEY ]) { + ({ initialState, reducer: actualReducer } = + simpleRequestDuck(types[ ROOT_KEY ], customReducer)); + } + initialState = keys.reduce( + (accumState, key) => accumState.set(key, ducks[ key ].initialState), + initialState, + ); + + const reducer = (inputState, action = {}) => { + let state = actualReducer(inputState, action); + keys.map((key) => { + state = state.update(key, subState => ducks[ key ].reducer(subState, action)); + }); + return state; + }; + + return { reducer, initialState }; +}; diff --git a/frontend/app/duck/tools/storageDuck.js b/frontend/app/duck/tools/storageDuck.js new file mode 100644 index 000000000..618b03224 --- /dev/null +++ b/frontend/app/duck/tools/storageDuck.js @@ -0,0 +1,25 @@ +import { Map } from 'immutable'; + +const initialState = Map({ + storage: Map(), +}); + +export default function storageDuck(name, fromJS = t => t, actions = []) { + const idKey = `${name}Id`; + + const reducer = (state = initialState, action) => { + if (actions.includes(action.type)) { + const { data } = action; + const updatingList = List(Array.isArray(data) ? data : [ data ]).map(fromJS); + + + return state + .update('storage', storage => updatingList + .reduce((storage, item) => storage // mergeDeep??? + .mergeIn([ item [ idKey ] ], item), storage)) + } + return state; + } + + return { reducer, initialState }; +} \ No newline at end of file diff --git a/frontend/app/duck/user.js b/frontend/app/duck/user.js new file mode 100644 index 000000000..83430e72d --- /dev/null +++ b/frontend/app/duck/user.js @@ -0,0 +1,189 @@ +import { List, Map, Record } from 'immutable'; +import Client from 'Types/client'; +import Account from 'Types/account'; +import { DELETE } from './jwt'; +import withRequestState, { RequestTypes } from './requestStateCreator'; + +export const LOGIN = new RequestTypes('user/LOGIN'); +export const SIGNUP = new RequestTypes('user/SIGNUP'); +export const RESET_PASSWORD = new RequestTypes('user/RESET_PASSWORD'); +export const REQUEST_RESET_PASSWORD = new RequestTypes('user/REQUEST_RESET_PASSWORD'); +const FETCH_ACCOUNT = new RequestTypes('user/FETCH_ACCOUNT'); +const FETCH_TENANTS = new RequestTypes('user/FETCH_TENANTS'); +const UPDATE_ACCOUNT = new RequestTypes('user/UPDATE_ACCOUNT'); +const RESEND_EMAIL_VERIFICATION = new RequestTypes('user/RESEND_EMAIL_VERIFICATION'); +const UPDATE_APPEARANCE = new RequestTypes('user/UPDATE_APPEARANCE'); +const FETCH_CLIENT = new RequestTypes('user/FETCH_CLIENT'); +export const UPDATE_PASSWORD = new RequestTypes('user/UPDATE_PASSWORD'); +const PUT_CLIENT = new RequestTypes('user/PUT_CLIENT'); + +const PUSH_NEW_SITE = 'user/PUSH_NEW_SITE'; +const SET_SITE_ID = 'user/SET_SITE_ID'; + +const SITE_ID_STORAGE_KEY = "__$user-siteId$__"; +const storedSiteId = localStorage.getItem(SITE_ID_STORAGE_KEY); + +const initialState = Map({ + client: Client(), + account: Account(), + siteId: null, + passwordRequestError: false, + passwordErrors: List(), + tenants: [] +}); + +const setClient = (state, data) => { + const client = Client(data); + let siteId = state.get("siteId"); + if (!siteId) { + siteId = !!client.sites.find(s => s.id === storedSiteId) + ? storedSiteId + : client.getIn([ 'sites', 0, 'id' ]); + } + return state + .set('client', client) + .set('siteId', siteId); +} + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case SIGNUP.SUCCESS: + case LOGIN.SUCCESS: + return setClient( + state.set('account', Account(action.data.user)), + action.data.client, + ); + case REQUEST_RESET_PASSWORD.SUCCESS: + break; + case UPDATE_APPEARANCE.REQUEST: //TODO: failure handling + return state.mergeIn([ 'account', 'appearance' ], action.appearance) + case UPDATE_PASSWORD.SUCCESS: + case UPDATE_ACCOUNT.SUCCESS: + case FETCH_ACCOUNT.SUCCESS: + return state.set('account', Account(action.data)).set('passwordErrors', List()); + case FETCH_TENANTS.SUCCESS: + return state.set('tenants', action.data.map(i => ({ text: i.name, value: i.tenantId}))); + case UPDATE_PASSWORD.FAILURE: + return state.set('passwordErrors', List(action.errors)) + case DELETE: + return initialState; + case PUT_CLIENT.REQUEST: + return state.mergeIn([ 'client' ], action.params); + case FETCH_CLIENT.SUCCESS: + return setClient(state, action.data); + case SET_SITE_ID: + localStorage.setItem(SITE_ID_STORAGE_KEY, action.siteId) + return state.set('siteId', action.siteId); + case PUSH_NEW_SITE: + return state.updateIn([ 'client', 'sites' ], list => + list.push(action.newSite)); + } + return state; +}; + +export default withRequestState({ + loginRequest: LOGIN, + signupRequest: SIGNUP, + updatePasswordRequest: UPDATE_PASSWORD, + requestResetPassowrd: REQUEST_RESET_PASSWORD, + resetPassword: RESET_PASSWORD, + fetchUserInfoRequest: [ FETCH_ACCOUNT, FETCH_CLIENT ], + putClientRequest: PUT_CLIENT, + updateAccountRequest: UPDATE_ACCOUNT, + updateAppearance: UPDATE_APPEARANCE, +}, reducer); + +export const login = params => dispatch => dispatch({ + types: LOGIN.toArray(), + call: client => client.post('/login', params), +}); + +export const signup = params => dispatch => dispatch({ + types: SIGNUP.toArray(), + call: client => client.post('/signup', params), +}); + +export const resetPassword = params => dispatch => dispatch({ + types: RESET_PASSWORD.toArray(), + call: client => client.post('/password/reset/2', params), +}); + +export const requestResetPassword = params => dispatch => dispatch({ + types: REQUEST_RESET_PASSWORD.toArray(), + call: client => client.post('/password/reset/1', params), +}); + +export const updatePassword = params => dispatch => dispatch({ + types: UPDATE_PASSWORD.toArray(), + call: client => client.post('/account/password', params), +}) + +export function fetchTenants() { + return { + types: FETCH_TENANTS.toArray(), + call: client => client.get('/signup') + } +} + +export const fetchUserInfo = () => dispatch => Promise.all([ + dispatch({ + types: FETCH_ACCOUNT.toArray(), + call: client => client.get('/account'), + }), + dispatch({ + types: FETCH_CLIENT.toArray(), + call: client => client.get('/client'), + }), +]); + +export function logout() { + return { + type: DELETE, + }; +} + +export function updateClient(params) { + return { + types: PUT_CLIENT.toArray(), + call: client => client.put('/client', params), + params, + }; +} + +export function updateAccount(params) { + return { + types: UPDATE_ACCOUNT.toArray(), + call: client => client.post('/account', params), + } +} + +export function resendEmailVerification(email) { + return { + types: RESEND_EMAIL_VERIFICATION.toArray(), + call: client => client.post('/re-validate', { email }), + } +} + +export function updateAppearance(appearance) { + return { + types: UPDATE_APPEARANCE.toArray(), + call: client => client.post('/account', { + appearance: Record.isRecord(appearance) ? appearance.toData() : appearance + }), + appearance, + }; +} + +export function setSiteId(siteId) { + return { + type: SET_SITE_ID, + siteId, + }; +} + +export function pushNewSite(newSite) { + return { + type: PUSH_NEW_SITE, + newSite, + }; +} diff --git a/frontend/app/duck/variables.js b/frontend/app/duck/variables.js new file mode 100644 index 000000000..21a0131c4 --- /dev/null +++ b/frontend/app/duck/variables.js @@ -0,0 +1,9 @@ +import Variable from 'Types/variable'; +import crudDuckGenerator from './tools/crudDuck'; + +const crudDuck = crudDuckGenerator('variable', Variable); +export const { + fetchList, fetch, init, edit, save, remove, +} = crudDuck.actions; + +export default crudDuck.reducer; diff --git a/frontend/app/duck/watchdogs.js b/frontend/app/duck/watchdogs.js new file mode 100644 index 000000000..87966264a --- /dev/null +++ b/frontend/app/duck/watchdogs.js @@ -0,0 +1,101 @@ +import { List, Map } from 'immutable'; +import Watchdog from 'Types/watchdog'; +import { mergeReducers, success, array, request } from './funcTools/tools'; +import { createRequestReducer } from './funcTools/request'; +import { + createCRUDReducer, + getCRUDRequestTypes, + createFetchList, + createInit, + createEdit, + createRemove, + createSave, +} from './funcTools/crud'; + +const name = 'issue_type'; +const idKey = 'id'; +const SET_ACTIVE_TAB = 'watchdogs/SET_ACTIVE_TAB'; +const FETCH_WATCHDOG_STATUS = 'watchdogs/FETCH_WATCHDOG_STATUS'; +const FETCH_WATCHDOG_STATUS_SUCCESS = success(FETCH_WATCHDOG_STATUS); +const FETCH_RULES = 'watchdogs/FETCH_RULES'; +const FETCH_RULES_SUCCESS = success(FETCH_RULES); +const SAVE_CAPTURE_RATE = 'watchdogs/SAVE_CAPTURE_RATE'; +const EDIT_CAPTURE_RATE = 'watchdogs/SAVE_CAPTURE_RATE'; + +const initialState = Map({ + activeTab: Map(), + instance: Watchdog(), + list: List(), + rules: List(), + captureRate: Map() +}); + +const reducer = (state = initialState, action = {}) => { + switch (action.type) { + case SET_ACTIVE_TAB: + return state.set('activeTab', action.instance); + case FETCH_RULES_SUCCESS: + return state.set('rules', action.data); + case FETCH_WATCHDOG_STATUS_SUCCESS: + case success(SAVE_CAPTURE_RATE): + return state.set('captureRate', Map(action.data)); + case request(SAVE_CAPTURE_RATE): + return state.mergeIn(['captureRate'], action.params); + case EDIT_CAPTURE_RATE: + return state.mergeIn(['captureRate'], {rate: action.rate}); + } + return state; +}; + + +export const fetchList = createFetchList(name); +export const init = createInit(name); +export const edit = createEdit(name); +export const save = createSave(name); +export const remove = createRemove(name); + +export function setActiveTab(instance) { + return { + type: SET_ACTIVE_TAB, + instance, + }; +} + +export const fetchRules = () => { + return { + types: array(FETCH_RULES), + call: client => client.get(`/watchdogs/rules`), + }; +} + +export default mergeReducers( + reducer, + createCRUDReducer(name, Watchdog, idKey), + createRequestReducer({ + fetchWatchdogStatus: FETCH_WATCHDOG_STATUS, + savingCaptureRate: SAVE_CAPTURE_RATE, + ...getCRUDRequestTypes(name), + }), +); + +export const saveCaptureRate = (params) => { + return { + params, + types: array(SAVE_CAPTURE_RATE), + call: client => client.post(`/sample_rate`, params), + } +} + +export const editCaptureRate = rate => { + return { + type: EDIT_CAPTURE_RATE, + rate + } +} + +export const fetchWatchdogStatus = () => { + return { + types: array(FETCH_WATCHDOG_STATUS), + call: client => client.get('/sample_rate'), + }; +} diff --git a/frontend/app/duck/webhook.js b/frontend/app/duck/webhook.js new file mode 100644 index 000000000..8dc323a75 --- /dev/null +++ b/frontend/app/duck/webhook.js @@ -0,0 +1,7 @@ +import Webhook from 'Types/webhook'; +import crudDuckGenerator from './tools/crudDuck'; + +const crudDuck = crudDuckGenerator('webhook', Webhook, { idKey: 'webhookId' }); +export const { fetchList, init, edit, save, remove } = crudDuck.actions; + +export default crudDuck.reducer; diff --git a/frontend/app/hooks/usePageTitle.js b/frontend/app/hooks/usePageTitle.js new file mode 100644 index 000000000..f1c701497 --- /dev/null +++ b/frontend/app/hooks/usePageTitle.js @@ -0,0 +1,7 @@ +import { useEffect } from 'react'; + +export default function usePageTitle(title) { + return useEffect(() => { + document.title = title; + }, []) +} \ No newline at end of file diff --git a/frontend/app/hooks/useToggle.js b/frontend/app/hooks/useToggle.js new file mode 100644 index 000000000..d8e567a9b --- /dev/null +++ b/frontend/app/hooks/useToggle.js @@ -0,0 +1,8 @@ +import { useState, useCallback } from 'react'; + +export default function useToggle(defaultValue = false) { + const [ value, setValue ] = useState(defaultValue); + const toggle = useCallback(() => setValue(d => !d), []); + const setFalse = useCallback(() => setValue(false), []); + return [ value, toggle, setFalse ]; +} \ No newline at end of file diff --git a/frontend/app/iconNames.js b/frontend/app/iconNames.js new file mode 100644 index 000000000..0162910c7 --- /dev/null +++ b/frontend/app/iconNames.js @@ -0,0 +1,45 @@ +export function osIcon(os) { + let osIcon = os.toLocaleLowerCase().replace(/ /g, '_'); + if (osIcon.includes('mac')) { + osIcon = 'mac_os_x'; + } + return 'os/' + osIcon; +} + +const browserNames = [ 'chrome', 'safari', 'firefox', 'opera', 'facebook', 'edge', 'ie' ]; +export function browserIcon(browser) { + if (typeof browser != 'string') return "browser/browser"; + const browserString = browser.toLocaleLowerCase(); + let browserName = 'browser'; + browserNames.some(bn => { + if (browserString.includes(bn)) { + browserName = bn; + return true; + } + return false; + }); + return `browser/${ browserName }`; +}; + +export function deviceTypeIcon(deviceType) { + switch (deviceType) { + case 'desktop': + return 'desktop'; + case 'console': + case 'mobile': + case 'tablet': + case 'phone': + return 'mobile' + default: + return 'device'; + } +} + +const ICON_LIST = ['icn_chameleon', 'icn_fox', 'icn_gorilla', 'icn_hippo', 'icn_horse', 'icn_hyena', + 'icn_kangaroo', 'icn_lemur', 'icn_mammel', 'icn_monkey', 'icn_moose', 'icn_panda', + 'icn_penguin', 'icn_porcupine', 'icn_quail', 'icn_rabbit', 'icn_rhino', 'icn_sea_horse', + 'icn_sheep', 'icn_snake', 'icn_squirrel', 'icn_tapir', 'icn_turtle', 'icn_vulture', + 'icn_wild1', 'icn_wild_bore']; +export function avatarIconName(seed = Math.floor(Math.random() * ICON_LIST.length)) { + return `avatar/${ICON_LIST[ seed % ICON_LIST.length ]}`; +} \ No newline at end of file diff --git a/frontend/app/init/codemirror.js b/frontend/app/init/codemirror.js new file mode 100644 index 000000000..37911ae6f --- /dev/null +++ b/frontend/app/init/codemirror.js @@ -0,0 +1,9 @@ +import { JSHINT } from 'jshint'; +import 'codemirror/mode/javascript/javascript'; +import 'codemirror/addon/lint/lint'; +import 'codemirror/addon/lint/javascript-lint'; + +window.JSHINT = JSHINT; + +// Init with no errors +JSHINT(''); diff --git a/frontend/app/init/immutable.js b/frontend/app/init/immutable.js new file mode 100644 index 000000000..4d9b28f52 --- /dev/null +++ b/frontend/app/init/immutable.js @@ -0,0 +1,11 @@ +import { Record } from 'immutable'; + +Record.prototype.exists = function exists() { + const idKey = this.idKey || 'id'; + return this[ idKey ] !== undefined && this[ idKey ] !== ''; +}; +Record.prototype.validate = () => true; +Record.prototype.isComplete = () => true; +Record.prototype.toData = function toData() { + return this.toJS(); +}; diff --git a/frontend/app/init/index.js b/frontend/app/init/index.js new file mode 100644 index 000000000..082b95b7c --- /dev/null +++ b/frontend/app/init/index.js @@ -0,0 +1,3 @@ +import './codemirror'; +import './immutable'; +import './sentry'; \ No newline at end of file diff --git a/frontend/app/init/sentry.js b/frontend/app/init/sentry.js new file mode 100644 index 000000000..dabf12ec3 --- /dev/null +++ b/frontend/app/init/sentry.js @@ -0,0 +1,5 @@ +import * as Sentry from '@sentry/browser'; + +if (window.ENV.SENTRY_ENABLED) { + Sentry.init({ dsn: window.ENV.SENTRY_URL }); +} \ No newline at end of file diff --git a/frontend/app/initialize.js b/frontend/app/initialize.js new file mode 100644 index 000000000..60760504f --- /dev/null +++ b/frontend/app/initialize.js @@ -0,0 +1,18 @@ +import './init'; + +import { render } from 'react-dom'; +import { Provider } from 'react-redux'; + +import store from './store'; +import Router from './Router'; + +document.addEventListener('DOMContentLoaded', () => { + render( + ( + <Provider store={ store }> + <Router /> + </Provider> + ), + document.getElementById('app'), + ); +}); diff --git a/frontend/app/local_storage.js b/frontend/app/local_storage.js new file mode 100644 index 000000000..b4329c7e2 --- /dev/null +++ b/frontend/app/local_storage.js @@ -0,0 +1,37 @@ +export default class LocalStorage { + constructor(types) { + this._types = types; + this._state = {}; + Object.keys(types).forEach((k) => { this._state[ k ] = null; }); + } + + state() { + Object.keys(this._types).forEach((k) => { + const v = localStorage.getItem(k); + this._state[ k ] = v; + if (v !== null) { + try { + const p = new this._types[ k ](JSON.parse(v)); + this._state[ k ] = p; + } catch (e) { + localStorage.removeItem(k); + } + } + }); + return this._state; + } + + sync(state) { + Object.keys(this._types).forEach((k) => { + const v = state[ k ]; + if (v === null) { + localStorage.removeItem(k); + return; + } + if (this._state[ k ] !== v) { + this._state[ k ] = v; + localStorage.setItem(k, JSON.stringify(v)); + } + }); + } +} diff --git a/frontend/app/logger/index.js b/frontend/app/logger/index.js new file mode 100644 index 000000000..c698f46e1 --- /dev/null +++ b/frontend/app/logger/index.js @@ -0,0 +1,27 @@ +import { options } from 'App/dev/console'; + +function log(...args) { + if (!window.ENV.PRODUCTION || options.logStuff) { + console.log(...args); + } +} + +function warn(...args) { + if (!window.ENV.PRODUCTION || options.logStuff) { + console.warn(...args); + } +} + +function error(...args) { + if (!window.ENV.PRODUCTION || options.logStuff) { + console.error(...args); + } +} + + +export default { + info: log, + log, + warn, + error, +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/MessageDistributor.js b/frontend/app/player/MessageDistributor/MessageDistributor.js new file mode 100644 index 000000000..ebdd423ce --- /dev/null +++ b/frontend/app/player/MessageDistributor/MessageDistributor.js @@ -0,0 +1,463 @@ +//@flow +import { Decoder } from "syncod"; +import logger from 'App/logger'; + +import Resource, { TYPES } from 'Types/session/resource'; // MBTODO: player types? +import { TYPES as EVENT_TYPES } from 'Types/session/event'; +import Log from 'Types/session/log'; +import Profile from 'Types/session/profile'; +import ReduxAction from 'Types/session/reduxAction'; + +import { update } from '../store'; +import { + init as initLists, + append as listAppend, + setStartTime as setListsStartTime + } from '../lists'; + +import StatedScreen from './StatedScreen'; + +import ListWalker from './managers/ListWalker'; +import PagesManager from './managers/PagesManager'; +import MouseManager from './managers/MouseManager'; + +import PerformanceTrackManager from './managers/PerformanceTrackManager'; +import WindowNodeCounter from './managers/WindowNodeCounter'; +import ActivityManager from './managers/ActivityManager'; + +import MessageGenerator from './MessageGenerator'; + +import { INITIAL_STATE as PARENT_INITIAL_STATE } from './StatedScreen'; + + +const LIST_NAMES = [ "redux", "mobx", "vuex", "ngrx", "graphql", "exceptions", "profiles", "longtasks" ] +const LISTS_INITIAL_STATE = {}; +LIST_NAMES.forEach(name => { + LISTS_INITIAL_STATE[`${name}ListNow`] = []; + LISTS_INITIAL_STATE[`${name}List`] = []; +}) +export const INITIAL_STATE = { + ...PARENT_INITIAL_STATE, + ...LISTS_INITIAL_STATE, + performanceChartData: [], + skipIntervals: [], +} + + +import type { + Message, + SetLocation, + SetTitle, + ConnectionInformation, + SetViewportSize, + SetViewportScroll, +} from './messages'; + + +type ReduxDecoded = Timed & { + action: {}, + state: {}, + duration: number, +} + +export default class MessageDistributor extends StatedScreen { + // TODO: consistent with the other data-lists + #locationEventManager: ListWalker<> = new ListWalker(); + #locationManager: ListWalker<SetLocation> = new ListWalker(); + #loadedLocationManager: ListWalker<SetLocation> = new ListWalker(); + #titleManager: ListWalker<SetTitle> = new ListWalker(); + #connectionInfoManger: ListWalker<ConnectionInformation> = new ListWalker(); + #performanceTrackManager: PerformanceTrackManager = new PerformanceTrackManager(); + #windowNodeCounter: WindowNodeCounter = new WindowNodeCounter(); + #clickManager: ListWalker = new ListWalker(); + + #resizeManager: ListWalker<SetViewportSize> = new ListWalker(); + #pagesManager: PagesManager; + #mouseManager: MouseManager; + + #scrollManager: ListWalker<SetViewportScroll> = new ListWalker(); + + #decoder = new Decoder(); + #lists = { + redux: new ListWalker(), + mobx: new ListWalker(), + vuex: new ListWalker(), + ngrx: new ListWalker(), + graphql: new ListWalker(), + exceptions: new ListWalker(), + profiles: new ListWalker(), + longtasks: new ListWalker(), + } + + #activirtManager: ActivityManager; + + #sessionStart: number; + #navigationStartOffset: number = 0; + #lastMessageTime: number = 0; + + constructor(sess: any /*Session*/, jwt: string) { + super(); + this.#pagesManager = new PagesManager(this, sess.isMobile) + this.#mouseManager = new MouseManager(this); + + this.#activirtManager = new ActivityManager(sess.duration.milliseconds); + + this.#sessionStart = sess.startedAt; + + /* == REFACTOR_ME == */ + const eventList = sess.events.toJSON(); + initLists({ + event: eventList, + stack: sess.stackEvents.toJSON(), + resource: sess.resources.toJSON(), + }); + + eventList.forEach(e => { + if (e.type === EVENT_TYPES.LOCATION) { //TODO type system + this.#locationEventManager.add(e); + } + if (e.type === EVENT_TYPES.CLICK) { + this.#clickManager.add(e); + } + }); + sess.errors.forEach(e => { + this.#lists.exceptions.add(e); + }); + /* === */ + + + if (sess.live) { + // const sockUrl = `wss://live.openreplay.com/1/${ sess.siteId }/${ sess.sessionId }/${ jwt }`; + // this.#subscribeOnMessages(sockUrl); + } else { + this._loadMessages(sess.mobsUrl); + } + } + + + // #subscribeOnMessages(sockUrl) { + // this.setMessagesLoading(true); + // const socket = new WebSocket(sockUrl); + // socket.binaryType = 'arraybuffer'; + // socket.onerror = (e) => { + // // TODO: reconnect + // update({ error: true }); + // } + // socket.onmessage = (socketMessage) => { + // const data = new Uint8Array(socketMessage.data); + // const msgs = []; + // messageGenerator // parseBuffer(msgs, data); + // // TODO: count indexes. Now will not work due to wrong indexes + // //msgs.forEach(this.#distributeMessage); + // this.setMessagesLoading(false); + // this.setDisconnected(false); + // } + // this._socket = socket; + // } + + _loadMessages(fileUrl): void { + this.setMessagesLoading(true); + window.fetch(fileUrl) + .then(r => r.arrayBuffer()) + .then(b => { + const mGen = new MessageGenerator(new Uint8Array(b), this.#sessionStart); + let mCount = 0; + const msgs = []; + + // Hack for upet (TODO: fix ordering in one mutation (removes first)) + const headChildrenIds = msgs.filter(m => m.parentID === 1).map(m => m.id); + //const createNodeTypes = ["create_text_node", "create_element_node"]; + this.#pagesManager.sort((m1, m2) =>{ + if (m1.time === m2.time) { + if (m1.tp === "remove_node" && m2.tp !== "remove_node") { + if (headChildrenIds.includes(m1.id)) { + return -1; + } + } else if (m2.tp === "remove_node" && m1.tp !== "remove_node") { + if (headChildrenIds.includes(m2.id)) { + return 1; + } + } else if (m2.tp === "remove_node" && m1.tp === "remove_node") { + const m1FromHead = headChildrenIds.includes(m1.id); + const m2FromHead = headChildrenIds.includes(m2.id); + if (m1FromHead && !m2FromHead) { + return -1; + } else if (m2FromHead && !m1FromHead) { + return 1; + } + } + } + return 0; + }) + // + + logger.info("Messages count: ", mCount, msgs); + + const stateToUpdate = { + performanceChartData: this.#performanceTrackManager.chartData, + performanceAvaliability: this.#performanceTrackManager.avaliability, + }; + this.#activirtManager.end(); + stateToUpdate.skipIntervals = this.#activirtManager.list; + LIST_NAMES.forEach(key => { + stateToUpdate[ `${ key }List` ] = this.#lists[ key ].list; + }); + update(stateToUpdate); + + this.#windowNodeCounter.reset(); + + this.setMessagesLoading(false); + }) + .catch((e) => { + logger.error(e); + this.setMessagesLoading(false); + update({ error: true }); + }); + } + + move(t: number, index: ?number):void { + const stateToUpdate = {}; + /* == REFACTOR_ME == */ + const lastLoadedLocationMsg = this.#loadedLocationManager.moveToLast(t, index); + if (!!lastLoadedLocationMsg) { + setListsStartTime(lastLoadedLocationMsg.time) + this.#navigationStartOffset = lastLoadedLocationMsg.navigationStart - this.#sessionStart; + } + const llEvent = this.#locationEventManager.moveToLast(t, index); + if (!!llEvent) { + if (llEvent.domContentLoadedTime != null) { + stateToUpdate.domContentLoadedTime = llEvent.domContentLoadedTime + this.#navigationStartOffset; + } + if (llEvent.loadTime != null) { + stateToUpdate.loadTime = llEvent.domContentLoadedTime + this.#navigationStartOffset + } + if (llEvent.domBuildingTime != null) { + stateToUpdate.domBuildingTime = llEvent.domBuildingTime; + } + } + /* === */ + const lastLocationMsg = this.#locationManager.moveToLast(t, index); + if (!!lastLocationMsg) { + stateToUpdate.location = lastLocationMsg.url; + } + const lastTitleMsg = this.#titleManager.moveToLast(t, index); + if (!!lastTitleMsg) { + stateToUpdate.title = lastTitleMsg.title; + } + const lastConnectionInfoMsg = this.#connectionInfoManger.moveToLast(t, index); + if (!!lastConnectionInfoMsg) { + stateToUpdate.connType = lastConnectionInfoMsg.type; + stateToUpdate.connBandwidth = lastConnectionInfoMsg.downlink; + } + const lastPerformanceTrackMessage = this.#performanceTrackManager.moveToLast(t, index); + if (!!lastPerformanceTrackMessage) { + stateToUpdate.performanceChartTime = lastPerformanceTrackMessage.time; + } + + LIST_NAMES.forEach(key => { + const lastMsg = this.#lists[ key ].moveToLast(t, key === 'exceptions' ? null : index); + if (lastMsg != null) { + stateToUpdate[`${key}ListNow`] = this.#lists[ key ].listNow; + } + }); + + update(stateToUpdate); + + /* Sequence of the managers is important here */ + // Preparing the size of "screen" + const lastResize = this.#resizeManager.moveToLast(t, index); + if (!!lastResize) { + this.setSize(lastResize) + } + this.#pagesManager.moveReady(t).then(() => { + + const lastScroll = this.#scrollManager.moveToLast(t, index); + if (!!lastScroll && this.window) { + this.window.scrollTo(lastScroll.x, lastScroll.y); + } + // Moving mouse and setting :hover classes on ready view + this.#mouseManager.move(t); + const lastClick = this.#clickManager.moveToLast(t); + // if (!!lastClick) { + // this.cursor.click(); + // } + // After all changes - redraw the marker + this.marker.redraw(); + }) + } + + _decodeMessage(msg, keys: Array<string>) { + const decoded = {}; + try { + keys.forEach(key => { + decoded[ key ] = this.#decoder.decode(msg[ key ]); + }); + } catch (e) { + logger.error("Error on message decoding: ", e, msg); + return null; + } + return { ...msg, ...decoded }; + } + + /* Binded */ + #distributeMessage = (msg: Message, index: number): void => { + if ([ + "mouse_move", + "set_input_value", + "set_input_checked", + "set_viewport_size", + "set_viewport_scroll", + ].includes(msg.tp)) { + this.#activirtManager.updateAcctivity(msg.time); + } + //const index = #i + index; //? + let decoded; + const time = msg.time; + switch (msg.tp) { + /* Lists: */ + case "resource_timing": + logger.log(msg) + listAppend("resource", Resource({ + time, + duration: msg.duration, + ttfb: msg.ttfb, + url: msg.url, + initiator: msg.initiator, + index, + })); + break; + case "console_log": + if (msg.level === 'debug') break; + listAppend("log", Log({ + level: msg.level, + value: msg.value, + time, + index, + })); + break; + case "fetch": + listAppend("fetch", Resource({ + method: msg.method, + url: msg.url, + payload: msg.request, + response: msg.response, + status: msg.status, + duration: msg.duration, + type: TYPES.FETCH, + time: msg.timestamp - this.#sessionStart, //~ + index, + })); + break; + /* */ + case "set_page_location": + this.#locationManager.add(msg); + if (msg.navigationStart > 0) { + this.#loadedLocationManager.add(msg); + } + break; + case "set_title": + this.#titleManager.add(msg); + break; + case "set_viewport_size": + this.#resizeManager.add(msg); + break; + case "mouse_move": + this.#mouseManager.add(msg); + break; + case "set_viewport_scroll": + this.#scrollManager.add(msg); + break; + case "performance_track": + this.#performanceTrackManager.add(msg); + break; + case "set_page_visibility": + this.#performanceTrackManager.handleVisibility(msg) + break; + case "connection_information": + this.#connectionInfoManger.add(msg); + break; + case "o_table": + this.#decoder.set(msg.key, msg.value); + break; + case "redux": + decoded = this._decodeMessage(msg, ["state", "action"]); + logger.log(decoded) + if (decoded != null) { + this.#lists.redux.add(decoded); + } + break; + case "ng_rx": + decoded = this._decodeMessage(msg, ["state", "action"]); + logger.log(decoded) + if (decoded != null) { + this.#lists.ngrx.add(decoded); + } + break; + case "vuex": + decoded = this._decodeMessage(msg, ["state", "mutation"]); + logger.log(decoded) + if (decoded != null) { + this.#lists.vuex.add(decoded); + } + break; + case "mob_x": + decoded = this._decodeMessage(msg, ["payload"]); + logger.log(decoded) + + if (decoded != null) { + this.#lists.mobx.add(decoded); + } + break; + case "graph_ql": + msg.duration = 0; + this.#lists.graphql.add(msg); + break; + case "profiler": + this.#lists.profiles.add(msg); + break; + case "long_task": + this.#lists.longtasks.add({ + ...msg, + time: msg.timestamp - this.#sessionStart, + }); + break; + default: + switch (msg.tp){ + case "create_document": + this.#windowNodeCounter.reset(); + this.#performanceTrackManager.setCurrentNodesCount(this.#windowNodeCounter.count); + break; + case "create_text_node": + case "create_element_node": + this.#windowNodeCounter.addNode(msg.id, msg.parentID); + this.#performanceTrackManager.setCurrentNodesCount(this.#windowNodeCounter.count); + break; + case "move_node": + this.#windowNodeCounter.moveNode(msg.id, msg.parentID); + this.#performanceTrackManager.setCurrentNodesCount(this.#windowNodeCounter.count); + break; + case "remove_node": + this.#windowNodeCounter.removeNode(msg.id); + this.#performanceTrackManager.setCurrentNodesCount(this.#windowNodeCounter.count); + break; + } + this.#pagesManager.add(msg); + break; + } + } + + getLastMessageTime():number { + return this.#lastMessageTime; + } + + getFirstMessageTime():number { + return 0; //this.#pagesManager.minTime; + } + + // TODO: clean managers? + clean() { + super.clean(); + if (this._socket) this._socket.close(); + update(INITIAL_STATE); + } +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/MessageGenerator.js b/frontend/app/player/MessageDistributor/MessageGenerator.js new file mode 100644 index 000000000..7b1bce463 --- /dev/null +++ b/frontend/app/player/MessageDistributor/MessageGenerator.js @@ -0,0 +1,82 @@ +import type { TimedMessage } from './Timed'; + +import logger from 'App/logger'; +import readMessage from './messages'; + +function needSkipMessage(data: Uint8Array, p: number, pLast: number): boolean { + for (let i = 7; i >= 0; i--) { + if (data[ p + i ] !== data[ pLast + i ]) { + return data[ p + i ] - data[ pLast + i ] < 0 + } + } + return true +} + +export default class MessageGenerator { + #data: Uint8Array; + #p: number = 0; + #pLastMessageID: number = 0; + #startTime: number; + #currentTime: ?number; + + #error: boolean = false; + constructor(data: Uint8Array, startTime: number) { + this.#startTime = startTime; + this.#data = data; + } + + _needSkipMessage():boolean { + if (this.#p === 0) return false; + for (let i = 7; i >= 0; i--) { + if (this.#data[ this.#p + i ] !== this.#data[ this.#pLastMessageID + i ]) { + return this.#data[ this.#p + i ] - this.#data[ this.#pLastMessageID + i ] < 0; + } + } + return true; + } + + _readMessage(): ?Message { + this.#p += 8; + try { + let msg + [ msg, this.#p ] = readMessage(this.#data, this.#p); + return msg; + } catch (e) { + this.#error = true; + logger.error("Read message error:", e); + return null; + } + } + + hasNext():boolean { + return !this.#error && this.#data.length > this.#p; + } + + next(): ?[ TimedMessage, number] { + if (!this.hasNext()) { + return null; + } + + while (this._needSkipMessage()) { + this._readMessage(); + } + this.#pLastMessageID = this.#p; + + const msg = this._readMessage(); + if (!msg) { + return null; + } + + + if (msg.tp === "timestamp") { + // if (this.#startTime == null) { + // this.#startTime = msg.timestamp + // } + this.#currentTime = msg.timestamp - this.#startTime; + } else { + msg.time = this.#currentTime; + msg._index = this.#pLastMessageID; + return [msg, this.#pLastMessageID]; + } + } +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/Cursor.js b/frontend/app/player/MessageDistributor/StatedScreen/Screen/Cursor.js new file mode 100644 index 000000000..bce178b41 --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/Cursor.js @@ -0,0 +1,52 @@ +import styles from './cursor.css'; + +export default class Cursor { + constructor(overlay, screen) { + this.screen = screen; + this._cursor = document.createElement('div'); + this._cursor.className = styles.cursor; + + this._click = document.createElement('div'); + this._click.className = styles.click; + + overlay.appendChild(this._click); + overlay.appendChild(this._cursor); + } + + toggle(flag) { + if (flag) { + this._cursor.style.display = 'block'; + } else { + this._cursor.style.display = 'none'; + } + } + + move({ x, y }) { + this._x = x; + this._y = y; + this._cursor.style.left = x + 'px'; + this._cursor.style.top = y + 'px'; + } + + // click() { + // this._cursor.style.left = this._x + 'px'; + // this._cursor.style.top = this._y + 'px'; + // this._click.style.display = 'block'; + // setTimeout(() => { + // this._click.style.display = "none"; + // }, 2000); + // } + + _getInternalCoordinates() { + return { x: this._x, y: this._y }; + } + + getTarget() { + return this.screen.getElementFromInternalPoint(this._getInternalCoordinates()); + } + + getTargets() { + return this.screen.getElementsFromInternalPoint(this._getInternalCoordinates()); + } + +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/Inspector.js b/frontend/app/player/MessageDistributor/StatedScreen/Screen/Inspector.js new file mode 100644 index 000000000..a4dd39e1c --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/Inspector.js @@ -0,0 +1,33 @@ +import { select } from 'optimal-select'; + + +export default class Inspector { + constructor(screen) { + this.screen = screen; + } + + _onMouseMove = (e) => { + const { overlay, marker } = this.screen; + if (e.target !== overlay) return marker.unmark(); + + e.stopPropagation(); + const target = this.screen.getElementFromPoint(e); + marker.mark(target); + } + + _onMarkClick = () => { + onTargetClick(select(markedTarget, { root: this.screen.document })); + } + + toggle(flag) { + if (flag) { + this.screen.cursor.toggle(false); + document.addEventListener('mousemove', this._onMouseMove); + this.screen.overlay.addEventListener('click', this._onMarkClick); + } else { + this.screen.toggle(true); + document.removeEventListener('mousemove', this._onMouseMove); + this.screen.overlay.removeEventListener('click', this._onMarkClick); + } + } +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/Marker.js b/frontend/app/player/MessageDistributor/StatedScreen/Screen/Marker.js new file mode 100644 index 000000000..971bf0f9d --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/Marker.js @@ -0,0 +1,84 @@ +import styles from './marker.css'; + +export default class Marker { + _target = null; + _selector = null; + + constructor(overlay, screen) { + this.screen = screen; + + const marker = document.createElement('div'); + marker.className = styles.marker; + const markerL = document.createElement('div'); + const markerR = document.createElement('div'); + const markerT = document.createElement('div'); + const markerB = document.createElement('div'); + markerL.className = styles.markerL; + markerR.className = styles.markerR; + markerT.className = styles.markerT; + markerB.className = styles.markerB; + marker.appendChild(markerL); + marker.appendChild(markerR); + marker.appendChild(markerT); + marker.appendChild(markerB); + + overlay.appendChild(marker); + this._marker = marker; + } + + mark(element) { + this._target = element; + this._selector = null; + this.redraw(); + } + + unmark() { + this.mark(null); + } + + _autodefineTarget() { + if (this._selector) { + try { + const fitTargets = this.screen.document.querySelectorAll(this._selector); + if (fitTargets.length === 0) { + this._target = null; + } else { + this._target = fitTargets[ 0 ]; + const cursorTarget = this.screen.cursor.getTarget(); + fitTargets.forEach((target) => { + if (target.contains(cursorTarget)) { + this._target = target; + } + }); + } + } catch(e) { + console.info(e); + } + } else { + this._target = null; + } + } + + markBySelector(selector) { + this._selector = selector; + this._autodefineTarget(); + this.redraw(); + } + + redraw() { + if (this._selector) { + this._autodefineTarget(); + } + if (!this._target) { + this._marker.style.display = 'none'; + return; + } + const rect = this._target.getBoundingClientRect(); + this._marker.style.display = 'block'; + this._marker.style.left = rect.left + 'px'; + this._marker.style.top = rect.top + 'px'; + this._marker.style.width = rect.width + 'px'; + this._marker.style.height = rect.height + 'px'; + } + +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/Screen.js b/frontend/app/player/MessageDistributor/StatedScreen/Screen/Screen.js new file mode 100644 index 000000000..5232e0960 --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/Screen.js @@ -0,0 +1,115 @@ +import Marker from './Marker'; +import Cursor from './Cursor'; +import Inspector from './Inspector'; +import styles from './screen.css'; +import { getState } from '../../../store'; + +export const INITIAL_STATE = { + width: 0, + height: 0, +} + +export default class Screen { + constructor() { + const iframe = document.createElement('iframe'); + iframe.className = styles.iframe; + this.iframe = iframe; + + const overlay = document.createElement('div'); + overlay.className = styles.overlay; + this.overlay = overlay; + + const screen = document.createElement('div'); + screen.className = styles.screen; + screen.appendChild(iframe); + screen.appendChild(overlay); + this._screen = screen; + + this.marker = new Marker(overlay, this); + this.cursor = new Cursor(overlay, this); + this.inspector = new Inspector(this); + } + + attach(parentElement) { + parentElement.appendChild(this._screen); + + this._parentElement = parentElement; + // parentElement.onresize = this.scale; + window.addEventListener('resize', this.scale); + this.scale(); + } + + get window() { + return this.iframe.contentWindow; + } + + get document() { + return this.iframe.contentDocument; + } + + _getInternalCoordinates({ x, y }) { + const { x: overlayX, y: overlayY, width } = this.overlay.getBoundingClientRect(); + const screenWidth = this.overlay.offsetWidth; + + const scale = screenWidth / width; + const screenX = (x - overlayX) * scale; + const screenY = (y - overlayY) * scale; + return { x: screenX, y: screenY }; + } + + getElementFromInternalPoint(coords) { + const { x, y } = this._getInternalCoordinates(coords); + return this.document.elementFromPoint(x, y); + } + + getElementsFromInternalPoint({ x, y }) { + // IE, Edge + if (typeof this.document.msElementsFromRect === 'function') { + return Array.prototype.slice.call(this.document.msElementsFromRect(x,y)) || []; + } + + if (typeof this.document.elementsFromPoint === 'function') { + return this.document.elementsFromPoint(x, y) || []; + } + const node = this.document.elementFromPoint(x, y); + return node ? [ node ] : []; + } + + getElementFromPoint(coords){ + return this.getElementFromInternalPoint(this._getInternalCoordinates(coords)); + } + + getElementsFromPoint(coords){ + return this.getElementsFromInternalPoint(this._getInternalCoordinates(coords)); + } + + display(flag = true) { + this._screen.style.display = flag ? '' : 'none'; + } + + displayFrame(flag = true) { + this.iframe.style.display = flag ? '' : 'none'; + } + + scale = () => { + if (!this._parentElement) return; + let s = 1; + const { height, width } = getState(); + const { offsetWidth, offsetHeight } = this._parentElement; + + s = Math.min(offsetWidth / width, offsetHeight / height); + if (s > 1) { + s = 1; + } else { + s = Math.round(s * 1e3) / 1e3; + } + + this._screen.style.transform = `scale(${ s }) translate(-50%, -50%)`; + this._screen.style.width = width + 'px'; + this._screen.style.height = height + 'px'; + } + + clean() { + window.removeEventListener('resize', this.scale); + } +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/cursor.css b/frontend/app/player/MessageDistributor/StatedScreen/Screen/cursor.css new file mode 100644 index 000000000..8853a7a4a --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/cursor.css @@ -0,0 +1,28 @@ +.cursor { + display: block; + position: absolute; + width: 20px; + height: 20px; + /*border-radius: 20px;*/ + background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M302.189 329.126H196.105l55.831 135.993c3.889 9.428-.555 19.999-9.444 23.999l-49.165 21.427c-9.165 4-19.443-.571-23.332-9.714l-53.053-129.136-86.664 89.138C18.729 472.71 0 463.554 0 447.977V18.299C0 1.899 19.921-6.096 30.277 5.443l284.412 292.542c11.472 11.179 3.007 31.141-12.5 31.141z"/></svg>'); + background-repeat: no-repeat; + /*border: 4px solid rgba(255, 255, 255, .8); + margin-left: -10px; + margin-top: -10px;*/ +} + +/*@keyframes click { + +}*/ + +/*.click { + display: block; + position: absolute; + width: 20px; + height: 20px; + background: yellow; + border-radius: 20px; + border: 4px solid rgba(255, 255, 255, .8); + margin-left: -10px; + margin-top: -10px; +}*/ \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/index.js b/frontend/app/player/MessageDistributor/StatedScreen/Screen/index.js new file mode 100644 index 000000000..96f315c68 --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/index.js @@ -0,0 +1,2 @@ +export { default } from './Screen'; +export * from './Screen'; diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/marker.css b/frontend/app/player/MessageDistributor/StatedScreen/Screen/marker.css new file mode 100644 index 000000000..63b93f1f5 --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/marker.css @@ -0,0 +1,35 @@ +.marker { + display: none; + position: absolute; + background: rgba(40, 40, 100, .5); +} +.marker div { + position: absolute; + background-image: linear-gradient(45deg, #00d 25%, #fff 25%, #fff 75%, #00d 75%, #00d), + linear-gradient(45deg, #00d 25%, #fff 25%, #fff 75%, #00d 75%, #00d); + background-size: 20px 20px; +} +.markerL { + left: -1px; + top: -100vh; + bottom: -100vh; + width: 2px; +} +.markerT { + top: -1px; + left: -100vw; + right: -100vw; + height: 2px; +} +.markerR { + right: 1px; + top: -100vh; + bottom: -100vh; + width: 2px; +} +.markerB { + bottom: 1px; + left: -100vw; + right: -100vw; + height: 2px; +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/screen.css b/frontend/app/player/MessageDistributor/StatedScreen/Screen/screen.css new file mode 100644 index 000000000..c4ff803b7 --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/screen.css @@ -0,0 +1,20 @@ +.screen { + overflow: hidden; + position: absolute; + transform-origin: left top; + top: 50%; + left: 50%; + box-shadow: 0px 0px 15px 0px rgba(0,0,0,0.1); +} +.iframe { + position: absolute; + border: none; +} +.overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 10; +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/StatedScreen.js b/frontend/app/player/MessageDistributor/StatedScreen/StatedScreen.js new file mode 100644 index 000000000..3a46ec51c --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/StatedScreen.js @@ -0,0 +1,41 @@ +import Screen, { INITIAL_STATE as SUPER_INITIAL_STATE } from './Screen'; +import { update, getState } from '../../store'; + +export const INITIAL_STATE = { + ...SUPER_INITIAL_STATE, + messagesLoading: false, + cssLoading: false, + disconnected: false, + userPageLoading: false, +} + +export default class StatedScreen extends Screen { + + setMessagesLoading(messagesLoading) { + this.display(!messagesLoading); + update({ messagesLoading }); + } + + setCSSLoading(cssLoading) { + this.displayFrame(!cssLoading); + update({ cssLoading }); + } + + setDisconnected(disconnected) { + if (!getState().live) return; //? + this.display(!disconnected); + update({ disconnected }); + } + + setUserPageLoading(userPageLoading) { + this.display(!userPageLoading); + update({ userPageLoading }); + } + + setSize({ height, width }) { + this.iframe.style.width = width + 'px'; + this.iframe.style.height = height + 'px'; + update({ width, height }); + this.scale(); + } +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/StatedScreen/index.js b/frontend/app/player/MessageDistributor/StatedScreen/index.js new file mode 100644 index 000000000..0955acffb --- /dev/null +++ b/frontend/app/player/MessageDistributor/StatedScreen/index.js @@ -0,0 +1,2 @@ +export { default } from './StatedScreen'; +export * from './StatedScreen'; \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/Timed.js b/frontend/app/player/MessageDistributor/Timed.js new file mode 100644 index 000000000..9c0c28b52 --- /dev/null +++ b/frontend/app/player/MessageDistributor/Timed.js @@ -0,0 +1,5 @@ +// @flow +import type { Message } from './messages'; + +export type Timed = { +time: number }; +export type TimedMessage = Timed & Message; diff --git a/frontend/app/player/MessageDistributor/index.js b/frontend/app/player/MessageDistributor/index.js new file mode 100644 index 000000000..8502aee50 --- /dev/null +++ b/frontend/app/player/MessageDistributor/index.js @@ -0,0 +1,2 @@ +export { default } from './MessageDistributor'; +export * from './MessageDistributor'; diff --git a/frontend/app/player/MessageDistributor/managers/ActivityManager.js b/frontend/app/player/MessageDistributor/managers/ActivityManager.js new file mode 100644 index 000000000..9881ecac1 --- /dev/null +++ b/frontend/app/player/MessageDistributor/managers/ActivityManager.js @@ -0,0 +1,43 @@ +import ListWalker from './ListWalker'; + + +class SkipInterval { + constructor({ start = 0, end = 0 }) { + this.start = start; + this.end = end; + } + get time(): number { + return this.start; + } + contains(ts) { + return ts > this.start && ts < this.end; + } +} + + +export default class ActivityManager extends ListWalker<SkipInterval> { + #endTime: number = 0; + #minInterval: number = 0; + #lastActivity: number = 0; + constructor(duration: number) { + super(); + this.#endTime = duration; + this.#minInterval = duration * 0.1; + } + + updateAcctivity(time: number) { + if (time - this.#lastActivity >= this.#minInterval) { + this.add(new SkipInterval({ start: this.#lastActivity, end: time })); + } + this.#lastActivity = time; + } + + end() { + if (this.#endTime - this.#lastActivity >= this.#minInterval) { + this.add(new SkipInterval({ start: this.#lastActivity, end: this.#endTime })); + } + + } + + +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/managers/DOMManager.js b/frontend/app/player/MessageDistributor/managers/DOMManager.js new file mode 100644 index 000000000..d2faf4b68 --- /dev/null +++ b/frontend/app/player/MessageDistributor/managers/DOMManager.js @@ -0,0 +1,283 @@ +//@flow +import type StatedScreen from '../StatedScreen'; +import type { Message, SetNodeScroll, CreateElementNode } from '../messages'; +import type { TimedMessage } from '../Timed'; + +import logger from 'App/logger'; +import StylesManager from './StylesManager'; +import ListWalker from './ListWalker'; + +const IGNORED_ATTRS = [ "autocomplete", "name" ]; + +const ATTR_NAME_REGEXP = /([^\t\n\f \/>"'=]+)/; // regexp costs ~ + +export default class DOMManager extends ListWalker<TimedMessage> { + #isMobile: boolean; + #screen: StatedScreen; + // #prop compiles to method that costs mor than strict property call. + _nl: Array<Element> = []; + _isLink: Array<boolean> = []; // Optimisations + _bodyId: number = -1; + _postponedBodyMessage: ?CreateElementNode = null; + #nodeScrollManagers: Array<ListWalker<SetNodeScroll>> = []; + + #stylesManager: StylesManager; + + #startTime: number; + + constructor(screen: StatedScreen, isMobile: boolean, startTime: number) { + super(); + this.#startTime = startTime; + this.#isMobile = isMobile; + this.#screen = screen; + this.#stylesManager = new StylesManager(screen); + } + + get time(): number { + return this.#startTime; + } + + add(m: TimedMessage): void { + switch (m.tp) { + case "set_node_scroll": + if (!this.#nodeScrollManagers[ m.id ]) { + this.#nodeScrollManagers[ m.id ] = new ListWalker(); + } + this.#nodeScrollManagers[ m.id ].add(m); + return; + //case "css_insert_rule": // || //set_css_data ??? + //case "css_delete_rule": + // (m.tp === "set_node_attribute" && this._isLink[ m.id ] && m.key === "href")) { + // this.#stylesManager.add(m); + // return; + default: + if (m.tp === "create_element_node") { + switch(m.tag) { + case "LINK": + this._isLink[ m.id ] = true; + break; + case "BODY": + this._bodyId = m.id; // Can be several body nodes at one document session? + break; + } + } else if (m.tp === "set_node_attribute" && + (IGNORED_ATTRS.includes(m.key) || !ATTR_NAME_REGEXP.test(m.key))) { + logger.log("Ignorring message: ", m) + return; // Ignoring... + } + super.add(m); + } + + } + + _removeBodyScroll(id: number): void { + if (this.#isMobile && this._bodyId === id) { + this._nl[ id ].style.overflow = "hidden"; + } + } + + // May be make it as a message on message add? + _removeAutocomplete({ id, tag }: { id: number, tag: string }): boolean { + const node = this._nl[ id ]; + if ([ "FORM", "TEXTAREA", "SELECT" ].includes(tag)) { + node.setAttribute("autocomplete", "off"); + return true; + } + if (tag === "INPUT") { + node.setAttribute("autocomplete", "new-password"); + return true; + } + return false; + } + + // type = NodeMessage ? + _insertNode({ parentID, id, index }: { parentID: number, id: number, index: number }): void { + if (!this._nl[ id ]) { + logger.error("Insert error. Node not found", id); + return; + } + if (!this._nl[ parentID ]) { + logger.error("Insert error. Parent node not found", parentID); + return; + } + // WHAT if text info contains some rules and the ordering is just wrong??? + if ((this._nl[ parentID ] instanceof HTMLStyleElement) && // TODO: correct ordering OR filter in tracker + this._nl[ parentID ].sheet && + this._nl[ parentID ].sheet.cssRules && + this._nl[ parentID ].sheet.cssRules.length > 0) { + logger.log("Trying to insert child to style tag with virtual rules: ", this._nl[ parentID ], this._nl[ id ]); + return; + } + + const childNodes = this._nl[ parentID ].childNodes; + if (!childNodes) { + logger.error("Node has no childNodes", this._nl[ parentID ]); + return; + } + this._nl[ parentID ] + .insertBefore(this._nl[ id ], childNodes[ index ]); + } + + #applyMessage: (Message => void) = msg => { + let node; + switch (msg.tp) { + case "create_document": + this.#screen.document.open(); + this.#screen.document.write(`${ msg.doctype || "<!DOCTYPE html>" }<html></html>`); + this.#screen.document.close(); + const fRoot = this.#screen.document.documentElement; + fRoot.innerText = ''; + //this._nl[ 0 ] = fRoot; // vs + this._nl = [ fRoot ]; + + // the last load event I can control + //if (this.document.fonts) { + // this.document.fonts.onloadingerror = () => this.marker.redraw(); + // this.document.fonts.onloadingdone = () => this.marker.redraw(); + //} + + //this.#screen.setDisconnected(false); + this.#stylesManager.reset(); + break; + case "create_text_node": + this._nl[ msg.id ] = document.createTextNode(''); + this._insertNode(msg); + break; + case "create_element_node": + if (msg.svg) { + this._nl[ msg.id ] = document.createElementNS('http://www.w3.org/2000/svg', msg.tag); + } else { + this._nl[ msg.id ] = document.createElement(msg.tag); + } + if (this._bodyId === msg.id) { + this._postponedBodyMessage = msg; + } else { + this._insertNode(msg); + } + this._removeBodyScroll(msg.id); + this._removeAutocomplete(msg); + break; + case "move_node": + this._insertNode(msg); + break; + case "remove_node": + if (!this._nl[ msg.id ]) { logger.error("Node not found", msg); break; } + if (!this._nl[ msg.id ].parentElement) { logger.error("Parent node not found", msg); break; } + this._nl[ msg.id ].parentElement.removeChild(this._nl[ msg.id ]); + break; + case "set_node_attribute": + let { id, name, value } = msg; + node = this._nl[ id ]; + if (!node) { logger.error("Node not found", msg); break; } + if (this._isLink[ id ] && name === "href") { + if (value.startsWith(window.ENV.ASSETS_HOST)) { // Hack for queries in rewrited urls + value = value.replace("?", "%3F"); + } + this.#stylesManager.setStyleHandlers(node, value); + } + try { + node.setAttribute(name, value); + } catch(e) { + logger.error(e, msg); + } + this._removeBodyScroll(msg.id); + break; + case "remove_node_attribute": + if (!this._nl[ msg.id ]) { logger.error("Node not found", msg); break; } + try { + this._nl[ msg.id ].removeAttribute(msg.name); + } catch(e) { + logger.error(e, msg); + } + break; + case "set_input_value": + if (!this._nl[ msg.id ]) { logger.error("Node not found", msg); break; } + const val = msg.mask > 0 ? '*'.repeat(msg.mask) : msg.value; + this._nl[ msg.id ].value = val; + break; + case "set_input_checked": + if (!this._nl[ msg.id ]) { logger.error("Node not found", msg); break; } + this._nl[ msg.id ].checked = msg.checked; + break; + case "set_node_data": + case "set_css_data": + if (!this._nl[ msg.id ]) { logger.error("Node not found", msg); break; } + this._nl[ msg.id ].data = msg.data; + break; + case "css_insert_rule": + if (!this._nl[ msg.id ]) { logger.error("Node not found", msg); break; } + if (!(this._nl[ msg.id ] instanceof HTMLStyleElement) // link or null + || this._nl[ msg.id ].sheet == null) { + logger.warn("Non-style node in CSS rules message (or sheet is null)", msg); + + // prev version fallback (TODO: delete on 30.10.20) + let styleSheet = this.#screen.document.styleSheets[ msg.id ]; + if (!styleSheet) { + styleSheet = this.#screen.document.styleSheets[0]; + } + if (!styleSheet) { + logger.log("Old-fasion insert rule: No stylesheet found;", msg); + break; + } + try { + styleSheet.insertRule(msg.rule, msg.index); + } catch(e) { + logger.log("Old-fasion insert rule:", e, msg); + styleSheet.insertRule(msg.rule); + } + // + + break; + } + try { + this._nl[ msg.id ].sheet.insertRule(msg.rule, msg.index) + } catch (e) { + logger.warn(e, msg) + this._nl[ msg.id ].sheet.insertRule(msg.rule) + } + break; + case "css_delete_rule": + if (!this._nl[ msg.id ]) { logger.error("Node not found", msg); break; } + if (!this._nl[ msg.id ] instanceof HTMLStyleElement) { // link or null + logger.warn("Non-style node in CSS rules message", msg); + break; + } + try { + this._nl[ msg.id ].sheet.deleteRule(msg.rule, msg.index) + } catch (e) { + logger.warn(e, msg) + } + break; + //not sure what to do with this one + //case "disconnected": + //setTimeout(() => { + // if last one + //if (this.msgs[ this.msgs.length - 1 ] === msg) { + // this.setDisconnected(true); + // } + //}, 10000); + //break; + } + } + + moveReady(t: number): Promise<void> { + this.moveApply(t, this.#applyMessage); // This function autoresets pointer if necessary (better name?) + this.#nodeScrollManagers.forEach(manager => { + const msg = manager.moveToLast(t); // TODO: reset (?) + if (!!msg && !!this._nl[msg.id]) { + this._nl[msg.id].scrollLeft = msg.x; + this._nl[msg.id].scrollTop = msg.y; + } + }); + + /* Mount body as late as possible */ + if (this._postponedBodyMessage != null) { + this._insertNode(this._postponedBodyMessage) + this._postponedBodyMessage = null; + } + + // Thinkabout (read): css preload + // What if we go back before it is ready? We'll have two handlres? + return this.#stylesManager.moveReady(t); + } +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/managers/ListWalker.js b/frontend/app/player/MessageDistributor/managers/ListWalker.js new file mode 100644 index 000000000..0354a365c --- /dev/null +++ b/frontend/app/player/MessageDistributor/managers/ListWalker.js @@ -0,0 +1,150 @@ +//@flow + +import type { Timed } from '../Timed'; + +export default class ListWalker<T: Timed> { + // Optimisation: #prop compiles to method that costs mor than strict property call. + _p = 0; + _list: Array<T>; + constructor(list: Array<T> = []) { + this._list = list; + } + + add(m: T): void { + return this.append(m); + } + + append(m: T): void { + if (this.length > 0 && m.time < this.last.time) { + console.error("Trying to append message with the less time then the list tail: ", m); + } + this._list.push(m); + } + + reset(): void { + this._p = 0; + } + + sort(comparator): void { + this._list.sort((m1,m2) => comparator(m1,m2) || (m1._index - m2._index) ); // indexes for sort stability (TODO: fix types???) + } + + forEach(f):void { + this._list.forEach(f); + } + + // set pointer(p: number): void { + // if (p >= this.length || p < 0) { + // // console.error("Trying to set wrong pointer") + // return; + // } + // this._p = p; + // } + + get last(): T | null { + if (this._list.length === 0) { + return null; + } + return this._list[ this._list.length - 1 ]; + } + + get current(): T | null { + if (this._p === 0) { + return null; + } + return this._list[ this._p - 1 ]; + } + + get timeNow(): number { + if (this._p === 0) { + return 0; + } + return this._list[ this._p - 1 ].time; + } + + get length(): number { + return this._list.length; + } + + get maxTime(): number { + if (this.length === 0) { + return 0; + } + return this._list[ this.length - 1 ].time; + } + get minTime(): number { + if (this.length === 0) { + return 0; + } + return this._list[ 0 ].time; + } + + get listNow(): Array<T> { + return this._list.slice(0, this._p); + } + + get list(): Array<T> { + return this._list; + } + + get count(): number { + return this.length; + } + + get countNow(): number { + return this._p; + } + + /* + Returns last message with the time <= t. + Assumed that the current message is already handled so + if pointer doesn't cahnge <undefined> is returned. + */ + moveToLast(t: number, index: ?number): ?T { + let key = "time"; //TODO + let val = t; + if (index != null) { + key = "_index"; + val = index; + } + + let changed = false; + while (this._p < this.length && this._list[this._p][key] <= val) { + this._p++; + changed = true; + } + while (this._p > 0 && this._list[ this._p - 1 ][key] > val) { + this._p--; + changed = true; + } + return changed ? this._list[ this._p - 1 ] : undefined; + } + + // moveToLastByIndex(i: number): ?T { + // let changed = false; + // while (!!this._list[this._p] && this._list[this._p]._index <= i) { + // this._p++; + // changed = true; + // } + // while (this._p > 0 && this._list[ this._p - 1 ]._index > i) { + // this._p--; + // changed = true; + // } + // return changed ? this._list[ this._p - 1 ] : undefined; + // } + + moveApply(t: number, fn: T => void): void { + // Applying only in increment order for now + if (t < this.timeNow) { + this.reset(); + } + + while (!!this._list[this._p] && this._list[this._p].time <= t) { + fn(this._list[ this._p++ ]); + } + //while (this._p > 0 && this._list[ this._p - 1 ].time > t) { + // fnBack(this._list[ --this._p ]); + //} + } + +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/managers/MouseManager.js b/frontend/app/player/MessageDistributor/managers/MouseManager.js new file mode 100644 index 000000000..dc5fbe66f --- /dev/null +++ b/frontend/app/player/MessageDistributor/managers/MouseManager.js @@ -0,0 +1,43 @@ +//@flow +import type StatedScreen from '../StatedScreen'; +import type { MouseMove } from '../messages'; +import type { Timed } from '../Timed'; + +import ListWalker from './ListWalker'; + +type MouseMoveTimed = MouseMove & Timed; + +const HOVER_CLASS = "-openreplay-hover"; + +export default class MouseManager extends ListWalker<MouseMoveTimed> { + #screen: StatedScreen; + #hoverElements: Array<Element> = []; + + constructor(screen: StatedScreen): void { + super(); + this.#screen = screen; + } + + _updateHover(): void { + const curHoverElements = this.#screen.cursor.getTargets(); + const diffAdd = curHoverElements.filter(elem => !this.#hoverElements.includes(elem)); + const diffRemove = this.#hoverElements.filter(elem => !curHoverElements.includes(elem)); + this.#hoverElements = curHoverElements; + diffAdd.forEach(elem => elem.classList.add(HOVER_CLASS)); + diffRemove.forEach(elem => elem.classList.remove(HOVER_CLASS)); + } + + reset(): void { + this.#hoverElements = []; + } + + move(t: number) { + const lastMouseMove = this.moveToLast(t); + if (!!lastMouseMove){ + this.#screen.cursor.move(lastMouseMove); + this._updateHover(); + } + } + + +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/managers/PagesManager.js b/frontend/app/player/MessageDistributor/managers/PagesManager.js new file mode 100644 index 000000000..d5816c57c --- /dev/null +++ b/frontend/app/player/MessageDistributor/managers/PagesManager.js @@ -0,0 +1,53 @@ +//@flow +import type StatedScreen from '../StatedScreen'; +import type { Message } from '../messages'; +import type { Timed } from '../Timed'; + +import ListWalker from './ListWalker'; +import DOMManager from './DOMManager'; + +type TimedMessage = Timed & Message; + +export default class PagesManager extends ListWalker<TimedMessage> { + #currentPage: DOMManager; + + #isMobile: boolean; + #screen: StatedScreen; + + constructor(screen: StatedScreen, isMobile: boolean): void { + super(); + this.#screen = screen; + this.#isMobile = isMobile; + } + + /* + Assumed that messages added in a correct time sequence. + */ + add(m: TimedMessage): void { + if (m.tp === "create_document") { + super.add(new DOMManager(this.#screen, this.#isMobile, m.time)) + } + if (this.last === null) { + // Log wrong + return; + } + this.last.add(m); + } + + sort(comparator) { + this.forEach(page => page.sort(comparator)) + } + + moveReady(t: number): Promise<void> { + const requiredPage = this.moveToLast(t); + if (!!requiredPage) { + this.#currentPage = requiredPage; + this.#currentPage.reset(); // Otherwise it won't apply create_document + } + if (!!this.#currentPage) { + return this.#currentPage.moveReady(t); + } + return Promise.resolve(); + } + +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/managers/PerformanceTrackManager.js b/frontend/app/player/MessageDistributor/managers/PerformanceTrackManager.js new file mode 100644 index 000000000..005b7004a --- /dev/null +++ b/frontend/app/player/MessageDistributor/managers/PerformanceTrackManager.js @@ -0,0 +1,104 @@ +// @flow + +import type { PerformanceTrack, SetPageVisibility } from '../messages'; +import type { Timed } from '../Timed'; + +import ListWalker from './ListWalker'; + +type TimedPerformanceTrack = Timed & PerformanceTrack; +type TimedSetPageVisibility = Timed & SetPageVisibility; + +type PerformanceChartPoint = { + time: number, + usedHeap: number, + totalHeap: number, + fps: ?number, + cpu: ?number, + nodesCount: number, +} + +export default class PerformanceTrackManager extends ListWalker<TimedPerformanceTrack> { + #chart: Array<PerformanceChartPoint> = []; + #isHidden: boolean = false; + #timeCorrection: number = 0; + #heapAvaliable: boolean = false; + #fpsAvaliable: boolean = false; + #cpuAvaliable: boolean = false; + #prevTime: ?number = null; + #prevNodesCount: number = 0; + + + add(msg: TimedPerformanceTrack):void { + let fps = null; + let cpu = null; + if (!this.#isHidden && this.#prevTime != null) { + let timePassed = msg.time - this.#prevTime + this.#timeCorrection; + + if (timePassed > 0 && msg.frames >= 0) { + if (msg.frames > 0) { this.#fpsAvaliable = true; } + fps = msg.frames*1e3/timePassed; // Multiply by 1e3 as time in ms; + fps = Math.min(fps,60); // What if 120? TODO: alert if more than 60 + if (this.#chart.length === 1) { + this.#chart[0].fps = fps; + } + } + + if (timePassed > 0 && msg.ticks >= 0) { + this.#cpuAvaliable = true; + let tickRate = msg.ticks * 30 / timePassed; + if (tickRate > 1) { + tickRate = 1; + } + cpu = Math.round(100 - tickRate*100); + if (this.#chart.length === 1) { + this.#chart[0].cpu = cpu; + } + } + } + + this.#prevTime = msg.time; + this.#timeCorrection = 0 + + this.#heapAvaliable = this.#heapAvaliable || msg.usedJSHeapSize > 0; + this.#chart.push({ + usedHeap: msg.usedJSHeapSize, + totalHeap: msg.totalJSHeapSize, + fps, + cpu, + time: msg.time, + nodesCount: this.#prevNodesCount, + }); + super.add(msg); + } + + setCurrentNodesCount(count: number) { + this.#prevNodesCount = count; + if (this.#chart.length > 0) { + this.#chart[ this.#chart.length - 1 ].nodesCount = count; + } + } + + handleVisibility(msg: TimedSetPageVisibility):void { + if (!this.#isHidden && msg.hidden && this.#prevTime != null) { + this.#timeCorrection = msg.time - this.#prevTime; + } + if (this.#isHidden && !msg.hidden) { + this.#prevTime = msg.time; + } + this.#isHidden = msg.hidden; + } + + get chartData(): Array<PerformanceChartPoint> { + return this.#chart; + } + + get avaliability(): { cpu: boolean, fps: boolean, heap: boolean } { + return { + cpu: this.#cpuAvaliable, + fps: this.#fpsAvaliable, + heap: this.#heapAvaliable, + nodes: true, + } + } + +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/managers/StylesManager.js b/frontend/app/player/MessageDistributor/managers/StylesManager.js new file mode 100644 index 000000000..9ae18fc83 --- /dev/null +++ b/frontend/app/player/MessageDistributor/managers/StylesManager.js @@ -0,0 +1,92 @@ +// @flow + +import type StatedScreen from '../StatedScreen'; +import type { CssInsertRule, CssDeleteRule } from '../messages'; +import type { Timed } from '../Timed'; + +type CSSRuleMessage = CssInsertRule | CssDeleteRule; +type TimedCSSRuleMessage = Timed & CSSRuleMessage; + +import logger from 'App/logger'; +import ListWalker from './ListWalker'; + +export default class StylesManager extends ListWalker<TimedCSSRuleMessage> { + #screen: StatedScreen; + _linkLoadingCount: number = 0; + _linkLoadPromises: Array<Promise<void>> = []; + _skipCSSLinks: Array<string> = []; // should be common for all pages + + constructor(screen: StatedScreen) { + super(); + this.#screen = screen; + } + + reset():void { + super.reset(); + this._linkLoadingCount = 0; + this._linkLoadPromises = []; + + //cancel all promises? tothinkaboutit + } + + setStyleHandlers(node: HTMLLinkElement, value: string): void { + let timeoutId; + const promise = new Promise((resolve) => { + if (this._skipCSSLinks.includes(value)) resolve(); + this._linkLoadingCount++; + this.#screen.setCSSLoading(true); + const setSkipAndResolve = () => { + this._skipCSSLinks.push(value); // watch out + resolve(); + } + timeoutId = setTimeout(setSkipAndResolve, 4000); + + node.onload = resolve; + node.onerror = setSkipAndResolve; + }).then(() => { + node.onload = null; + node.onerror = null; + clearTimeout(timeoutId); + this._linkLoadingCount--; + if (this._linkLoadingCount === 0) { + this.#screen.setCSSLoading(false); + } + }); + this._linkLoadPromises.push(promise); + } + + #manageRule = (msg: CSSRuleMessage):void => { + // if (msg.tp === "css_insert_rule") { + // let styleSheet = this.#screen.document.styleSheets[ msg.stylesheetID ]; + // if (!styleSheet) { + // logger.log("No stylesheet with corresponding ID found: ", msg) + // styleSheet = this.#screen.document.styleSheets[0]; + // if (!styleSheet) { + // return; + // } + // } + // try { + // styleSheet.insertRule(msg.rule, msg.index); + // } catch (e) { + // logger.log(e, msg) + // //const index = Math.min(msg.index, styleSheet.cssRules.length); + // styleSheet.insertRule(msg.rule, styleSheet.cssRules.length); + // //styleSheet.ownerNode.innerHTML += msg.rule; + // } + // } + // if (msg.tp === "css_delete_rule") { + // // console.warn('Warning: STYLESHEET_DELETE_RULE msg') + // const styleSheet = this.#screen.document.styleSheets[msg.stylesheetID]; + // if (!styleSheet) { + // logger.log("No stylesheet with corresponding ID found: ", msg) + // return; + // } + // styleSheet.deleteRule(msg.index); + // } + } + + moveReady(t: number): Promise<void> { + return Promise.all(this._linkLoadPromises) + .then(() => this.moveApply(t, this.#manageRule)); + } +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/managers/WindowNodeCounter.js b/frontend/app/player/MessageDistributor/managers/WindowNodeCounter.js new file mode 100644 index 000000000..d3e0fd394 --- /dev/null +++ b/frontend/app/player/MessageDistributor/managers/WindowNodeCounter.js @@ -0,0 +1,95 @@ +// @flow + +class NodeCounter { + _id: number; + _parent: NodeCount | null = null; + _count: number = 0; + _children: Array<NodeCounter> = []; + + + bubbleCount(count: number) { + this._count += count; + if (this._parent != null) { + this._parent.bubbleCount(count); + } + } + + newChild(): NodeCounter { + const child = new NodeCounter(); + this._children.push(child); + child._parent = this; + this.bubbleCount(1); + return child + } + + removeChild(child: NodeCounter) { + this._children = this._children.filter(c => c != child); + this.bubbleCount(-(child._count + 1)); + } + + removeNode() { + this._parent.removeChild(this); + this._parent = null; + } + + moveNode(newParent: NodeCounter) { + this.removeNode(); + newParent._children.push(this); + this._parent = newParent; + newParent.bubbleCount(this._count + 1); + } + + get count() { + return this._count; + } +} + + +export default class WindowNodeCounter { + _root: NodeCounter = new NodeCounter(); + _nodes: Array<NodeCounter> = [ this._root ]; + + + reset() { + this._root = new NodeCounter(); + this._nodes = [ this._root ]; + } + + addNode(id: number, parentID: number) { + if (!this._nodes[ parentID ]) { + console.error(`Wrong! Node with id ${ parentID } (parentId) not found.`); + return; + } + if (!!this._nodes[ id ]) { + console.error(`Wrong! Node with id ${ id } already exists.`); + return; + } + this._nodes[id] = this._nodes[ parentID ].newChild(); + } + + removeNode(id: number) { + if (!this._nodes[ id ]) { + // Might be text node + //console.error(`Wrong! Node with id ${ id } not found.`); + return; + } + this._nodes[ id ].removeNode(); + } + + moveNode(id: number, parentId: number) { + if (!this._nodes[ id ]) { + console.error(`Wrong! Node with id ${ id } not found.`); + return; + } + if (!this._nodes[ parentId ]) { + console.error(`Wrong! Node with id ${ parentId } (parentId) not found.`); + return; + } + this._nodes[ id ].moveNode(this._nodes[ parentId ]); + } + + get count() { + return this._root.count; + } + +} \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/messages.js b/frontend/app/player/MessageDistributor/messages.js new file mode 100644 index 000000000..6ff087eaf --- /dev/null +++ b/frontend/app/player/MessageDistributor/messages.js @@ -0,0 +1,596 @@ +// Auto-generated, do not edit + +import { readUint, readInt, readString, readBoolean } from './readPrimitives' + + +export type Timestamp = { + tp: "timestamp", + timestamp: number, +} + +export type SessionDisconnect = { + tp: "session_disconnect", + timestamp: number, +} + +export type SetPageLocation = { + tp: "set_page_location", + url: string, + referrer: string, + navigationStart: number, +} + +export type SetViewportSize = { + tp: "set_viewport_size", + width: number, + height: number, +} + +export type SetViewportScroll = { + tp: "set_viewport_scroll", + x: number, + y: number, +} + +export type CreateDocument = { + tp: "create_document", + +} + +export type CreateElementNode = { + tp: "create_element_node", + id: number, + parentID: number, + index: number, + tag: string, + svg: boolean, +} + +export type CreateTextNode = { + tp: "create_text_node", + id: number, + parentID: number, + index: number, +} + +export type MoveNode = { + tp: "move_node", + id: number, + parentID: number, + index: number, +} + +export type RemoveNode = { + tp: "remove_node", + id: number, +} + +export type SetNodeAttribute = { + tp: "set_node_attribute", + id: number, + name: string, + value: string, +} + +export type RemoveNodeAttribute = { + tp: "remove_node_attribute", + id: number, + name: string, +} + +export type SetNodeData = { + tp: "set_node_data", + id: number, + data: string, +} + +export type SetCssData = { + tp: "set_css_data", + id: number, + data: string, +} + +export type SetNodeScroll = { + tp: "set_node_scroll", + id: number, + x: number, + y: number, +} + +export type SetInputValue = { + tp: "set_input_value", + id: number, + value: string, + mask: number, +} + +export type SetInputChecked = { + tp: "set_input_checked", + id: number, + checked: boolean, +} + +export type MouseMove = { + tp: "mouse_move", + x: number, + y: number, +} + +export type ConsoleLog = { + tp: "console_log", + level: string, + value: string, +} + +export type PerformanceTrack = { + tp: "performance_track", + frames: number, + ticks: number, + totalJSHeapSize: number, + usedJSHeapSize: number, +} + +export type ConnectionInformation = { + tp: "connection_information", + downlink: number, + type: string, +} + +export type SetPageVisibility = { + tp: "set_page_visibility", + hidden: boolean, +} + +export type CssInsertRule = { + tp: "css_insert_rule", + id: number, + rule: string, + index: number, +} + +export type CssDeleteRule = { + tp: "css_delete_rule", + id: number, + index: number, +} + +export type Fetch = { + tp: "fetch", + method: string, + url: string, + request: string, + response: string, + status: number, + timestamp: number, + duration: number, +} + +export type Profiler = { + tp: "profiler", + name: string, + duration: number, + args: string, + result: string, +} + +export type OTable = { + tp: "o_table", + key: string, + value: string, +} + +export type Redux = { + tp: "redux", + action: string, + state: string, + duration: number, +} + +export type Vuex = { + tp: "vuex", + mutation: string, + state: string, +} + +export type MobX = { + tp: "mob_x", + type: string, + payload: string, +} + +export type NgRx = { + tp: "ng_rx", + action: string, + state: string, + duration: number, +} + +export type GraphQl = { + tp: "graph_ql", + operationKind: string, + operationName: string, + variables: string, + response: string, +} + +export type LongTask = { + tp: "long_task", + timestamp: number, + duration: number, + context: number, + containerType: number, + containerSrc: string, + containerId: string, + containerName: string, +} + +export type TechnicalInfo = { + tp: "technical_info", + type: string, + value: string, +} + +export type IosSessionStart = { + tp: "ios_session_start", + timestamp: number, + projectID: number, + trackerVersion: string, + revID: string, + userUUID: string, + userOS: string, + userOSVersion: string, + userDevice: string, + userDeviceType: string, + userCountry: string, +} + +export type IosCustomEvent = { + tp: "ios_custom_event", + timestamp: number, + length: number, + name: string, + payload: string, +} + +export type IosClickEvent = { + tp: "ios_click_event", + timestamp: number, + length: number, + label: string, + x: number, + y: number, +} + +export type IosPerformanceEvent = { + tp: "ios_performance_event", + timestamp: number, + length: number, + name: string, + value: number, +} + +export type IosLog = { + tp: "ios_log", + timestamp: number, + length: number, + severity: string, + content: string, +} + +export type IosNetworkCall = { + tp: "ios_network_call", + timestamp: number, + length: number, + duration: number, + headers: string, + body: string, + url: string, + success: boolean, + method: string, + status: number, +} + + +export type Message = Timestamp | SessionDisconnect | SetPageLocation | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetCssData | SetNodeScroll | SetInputValue | SetInputChecked | MouseMove | ConsoleLog | PerformanceTrack | ConnectionInformation | SetPageVisibility | CssInsertRule | CssDeleteRule | Fetch | Profiler | OTable | Redux | Vuex | MobX | NgRx | GraphQl | LongTask | TechnicalInfo | IosSessionStart | IosCustomEvent | IosClickEvent | IosPerformanceEvent | IosLog | IosNetworkCall; + +export default function (buf: Uint8Array, p: number): [Message, number] { + const msg = {}; + let r; + switch (buf[p++]) { + + case 0: + (msg:Timestamp).tp = "timestamp"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; + break; + + case 2: + (msg:SessionDisconnect).tp = "session_disconnect"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; + break; + + case 4: + (msg:SetPageLocation).tp = "set_page_location"; + r = readString(buf, p); msg.url = r[0]; p = r[1]; +r = readString(buf, p); msg.referrer = r[0]; p = r[1]; +r = readUint(buf, p); msg.navigationStart = r[0]; p = r[1]; + break; + + case 5: + (msg:SetViewportSize).tp = "set_viewport_size"; + r = readUint(buf, p); msg.width = r[0]; p = r[1]; +r = readUint(buf, p); msg.height = r[0]; p = r[1]; + break; + + case 6: + (msg:SetViewportScroll).tp = "set_viewport_scroll"; + r = readInt(buf, p); msg.x = r[0]; p = r[1]; +r = readInt(buf, p); msg.y = r[0]; p = r[1]; + break; + + case 7: + (msg:CreateDocument).tp = "create_document"; + + break; + + case 8: + (msg:CreateElementNode).tp = "create_element_node"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readUint(buf, p); msg.parentID = r[0]; p = r[1]; +r = readUint(buf, p); msg.index = r[0]; p = r[1]; +r = readString(buf, p); msg.tag = r[0]; p = r[1]; +r = readBoolean(buf, p); msg.svg = r[0]; p = r[1]; + break; + + case 9: + (msg:CreateTextNode).tp = "create_text_node"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readUint(buf, p); msg.parentID = r[0]; p = r[1]; +r = readUint(buf, p); msg.index = r[0]; p = r[1]; + break; + + case 10: + (msg:MoveNode).tp = "move_node"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readUint(buf, p); msg.parentID = r[0]; p = r[1]; +r = readUint(buf, p); msg.index = r[0]; p = r[1]; + break; + + case 11: + (msg:RemoveNode).tp = "remove_node"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; + break; + + case 12: + (msg:SetNodeAttribute).tp = "set_node_attribute"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readString(buf, p); msg.name = r[0]; p = r[1]; +r = readString(buf, p); msg.value = r[0]; p = r[1]; + break; + + case 13: + (msg:RemoveNodeAttribute).tp = "remove_node_attribute"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readString(buf, p); msg.name = r[0]; p = r[1]; + break; + + case 14: + (msg:SetNodeData).tp = "set_node_data"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readString(buf, p); msg.data = r[0]; p = r[1]; + break; + + case 15: + (msg:SetCssData).tp = "set_css_data"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readString(buf, p); msg.data = r[0]; p = r[1]; + break; + + case 16: + (msg:SetNodeScroll).tp = "set_node_scroll"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readInt(buf, p); msg.x = r[0]; p = r[1]; +r = readInt(buf, p); msg.y = r[0]; p = r[1]; + break; + + case 18: + (msg:SetInputValue).tp = "set_input_value"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readString(buf, p); msg.value = r[0]; p = r[1]; +r = readInt(buf, p); msg.mask = r[0]; p = r[1]; + break; + + case 19: + (msg:SetInputChecked).tp = "set_input_checked"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readBoolean(buf, p); msg.checked = r[0]; p = r[1]; + break; + + case 20: + (msg:MouseMove).tp = "mouse_move"; + r = readUint(buf, p); msg.x = r[0]; p = r[1]; +r = readUint(buf, p); msg.y = r[0]; p = r[1]; + break; + + case 22: + (msg:ConsoleLog).tp = "console_log"; + r = readString(buf, p); msg.level = r[0]; p = r[1]; +r = readString(buf, p); msg.value = r[0]; p = r[1]; + break; + + case 49: + (msg:PerformanceTrack).tp = "performance_track"; + r = readInt(buf, p); msg.frames = r[0]; p = r[1]; +r = readInt(buf, p); msg.ticks = r[0]; p = r[1]; +r = readUint(buf, p); msg.totalJSHeapSize = r[0]; p = r[1]; +r = readUint(buf, p); msg.usedJSHeapSize = r[0]; p = r[1]; + break; + + case 54: + (msg:ConnectionInformation).tp = "connection_information"; + r = readUint(buf, p); msg.downlink = r[0]; p = r[1]; +r = readString(buf, p); msg.type = r[0]; p = r[1]; + break; + + case 55: + (msg:SetPageVisibility).tp = "set_page_visibility"; + r = readBoolean(buf, p); msg.hidden = r[0]; p = r[1]; + break; + + case 37: + (msg:CssInsertRule).tp = "css_insert_rule"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readString(buf, p); msg.rule = r[0]; p = r[1]; +r = readUint(buf, p); msg.index = r[0]; p = r[1]; + break; + + case 38: + (msg:CssDeleteRule).tp = "css_delete_rule"; + r = readUint(buf, p); msg.id = r[0]; p = r[1]; +r = readUint(buf, p); msg.index = r[0]; p = r[1]; + break; + + case 39: + (msg:Fetch).tp = "fetch"; + r = readString(buf, p); msg.method = r[0]; p = r[1]; +r = readString(buf, p); msg.url = r[0]; p = r[1]; +r = readString(buf, p); msg.request = r[0]; p = r[1]; +r = readString(buf, p); msg.response = r[0]; p = r[1]; +r = readUint(buf, p); msg.status = r[0]; p = r[1]; +r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; +r = readUint(buf, p); msg.duration = r[0]; p = r[1]; + break; + + case 40: + (msg:Profiler).tp = "profiler"; + r = readString(buf, p); msg.name = r[0]; p = r[1]; +r = readUint(buf, p); msg.duration = r[0]; p = r[1]; +r = readString(buf, p); msg.args = r[0]; p = r[1]; +r = readString(buf, p); msg.result = r[0]; p = r[1]; + break; + + case 41: + (msg:OTable).tp = "o_table"; + r = readString(buf, p); msg.key = r[0]; p = r[1]; +r = readString(buf, p); msg.value = r[0]; p = r[1]; + break; + + case 44: + (msg:Redux).tp = "redux"; + r = readString(buf, p); msg.action = r[0]; p = r[1]; +r = readString(buf, p); msg.state = r[0]; p = r[1]; +r = readUint(buf, p); msg.duration = r[0]; p = r[1]; + break; + + case 45: + (msg:Vuex).tp = "vuex"; + r = readString(buf, p); msg.mutation = r[0]; p = r[1]; +r = readString(buf, p); msg.state = r[0]; p = r[1]; + break; + + case 46: + (msg:MobX).tp = "mob_x"; + r = readString(buf, p); msg.type = r[0]; p = r[1]; +r = readString(buf, p); msg.payload = r[0]; p = r[1]; + break; + + case 47: + (msg:NgRx).tp = "ng_rx"; + r = readString(buf, p); msg.action = r[0]; p = r[1]; +r = readString(buf, p); msg.state = r[0]; p = r[1]; +r = readUint(buf, p); msg.duration = r[0]; p = r[1]; + break; + + case 48: + (msg:GraphQl).tp = "graph_ql"; + r = readString(buf, p); msg.operationKind = r[0]; p = r[1]; +r = readString(buf, p); msg.operationName = r[0]; p = r[1]; +r = readString(buf, p); msg.variables = r[0]; p = r[1]; +r = readString(buf, p); msg.response = r[0]; p = r[1]; + break; + + case 59: + (msg:LongTask).tp = "long_task"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; +r = readUint(buf, p); msg.duration = r[0]; p = r[1]; +r = readUint(buf, p); msg.context = r[0]; p = r[1]; +r = readUint(buf, p); msg.containerType = r[0]; p = r[1]; +r = readString(buf, p); msg.containerSrc = r[0]; p = r[1]; +r = readString(buf, p); msg.containerId = r[0]; p = r[1]; +r = readString(buf, p); msg.containerName = r[0]; p = r[1]; + break; + + case 63: + (msg:TechnicalInfo).tp = "technical_info"; + r = readString(buf, p); msg.type = r[0]; p = r[1]; +r = readString(buf, p); msg.value = r[0]; p = r[1]; + break; + + case 90: + (msg:IosSessionStart).tp = "ios_session_start"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; +r = readUint(buf, p); msg.projectID = r[0]; p = r[1]; +r = readString(buf, p); msg.trackerVersion = r[0]; p = r[1]; +r = readString(buf, p); msg.revID = r[0]; p = r[1]; +r = readString(buf, p); msg.userUUID = r[0]; p = r[1]; +r = readString(buf, p); msg.userOS = r[0]; p = r[1]; +r = readString(buf, p); msg.userOSVersion = r[0]; p = r[1]; +r = readString(buf, p); msg.userDevice = r[0]; p = r[1]; +r = readString(buf, p); msg.userDeviceType = r[0]; p = r[1]; +r = readString(buf, p); msg.userCountry = r[0]; p = r[1]; + break; + + case 93: + (msg:IosCustomEvent).tp = "ios_custom_event"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; +r = readUint(buf, p); msg.length = r[0]; p = r[1]; +r = readString(buf, p); msg.name = r[0]; p = r[1]; +r = readString(buf, p); msg.payload = r[0]; p = r[1]; + break; + + case 100: + (msg:IosClickEvent).tp = "ios_click_event"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; +r = readUint(buf, p); msg.length = r[0]; p = r[1]; +r = readString(buf, p); msg.label = r[0]; p = r[1]; +r = readUint(buf, p); msg.x = r[0]; p = r[1]; +r = readUint(buf, p); msg.y = r[0]; p = r[1]; + break; + + case 102: + (msg:IosPerformanceEvent).tp = "ios_performance_event"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; +r = readUint(buf, p); msg.length = r[0]; p = r[1]; +r = readString(buf, p); msg.name = r[0]; p = r[1]; +r = readUint(buf, p); msg.value = r[0]; p = r[1]; + break; + + case 103: + (msg:IosLog).tp = "ios_log"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; +r = readUint(buf, p); msg.length = r[0]; p = r[1]; +r = readString(buf, p); msg.severity = r[0]; p = r[1]; +r = readString(buf, p); msg.content = r[0]; p = r[1]; + break; + + case 105: + (msg:IosNetworkCall).tp = "ios_network_call"; + r = readUint(buf, p); msg.timestamp = r[0]; p = r[1]; +r = readUint(buf, p); msg.length = r[0]; p = r[1]; +r = readUint(buf, p); msg.duration = r[0]; p = r[1]; +r = readString(buf, p); msg.headers = r[0]; p = r[1]; +r = readString(buf, p); msg.body = r[0]; p = r[1]; +r = readString(buf, p); msg.url = r[0]; p = r[1]; +r = readBoolean(buf, p); msg.success = r[0]; p = r[1]; +r = readString(buf, p); msg.method = r[0]; p = r[1]; +r = readUint(buf, p); msg.status = r[0]; p = r[1]; + break; + + default: + let len; + [ _, p ] = readUint(buf, p); + [ len, p ] = readUint(buf, p); + return [null, p + len] // skip + //throw `Unknown type (${buf[p-1]})`; + } + return [msg, p]; +} diff --git a/frontend/app/player/MessageDistributor/readPrimitives.js b/frontend/app/player/MessageDistributor/readPrimitives.js new file mode 100644 index 000000000..3279c08f3 --- /dev/null +++ b/frontend/app/player/MessageDistributor/readPrimitives.js @@ -0,0 +1,31 @@ +export function readUint(buf, p) { + var r = 0, s = 1, b; + do { + b = buf[p++]; + r += (b & 0x7F) * s; + s *= 128; + } while (b >= 0x80) + return [r, p]; +} + +export function readInt(buf, p) { + var r = readUint(buf, p); + if (r[0] % 2) { + r[0] = (r[0] + 1) / -2; + } else { + r[0] = r[0] / 2; + } + return r; +} + +export function readString(buf, p) { + var r = readUint(buf, p); + var f = r[1]; + r[1] += r[0]; + r[0] = new TextDecoder().decode(buf.subarray(f, r[1])); + return r; +} + +export function readBoolean(buf, p) { + return [!!buf[p], p+1]; +} diff --git a/frontend/app/player/Player.js b/frontend/app/player/Player.js new file mode 100644 index 000000000..a2e37d46e --- /dev/null +++ b/frontend/app/player/Player.js @@ -0,0 +1,185 @@ +import { goTo as listsGoTo } from './lists'; +import { update, getState } from './store'; +import MessageDistributor, { INITIAL_STATE as SUPER_INITIAL_STATE } from './MessageDistributor'; + +const fps = 60; +const performance = window.performance || { now: Date.now.bind(Date) }; +const requestAnimationFrame = + window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + (callback => window.setTimeout(() => { callback(performance.now()); }, 1000 / fps)); +const cancelAnimationFrame = + window.cancelAnimationFrame || + window.mozCancelAnimationFrame || + window.clearTimeout; + +const HIGHEST_SPEED = 3; + + +const SPEED_STORAGE_KEY = "__$player-speed$__"; +const SKIP_STORAGE_KEY = "__$player-skip$__"; +const storedSpeed = +localStorage.getItem(SPEED_STORAGE_KEY); +const initialSpeed = [1,2,3].includes(storedSpeed) ? storedSpeed : 1; +const initialSkip = !!localStorage.getItem(SKIP_STORAGE_KEY); + +export const INITIAL_STATE = { + ...SUPER_INITIAL_STATE, + time: 0, + playing: false, + completed: false, + endTime: 0, + live: false, + livePlay: false, +} + +export const INITIAL_NON_RESETABLE_STATE = { + skip: initialSkip, + speed: initialSpeed, +} + +export default class Player extends MessageDistributor { + _animationFrameRequestId = null; + + _setTime(time, index) { + update({ + time, + completed: false, + }); + this.move(time, index); + listsGoTo(time, index); + } + + _startAnimation() { + let prevTime = getState().time; + let animationPrevTime = performance.now(); + + const nextFrame = (animationCurrentTime) => { + const { + speed, + skip, + skipIntervals, + endTime, + live, + livePlay, + disconnected, + messagesLoading, + cssLoading, + } = getState(); + + const diffTime = messagesLoading || cssLoading || disconnected + ? 0 + : Math.max(animationCurrentTime - animationPrevTime, 0) * speed; + + let time = prevTime + diffTime; + + const skipInterval = skip && skipIntervals.find(si => si.contains(time)); // TODO: good skip by messages + if (skipInterval) time = skipInterval.end; + + const fmt = this.getFirstMessageTime(); + if (time < fmt) time = fmt; // ? + + const lmt = this.getLastMessageTime(); + if (livePlay && time < lmt) time = lmt; + if (endTime < lmt) { + update({ + endTime: lmt, + }); + } + + prevTime = time; + animationPrevTime = animationCurrentTime; + + const completed = !live && time >= endTime; + if (completed) { + this._setTime(endTime); + return update({ + playing: false, + completed: true, + }); + } + + if (live && time > endTime) { + update({ + endTime: time, + }); + } + this._setTime(time); + this._animationFrameRequestId = requestAnimationFrame(nextFrame); + }; + this._animationFrameRequestId = requestAnimationFrame(nextFrame); + } + + play() { + cancelAnimationFrame(this._animationFrameRequestId); + update({ playing: true }); + this._startAnimation(); + } + + pause() { + cancelAnimationFrame(this._animationFrameRequestId); + update({ playing: false }) + } + + togglePlay() { + const { playing, completed } = getState(); + if (playing) { + this.pause(); + } else if (completed) { + this._setTime(0); + this.play(); + } else { + this.play(); + } + } + + jump(time = getState().time, index) { + if (getState().playing) { + cancelAnimationFrame(this._animationFrameRequestId); + // this._animationFrameRequestId = requestAnimationFrame(() => { + this._setTime(time, index); + this._startAnimation(); + update({ livePlay: time === getState().endTime }); + //}); + } else { + //this._animationFrameRequestId = requestAnimationFrame(() => { + this._setTime(time, index); + update({ livePlay: time === getState().endTime }); + //}); + } + } + + toggleSkip() { + const skip = !getState().skip; + localStorage.setItem(SKIP_STORAGE_KEY, skip); + update({ skip }); + + } + + _updateSpeed(speed) { + localStorage.setItem(SPEED_STORAGE_KEY, speed); + update({ speed }); + } + + toggleSpeed() { + const { speed } = getState(); + this._updateSpeed(speed < HIGHEST_SPEED ? speed + 1 : 1); + } + + speedUp() { + const { speed } = getState(); + this._updateSpeed(Math.min(HIGHEST_SPEED, speed + 1)); + } + + speedDown() { + const { speed } = getState(); + this._updateSpeed(Math.max(1, speed - 1)); + } + + clean() { + this.pause(); + super.clean(); + } +} \ No newline at end of file diff --git a/frontend/app/player/index.js b/frontend/app/player/index.js new file mode 100644 index 000000000..70b02ae53 --- /dev/null +++ b/frontend/app/player/index.js @@ -0,0 +1,2 @@ +export { PlayerProvider, connectPlayer } from './store'; +export * from './singletone'; \ No newline at end of file diff --git a/frontend/app/player/ios/ImagePlayer.js b/frontend/app/player/ios/ImagePlayer.js new file mode 100644 index 000000000..824ee397a --- /dev/null +++ b/frontend/app/player/ios/ImagePlayer.js @@ -0,0 +1,454 @@ +import { io } from 'socket.io-client'; +import { makeAutoObservable, autorun } from 'mobx'; +import logger from 'App/logger'; +import { + createPlayerState, + createToolPanelState, + createToggleState, + PLAYING, + PAUSED, + COMPLETED, + SOCKET_ERROR, + + CRASHES, + LOGS, + NETWORK, + PERFORMANCE, + CUSTOM, + EVENTS, // last evemt +clicks +} from "./state"; +import { + createListState, + createScreenListState, +} from './lists'; +import Parser from './parser'; +import PerformanceList from './PerformanceList'; + +const HIGHEST_SPEED = 3; + + +export default class ImagePlayer { + _screen = null + _wrapper = null + _socket = null + toolPanel = createToolPanelState() + fullscreen = createToggleState() + lists = { + [LOGS]: createListState(), + [NETWORK]: createListState(), + [CRASHES]: createListState(), + [EVENTS]: createListState(), + [CUSTOM]: createListState(), + [PERFORMANCE]: new PerformanceList(), + } + _clicks = createListState() + _screens = createScreenListState() + + constructor(session) { + this.state = createPlayerState({ + endTime: session.duration.valueOf(), + }); + //const canvas = document.createElement("canvas"); + // this._context = canvas.getContext('2d'); + // this._img = new Image(); + // this._img..onerror = function(e){ + // logger.log('Error during loading image:', e); + // }; + // wrapper.appendChild(this._img); + session.crashes.forEach(c => this.lists[CRASHES].append(c)); + session.events.forEach(e => this.lists[EVENTS].append(e)); + session.stackEvents.forEach(e => this.lists[CUSTOM].append(e)); + window.fetch(session.mobsUrl) + .then(r => r.arrayBuffer()) + .then(b => { + new Parser(new Uint8Array(b)).parseEach(m => { + m.time = m.timestamp - session.startedAt; + try { + if (m.tp === "ios_log") { + this.lists[LOGS].append(m); + } else if (m.tp === "ios_network_call") { + this.lists[NETWORK].append(m); + // } else if (m.tp === "ios_custom_event") { + // this.lists[CUSTOM].append(m); + } else if (m.tp === "ios_click_event") { + m.time -= 600; //for graphic initiation + this._clicks.append(m); + } else if (m.tp === "ios_performance_event") { + this.lists[PERFORMANCE].append(m); + } + } catch (e) { + logger.error(e); + } + }); + Object.values(this.lists).forEach(list => list.moveToLast(0)); // In case of negative values + }) + + if (session.socket == null || typeof session.socket.jwt !== "string" || typeof session.socket.url !== "string") { + logger.error("No socket info found fpr session", session); + return + } + + const options = { + extraHeaders: {Authorization: `Bearer ${session.socket.jwt}`}, + reconnectionAttempts: 5, + //transports: ['websocket'], + } + + const socket = this._socket = io(session.socket.url, options); + socket.on("connect", () => { + logger.log("Socket Connected"); + }); + + socket.on('disconnect', (reason) => { + if (reason === 'io client disconnect') { + return; + } + logger.error("Disconnected. Reason: ", reason) + // if (reason === 'io server disconnect') { + // socket.connect(); + // } + }); + socket.on('connect_error', (e) => { + this.state.setState(SOCKET_ERROR); + logger.error(e) + }); + + socket.on('screen', (time, width, height, binary) => { + //logger.log("New Screen!", time, width, height, binary); + this._screens.insertScreen(time, width, height, binary); + }); + socket.on('buffered', (playTime) => { + if (playTime === this.state.time) { + this.state.setBufferingState(false); + } + logger.log("Play ack!", playTime); + }); + + let startPingInterval; + socket.on('start', () => { + logger.log("Started!"); + clearInterval(startPingInterval) + this.state.setBufferingState(true); + socket.emit("speed", this.state.speed); + this.play(); + }); + startPingInterval = setInterval(() => socket.emit("start"), 1000); + socket.emit("start"); + + window.addEventListener("resize", this.scale); + autorun(this.scale); + } + + _click + _getClickElement() { + if (this._click != null) { + return this._click; + } + const click = document.createElement('div'); + click.style.position = "absolute"; + click.style.background = "#ddd"; + click.style.border = "solid 4px #bbb"; + click.style.borderRadius = "50%"; + click.style.width = "32px"; + click.style.height = "32px"; + click.style.transformOrigin = "center"; + return this._click = click; + } + // More sufficient ways? + _animateClick({ x, y }) { + if (this._screen == null) { + return; + } + const click = this._getClickElement(); + if (click.parentElement == null) { + this._screen.appendChild(click); + } + click.style.transition = "none"; + click.style.left = `${x-18}px`; + click.style.top = `${y-18}px`; + click.style.transform = "scale(1)"; + click.style.opacity = "1"; + setTimeout(() => { + click.style.transition = "all ease-in .5s"; + click.style.transform = "scale(0)"; + click.style.opacity = "0"; + }, 0) + } + + _updateFrame({ image, width, height }) { + // const img = new Image(); + // img.onload = () => { + // this._context.drawImage(img); + // }; + // img.onerror = function(e){ + // logger.log('Error during loading image:', e); + // }; + // this._screen.style.backgroundImage = `url(${binaryToDataURL(binaryArray)})`; + this._canvas.getContext('2d').drawImage(image, 0, 0, this._canvas.width, this._canvas.height); + } + + _setTime(ts) { + ts = Math.max(Math.min(ts, this.state.endTime), 0); + this.state.setTime(ts); + Object.values(this.lists).forEach(list => list.moveToLast(ts)); + const screen = this._screens.moveToLast(ts); + if (screen != null) { + const { dataURL, width, height } = screen; + this.state.setSize(width, height); + //imagePromise.then(() => this._updateFrame({ image, width, height })); + //this._screen.style.backgroundImage = `url(${screen.dataURL})`; + screen.loadImage.then(() => this._screen.style.backgroundImage = `url(${screen.dataURL})`); + } + const lastClick = this._clicks.moveToLast(ts); + if (lastClick != null && lastClick.time > ts - 600) { + this._animateClick(lastClick); + } + } + + attach({ wrapperId, screenId }) { + const screen = document.getElementById(screenId); + if (!screen) { + throw new Error(`ImagePlayer: No screen element found with ID "${screenId}" `); + } + const wrapper = document.getElementById(wrapperId); + if (!wrapper) { + throw new Error(`ImagePlayer: No wrapper element found with ID "${wrapperId}" `); + } + screen.style.backgroundSize = "contain"; + screen.style.backgroundPosition = "center"; + wrapper.style.position = "absolute"; + wrapper.style.transformOrigin = "left top"; + wrapper.style.top = "50%"; + wrapper.style.left = "50%"; + // const canvas = document.createElement('canvas'); + // canvas.style.width = "300px"; + // canvas.style.height = "600px"; + // screen.appendChild(canvas); + // this._canvas = canvas; + this._screen = screen; + this._wrapper = wrapper; + this.scale(); + } + + + get loading() { + return this.state.initializing; + } + + get buffering() { + return this.state.buffering; + } + + // get timeTravelDisabled() { + // return this.state.initializing; + // } + + get controlsDisabled() { + return this.state.initializing; //|| this.state.buffering; + } + + _animationFrameRequestId = null + _stopAnimation() { + cancelAnimationFrame(this._animationFrameRequestId); + } + _startAnimation() { + let prevTime = this.state.time; + let animationPrevTime = performance.now(); + const nextFrame = (animationCurrentTime) => { + const { + speed, + //skip, + //skipIntervals, + endTime, + playing, + buffering, + //live, + //livePlay, + //disconnected, + //messagesLoading, + //cssLoading, + } = this.state; + + const diffTime = !playing || buffering + ? 0 + : Math.max(animationCurrentTime - animationPrevTime, 0) * speed; + + let time = prevTime + diffTime; + + //const skipInterval = skip && skipIntervals.find(si => si.contains(time)); // TODO: good skip by messages + //if (skipInterval) time = skipInterval.end; + + //const fmt = this.getFirstMessageTime(); + //if (time < fmt) time = fmt; // ? + + //const lmt = this.getLastMessageTime(); + //if (livePlay && time < lmt) time = lmt; + // if (endTime < lmt) { + // update({ + // endTime: lmt, + // }); + // } + + prevTime = time; + animationPrevTime = animationCurrentTime; + + const completed = time >= endTime; + if (completed) { + this._setComplete(); + } else { + + // if (live && time > endTime) { + // update({ + // endTime: time, + // }); + // } + this._setTime(time); + this._animationFrameRequestId = requestAnimationFrame(nextFrame); + } + }; + this._animationFrameRequestId = requestAnimationFrame(nextFrame); + } + + + scale = () => { + const { height, width } = this.state; // should be before any return for mobx observing + if (this._wrapper === null) return; + const parent = this._wrapper.parentElement; + if (parent === null) return; + let s = 1; + const { offsetWidth, offsetHeight } = parent; + + s = Math.min(offsetWidth / width, (offsetHeight - 20) / height); + if (s > 1) { + s = 1; + } else { + s = Math.round(s * 1e3) / 1e3; + } + + this._wrapper.style.transform = `scale(${ s }) translate(-50%, -50%)`; + this._wrapper.style.width = width + 'px'; + this._wrapper.style.height = height + 'px'; + // this._canvas.style.width = width + 'px'; + // this._canvas.style.height = height + 'px'; + } + + _setComplete() { + this.state.setStatus(COMPLETED); + this._setTime(this.state.endTime); + if (this._socket != null) { + this._socket.emit("pause"); + } + } + + + _pause() { + this._stopAnimation(); + this.state.setStatus(PAUSED); + } + + pause = () => { + this._pause(); + if (this._socket != null) { + this._socket.emit("pause"); + } + } + + _play() { + if (!this.state.playing) { + this._startAnimation(); + } + this.state.setStatus(PLAYING); + } + play = () => { + this._play() + if (this._socket != null) { + this._socket.emit("resume"); + } + } + + _jump(ts) { + if (this.state.playing) { + this._stopAnimation(); + this._setTime(ts); + this._startAnimation(); + } else { + this._setTime(ts); + this.state.setStatus(PAUSED); // for the case when completed + } + } + jump = (ts) => { + ts = Math.round(ts); // Should be integer + this._jump(ts); + if (this._socket != null) { + this.state.setBufferingState(true); + console.log("Send play on jump!", ts) + this._socket.emit("jump", ts); + } + } + + togglePlay = () => { + if (this.state.playing) { + this.pause() + } else { + if (this.state.completed) { + //this.state.time = 0; + this.jump(0) + } + this.play() + } + } + backTenSeconds = () => { + this.jump(Math.max(this.state.time - 10000, 0)); + } + forthTenSeconds = () => { + this.jump(Math.min(this.state.time + 10000, this.state.endTime)); + } + + _setSpeed(speed) { + if (this._socket != null) { + this._socket.emit("speed", speed); + } + this.state.setSpeed(speed) + } + + toggleSpeed = () => { + const speed = this.state.speed; + this._setSpeed(speed < HIGHEST_SPEED ? speed + 1 : 1); + } + + speedUp = () => { + const speed = this.state.speed; + this._setSpeed(Math.min(HIGHEST_SPEED, speed + 1)); + } + + speedDown = () => { + const speed = this.state.speed; + this._setSpeed(Math.max(1, speed - 1)); + } + + togglePanel = (key) => { + this.toolPanel.toggle(key); + setTimeout(() => this.scale(), 0); + } + + closePanel = () => { + this.toolPanel.close(); + setTimeout(() => this.scale(), 0); + } + + toggleFullscreen = (flag = true) => { + this.fullscreen.toggle(flag); + setTimeout(() => this.scale(), 0); + } + + + clean() { + this._stopAnimation(); + if (this._socket != null) { + //this._socket.emit("close"); + this._socket.close(); + } + this._screens.clean(); + } +} + diff --git a/frontend/app/player/ios/PerformanceList.js b/frontend/app/player/ios/PerformanceList.js new file mode 100644 index 000000000..5da8272dc --- /dev/null +++ b/frontend/app/player/ios/PerformanceList.js @@ -0,0 +1,73 @@ +import { + createListState, +} from './lists'; + +const MIN_INTERVAL = 500; + + +const NAME_MAP = { + "mainThreadCPU": "cpu", + "batteryLevel": "battery", + "memoryUsage": "memory", +} + +export default class PerformanceList { + _list = createListState() + availability = { + cpu: false, + memory: false, + battery: false, + } + + get list() { + return this._list.list; + } + + get count() { + return this._list.count; + } + + moveToLast(t) { + this._list.moveToLast(t); + } + + append(m) { + if (!["mainThreadCPU", "memoryUsage", "batteryLevel", "thermalState", "activeProcessorCount", "isLowPowerModeEnabled"].includes(m.name)) { + return; + } + + let lastPoint = Object.assign({ time: 0, cpu: null, battery: null, memory: null }, this._list.last); + if (this._list.length === 0) { + this._list.append(lastPoint); + } + + if (NAME_MAP[m.name] != null) { + this.availability[ NAME_MAP[m.name] ] = true; + if (lastPoint[NAME_MAP[m.name]] === null) { + this._list.forEach(p => p[NAME_MAP[m.name]] = m.value); + lastPoint[NAME_MAP[m.name]] = m.value; + } + } + + + const newPoint = Object.assign({}, lastPoint, { + time: m.time, + [ NAME_MAP[m.name] || m.name ]: m.value, + }); + + const dif = m.time - lastPoint.time; + const insertCount = Math.floor(dif/MIN_INTERVAL); + for (let i = 0; i < insertCount; i++){ + const evalValue = (key) => lastPoint[key] + Math.floor((newPoint[key]-lastPoint[key])/insertCount*(i + 1)) + this._list.append({ + ...lastPoint, + time: evalValue("time"), + cpu: evalValue("cpu") + (Math.floor(5*Math.random())-2), + battery: evalValue("battery"), + memory: evalValue("memory")*(1 + (0.1*Math.random() - 0.05)), + }); + } + + this._list.append(newPoint); + } +} \ No newline at end of file diff --git a/frontend/app/player/ios/ScreenList.js b/frontend/app/player/ios/ScreenList.js new file mode 100644 index 000000000..a19b9bd2a --- /dev/null +++ b/frontend/app/player/ios/ScreenList.js @@ -0,0 +1,57 @@ +import ListWalker from '../MessageDistributor/managers/ListWalker'; + +//URL.revokeObjectURL() !! +function binaryToDataURL(arrayBuffer){ + var blob = new Blob([new Uint8Array(arrayBuffer)], {'type' : 'image/jpeg'}); + return URL.createObjectURL(blob); +} + +function prepareImage(width, height, arrayBuffer) { + const dataURL = binaryToDataURL(arrayBuffer); + return { + loadImage: new Promise(resolve => { + const img = new Image(); + img.onload = function() { + //URL.revokeObjectURL(this.src); + resolve(img); + }; + img.src = dataURL; + }).then(), + dataURL, + }; +} + +export default class ScreenList { + _walker = new ListWalker(); + _insertUnique(m) { + let p = this._walker._list.length; + while (p > 0 && this._walker._list[ p - 1 ].time > m.time) { + p--; + } + if (p > 0 && this._walker._list[ p - 1 ].time === m.time) { + return; + } + this._walker._list.splice(p, 0, m); + } + + moveToLast(time) { + return this._walker.moveToLast(time); + } + + insertScreen(time, width, height, arrayBuffer): void { + this._insertUnique({ + time, + width, + height, + ...prepareImage(width, height, arrayBuffer), + //image: new ImageData(new Uint8ClampedArray(arrayBuffer), width, height), + // dataURL: binaryToDataURL(arrayBuffer) + }); + } + + clean() { + this._walker.forEach(m => { + URL.revokeObjectURL(m.dataURL); + }); + } +} \ No newline at end of file diff --git a/frontend/app/player/ios/lists.js b/frontend/app/player/ios/lists.js new file mode 100644 index 000000000..b0ddb9d0d --- /dev/null +++ b/frontend/app/player/ios/lists.js @@ -0,0 +1,12 @@ +import { makeAutoObservable } from "mobx" +import ListWalker from '../MessageDistributor/managers/ListWalker'; + +import ScreenList from './ScreenList'; + +export function createListState(list) { + return makeAutoObservable(new ListWalker(list)); +} + +export function createScreenListState() { + return makeAutoObservable(new ScreenList()); +} \ No newline at end of file diff --git a/frontend/app/player/ios/parser.js b/frontend/app/player/ios/parser.js new file mode 100644 index 000000000..83ddaec50 --- /dev/null +++ b/frontend/app/player/ios/parser.js @@ -0,0 +1,31 @@ +import readMessage from '../MessageDistributor/messages'; + + +export default class Parser { + _p = 0 + _data + _error = null + constructor(byteArray) { + this._data = byteArray; + } + + parseEach(cb) { + while (this.hasNext()) { + const msg = this.parseNext(); + if (msg !== null) { + cb(msg); + } + } + } + + hasNext() { + return !this._error && this._data.length > this._p; + } + + parseNext() { + let msg; + [ msg, this._p ] = readMessage(this._data, this._p); + return msg + } + +} \ No newline at end of file diff --git a/frontend/app/player/ios/state.js b/frontend/app/player/ios/state.js new file mode 100644 index 000000000..766ba08fe --- /dev/null +++ b/frontend/app/player/ios/state.js @@ -0,0 +1,112 @@ +import { makeAutoObservable } from "mobx" + +//configure ({empceActions: true}) + +export const + NONE = 0, + CRASHES = 1, + NETWORK = 2, + LOGS = 3, + EVENTS = 4, + CUSTOM = 5, + PERFORMANCE = 6; + +export function createToolPanelState() { + return makeAutoObservable({ + key: NONE, + toggle(key) { // auto-bind?? + this.key = this.key === key ? NONE : key; + }, + close() { + this.key = NONE; + }, + }); +} + + +export function createToggleState() { + return makeAutoObservable({ + enabled: false, + toggle(flag) { + this.enabled = typeof flag === 'boolean' + ? flag + : !this.enabled; + }, + enable() { + this.enabled = true; + }, + disable() { + this.enabled = false; + }, + }); +} + +const SPEED_STORAGE_KEY = "__$player-speed$__"; +//const SKIP_STORAGE_KEY = "__$player-skip$__"; +//const initialSkip = !!localStorage.getItem(SKIP_STORAGE_KEY); + +export const + INITIALIZING = 0, + PLAYING = 1, + PAUSED = 2, + COMPLETED = 3, + SOCKET_ERROR = 5; + +export const + PORTRAIT = 1, + LANDSCAPE = 2; + +export function createPlayerState(state) { + const storedSpeed = +localStorage.getItem(SPEED_STORAGE_KEY); + const initialSpeed = [1,2,3].includes(storedSpeed) ? storedSpeed : 1; + + return makeAutoObservable({ + status: INITIALIZING, + _statusSaved: null, + setTime(t) { + this.time = t + }, + time: 0, + endTime: 0, + setStatus(status) { + this.status = status; + }, + get initializing() { + return this.status === INITIALIZING; + }, + get playing() { + return this.status === PLAYING; + }, + get completed() { + return this.status === COMPLETED; + }, + _buffering: false, + get buffering() { + return this._buffering; + }, + setBufferingState(flag = true) { + this._buffering = flag; + }, + speed: initialSpeed, + setSpeed(speed) { + localStorage.setItem(SPEED_STORAGE_KEY, speed); + this.speed = speed; + }, + width: 360, + height: 780, + orientation: PORTRAIT, + get orientationLandscape() { + return this.orientation === LANDSCAPE; + }, + setSize(width, height) { + if (height < 0 || width < 0) { + console.log("Player: wrong non-positive size") + return; + } + this.width = width; + this.height = height; + this.orientation = width > height ? LANDSCAPE : PORTRAIT; + }, + ...state, + }); +} diff --git a/frontend/app/player/lists/ListReader.js b/frontend/app/player/lists/ListReader.js new file mode 100644 index 000000000..641d3341a --- /dev/null +++ b/frontend/app/player/lists/ListReader.js @@ -0,0 +1,124 @@ +export default class ListReader { + _callback; + _p = -1; + _list = []; + _offset = 0; + + constructor(callback = Function.prototype) { + if (typeof callback !== 'function') { + return console.error("List Reader: wrong constructor argument. `callback` must be a function."); + } + this._callback = callback; + } + + static checkItem(item) { + if(typeof item !== 'object' || item === null) { + console.error("List Reader: expected item to be not null object but got ", item); + return false; + } + if (typeof item.time !== 'number') { + console.error("List Reader: expected item to have number property 'time', ", item); + return false; + } + // if (typeof item.index !== 'number') { + // console.error("List Reader: expected item to have number property 'index', ", item); + // return false; + // } // future: All will have index + return true; + } + /* EXTENDABLE METHODS */ + _onIncrement() {} + _onDecrement() {} + _onStartTimeChange() {} + + inc() { + const item = this._list[ ++this._p ]; + this._onIncrement(item); + return item; + } + + dec() { + const item = this._list[ this._p-- ]; + this._onDecrement(item); + return item + } + + get _goToReturn() { + return { listNow: this.listNow }; + } + + goTo(time) { + const prevPointer = this._p; + while (!!this._list[ this._p + 1 ] && this._list[ this._p + 1 ].time <= time) { + this.inc(); + } + while (this._p >= 0 && this._list[ this._p ].time > time) { + this.dec(); + } + if (prevPointer !== this._p) { + //this._notify([ "listNow" ]); + return this._goToReturn; + } + } + + goToIndex(index) { // thinkaboutit + const prevPointer = this._p; + while (!!this._list[ this._p + 1 ] && + this._list[ this._p + 1 ].index <= index + ) { + this.inc(); + } + while (this._p >= 0 && this._list[ this._p ].index > index) { + this.dec(); + } + if (prevPointer !== this._p) { + //this._notify([ "listNow" ]); + return this._goToReturn; + } + } + + // happens rare MBTODO only in class ResourceListReader extends ListReaderWithRed + set startTime(time) { + const prevOffset = this._offset; + const prevPointer = this._p; + this._offset = this._list.findIndex(({ time, duration = 0 }) => time + duration >= time); // TODO: strict for duration rrrrr + this._p = Math.max(this._p, this._offset - 1); + if (prevOffset !== this._offset || prevPointer !== this._p) { + this._notify([ "listNow" ]); + } + this._onStartTimeChange(); + } + + get list() { + return this._list; + } + get count() { + return this._list.length; + } + get listNow() { + return this._list.slice(this._offset, this._p + 1); + } + + set list(_list) { + if (!Array.isArray(_list)) { + console.error("List Reader: wrong list value.", _list) + } + const valid = _list.every(this.constructor.checkItem); + if (!valid) return; + this._list = _list; // future: time + index sort + this._notify([ "list", "count" ]); + } + + append(item) { + if (!this.constructor.checkItem(item)) return; + this._list.push(item); // future: time + index sort + this._notify([ "count" ]); // list is the same by ref, CAREFULL + } + + _notify(propertyList) { + const changedState = {}; + propertyList.forEach(p => changedState[ p ] = this[ p ]); + this._callback(changedState); + } + +} \ No newline at end of file diff --git a/frontend/app/player/lists/ListReaderWithRed.js b/frontend/app/player/lists/ListReaderWithRed.js new file mode 100644 index 000000000..84da42138 --- /dev/null +++ b/frontend/app/player/lists/ListReaderWithRed.js @@ -0,0 +1,48 @@ +import ListReader from './ListReader'; + +export default class ListReaderWithRed extends ListReader { + _redCountNow = 0; + + static checkItem(item) { + const superCheckResult = super.checkItem(item); + if (typeof item.isRed !== 'function') { + console.error("List Reader With Red: expected item to have method 'isRed', ", item); + return false; + } + return superCheckResult; + } + + get _goToReturn() { + return { + listNow: this.listNow, + redCountNow: this.redCountNow, + } + } + + _onIncrement(item) { + if (item.isRed()) { + this._redCountNow++; + //this._notify([ "redCountNow" ]); + } + } + + _onDecrement(item) { + if (item.isRed()) { + this._redCountNow--; + //this._notify([ "redCountNow" ]); + } + } + + _onStartTimeChange() { + this._redCountNow = this._list + .slice(this._offset, this._p + 1) + .filter(item => item.isRed()) + .length; + this._notify([ "redCountNow" ]); + } + + get redCountNow() { + return this._redCountNow; + } + +} \ No newline at end of file diff --git a/frontend/app/player/lists/ReduxListReader.js b/frontend/app/player/lists/ReduxListReader.js new file mode 100644 index 000000000..5671d7171 --- /dev/null +++ b/frontend/app/player/lists/ReduxListReader.js @@ -0,0 +1,51 @@ +import { applyChange, revertChange } from 'deep-diff'; +import ListReader from './ListReader'; + +export default class ReduxListReader extends ListReader { + #state = {}; + #finalStates = []; + + get _goToReturn() { + return { + listNow: this.listNow, + state: { ...this.#state }, + }; + } + + _onIncrement(item) { + this._processRedux(item, true); + } + + _onDecrement(item) { + this._processRedux(item, false); + } + + _processRedux(action, forward) { + if (forward) { + if (!!action.state) { + this.#finalStates.push(this.#state); + this.#state = JSON.parse(JSON.stringify(action.state)); // Deep clone :( + } else { + action.diff.forEach(d => { + try { + applyChange(this.#state, d); + } catch (e) { + //console.warn("Deepdiff error") + } + }); + } + } else { + if (!!action.state) { + this.#state = this.#finalStates.pop(); + } else { + action.diff.forEach(d => { + try { + revertChange(this.#state, 1, d); // bad lib :( TODO: write our own diff + } catch (e) { + //console.warn("Deepdiff error") + } + }); + } + } + } +} \ No newline at end of file diff --git a/frontend/app/player/lists/index.js b/frontend/app/player/lists/index.js new file mode 100644 index 000000000..bcaeb5ec6 --- /dev/null +++ b/frontend/app/player/lists/index.js @@ -0,0 +1,69 @@ +import ListReader from './ListReader'; +import ListReaderWithRed from './ListReaderWithRed'; +import ReduxListReader from './ReduxListReader'; +import { update as updateStore } from '../store'; + +const l = n => `${ n }List`; +const c = n => `${ n }Count`; +const ln = n => `${ n }ListNow`; +const rcn = n => `${ n }RedCountNow`; + +const entityNamesWithRed = [ "log", "resource", "fetch", "stack" ]; +const entityNamesSimple = [ "event", "profile" ]; +const entityNames = /*[ "redux" ].*/entityNamesWithRed.concat(entityNamesSimple); + +const is = {}; +entityNames.forEach(n => { + is[ l(n) ] = []; + is[ c(n) ] = 0; + is[ ln(n) ] = []; + if (entityNamesWithRed.includes(n)) { + is[ rcn(n) ] = 0; + } +}); +//is["reduxState"] = {}; +//is["reduxFinalStates"] = []; + + +const createCallback = n => { + const entityfy = s => `${ n }${ s[ 0 ].toUpperCase() }${ s.slice(1) }`; + return state => { + if (!state) return; + const namedState = {}; + Object.keys(state).forEach(key => { + namedState[ entityfy(key) ] = state[ key ]; + }); + return updateStore(namedState); + } +} + +let readers = null; + +export function init(lists) { + readers = {}; + entityNamesSimple.forEach(n => readers[ n ] = new ListReader(createCallback(n))); + entityNamesWithRed.forEach(n => readers[ n ] = new ListReaderWithRed(createCallback(n))); + //readers.redux = new ReduxListReader(createCallback("redux")); + entityNames.forEach(n => readers[ n ].list = lists[ n ] || []); +} +export function append(name, item) { + readers[ name ].append(item); +} +export function setStartTime(time) { + readers.resource.startTime = time; +} +const byTimeNames = [ "event", "stack" ]; // TEMP +const byIndexNames = entityNames.filter(n => !byTimeNames.includes(n)); +export function goTo(time, index) { + if (readers === null) return; + if (typeof index === 'number') { + byTimeNames.forEach(n => readers[ n ] && readers[ n ]._callback(readers[ n ].goTo(time))); + byIndexNames.forEach(n => readers[ n ] && readers[ n ]._callback(readers[ n ].goToIndex(index))); + } else { + entityNames.forEach(n => readers[ n ] && readers[ n ]._callback(readers[ n ].goTo(time))); + } +} +export function clean() { + entityNames.forEach(n => delete readers[ n ]); +} +export const INITIAL_STATE = is; diff --git a/frontend/app/player/singletone.js b/frontend/app/player/singletone.js new file mode 100644 index 000000000..3e0ea911f --- /dev/null +++ b/frontend/app/player/singletone.js @@ -0,0 +1,79 @@ +import Player from './Player'; +import { update, clean as cleanStore, getState } from './store'; +import { clean as cleanLists } from './lists'; + + +let instance = null; + +const initCheck = method => (...args) => { + if (instance === null) { + console.error("Player method called before Player have been initialized."); + return; + } + method(...args); +} + + +let autoPlay = true; +document.addEventListener("visibilitychange", function() { + if (instance === null) return; + if (document.hidden) { + const { playing } = getState(); + autoPlay = playing + if (playing) { + instance.pause(); + } + } else if (autoPlay) { + instance.play(); + } +}); + +export function init(session, jwt) { + const live = session.live; + const endTime = !live && session.duration.valueOf(); + + instance = new Player(session, jwt); + update({ + initialized: true, + live, + livePlay: live, + endTime, // : 0, //TODO: through initialState + session, + }); + + if (!document.hidden) { + instance.play(); + } +} + +export function clean() { + if (instance === null) return; + instance.clean(); + cleanStore(); + cleanLists(); + instance = null; +} +export const jump = initCheck((...args) => instance.jump(...args)); + +export const togglePlay = initCheck((...args) => instance.togglePlay(...args)); +export const pause = initCheck((...args) => instance.pause(...args)); +export const toggleSkip = initCheck((...args) => instance.toggleSkip(...args)); +export const toggleSpeed = initCheck((...args) => instance.toggleSpeed(...args)); +export const speedUp = initCheck((...args) => instance.speedUp(...args)); +export const speedDown = initCheck((...args) => instance.speedDown(...args)); +export const attach = initCheck((...args) => instance.attach(...args)); +export const mark = initCheck((...args) => instance.marker.markBySelector(...args)); +export const scale = initCheck(() => instance.scale()); +export const markBelowMouse = initCheck(() => instance.marker.mark(instance.cursor.getTarget())); + +export const Controls = { + jump, + togglePlay, + pause, + toggleSkip, + toggleSpeed, + speedUp, + speedDown, + mark, + markBelowMouse, +} diff --git a/frontend/app/player/store/connector.js b/frontend/app/player/store/connector.js new file mode 100644 index 000000000..9e74f56a6 --- /dev/null +++ b/frontend/app/player/store/connector.js @@ -0,0 +1,24 @@ +import { connect, createProvider } from 'react-redux' +import store from './store'; + +const STORE_KEY = 'playerStore'; + +const PlayerProvider = createProvider(STORE_KEY); +PlayerProvider.defaultProps = { store }; + +function connectPlayer( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options = {} +) { + options.storeKey = STORE_KEY + return connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options + ) +} + +export { PlayerProvider, connectPlayer }; \ No newline at end of file diff --git a/frontend/app/player/store/duck.js b/frontend/app/player/store/duck.js new file mode 100644 index 000000000..faf77041c --- /dev/null +++ b/frontend/app/player/store/duck.js @@ -0,0 +1,42 @@ +import { applyChange, revertChange } from 'deep-diff'; +import { INITIAL_STATE as listsInitialState } from '../lists'; +import { INITIAL_STATE as playerInitialState, INITIAL_NON_RESETABLE_STATE as playerInitialNonResetableState } from '../Player'; + +const UPDATE = 'player/UPDATE'; +const CLEAN = 'player/CLEAN'; +const REDUX = 'player/REDUX'; + +const resetState = { + ...listsInitialState, + ...playerInitialState, + initialized: false, +}; + +const initialState = { + ...resetState, + ...playerInitialNonResetableState, +} + +export default (state = initialState, action = {}) => { + switch (action.type) { + case UPDATE: + return { ...state, ...action.state }; + case CLEAN: + return { ...state, ...resetState }; + default: + return state; + } +} + +export function update(state = {}) { + return { + type: UPDATE, + state, + }; +} + +export function clean() { + return { + type: CLEAN + }; +} diff --git a/frontend/app/player/store/index.js b/frontend/app/player/store/index.js new file mode 100644 index 000000000..c2a987661 --- /dev/null +++ b/frontend/app/player/store/index.js @@ -0,0 +1,4 @@ +export * from './connector'; +export * from './store'; +export * from './selectors'; +export { default } from './store'; \ No newline at end of file diff --git a/frontend/app/player/store/selectors.js b/frontend/app/player/store/selectors.js new file mode 100644 index 000000000..1a6f0dc2d --- /dev/null +++ b/frontend/app/player/store/selectors.js @@ -0,0 +1,44 @@ +const REDUX = "redux"; +const MOBX = "mobx"; +const VUEX = "vuex"; +const NGRX = "ngrx"; +const NONE = 0; + + +export const STORAGE_TYPES = { + REDUX, + MOBX, + VUEX, + NGRX, + NONE, +}; + + +export function selectStorageType(state) { + if (!state.reduxList) return NONE; + if (state.reduxList.length > 0) { + return REDUX; + } else if (state.vuexList.length > 0) { + return VUEX; + } else if (state.mobxList.length > 0) { + return MOBX; + } else if (state.ngrxList.length > 0) { + return NGRX; + } + return NONE; +} + +export function selectStorageList(state) { + const key = selectStorageType(state); + if (key !== NONE) { + return state[`${key}List`] || []; + } + return []; +} +export function selectStorageListNow(state) { + const key = selectStorageType(state); + if (key !== NONE) { + return state[`${key}ListNow`] || []; + } + return []; +} \ No newline at end of file diff --git a/frontend/app/player/store/store.js b/frontend/app/player/store/store.js new file mode 100644 index 000000000..a09ba881a --- /dev/null +++ b/frontend/app/player/store/store.js @@ -0,0 +1,19 @@ +import { createStore } from 'redux'; +import reducer, { + update as updateAction, + clean as cleanAction, +} from './duck'; + +const store = createStore(reducer); + +export const getState = store.getState.bind(store); + +export function update(...args) { + return store.dispatch(updateAction(...args)); +} + +export function clean() { + return store.dispatch(cleanAction()); +} + +export default store; diff --git a/frontend/app/routes.js b/frontend/app/routes.js new file mode 100644 index 000000000..df032fe32 --- /dev/null +++ b/frontend/app/routes.js @@ -0,0 +1,136 @@ +const hashed = (path, hash) => { + if ((typeof hash === 'string' && hash !== '') || typeof hash === 'number') { + return `${ path }#${ hash }`; + } + return path; +}; + +export const queried = (path, params) => { + const keys = typeof params === 'object' && params !== null && Object.keys(params) + .filter(key => /string|number|boolean/.test(typeof params[ key ])); + if (keys && keys.length > 0) { + const queriedPath = path + '?' + keys + .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[ k ])) + .join('&'); + return queriedPath; + } + return path; +}; + +export const parseQuery = (location, avaliableQueryParams) => { + const params = {}; + location.search + .substring(1) + .split('&') + .map(param => param.split('=')) + .map(kv => kv.map(decodeURIComponent)) + .filter(([ paramName ]) => !avaliableQueryParams || avaliableQueryParams.includes(paramName)) + .map(([ paramName, paramValue ]) => { params[ paramName ] = paramValue; }); + return params; +}; + +export const removeQueryParams = (location, removingParams = []) => { + const rp = typeof removingParams === 'string' ? [ removingParams ] : removingParams; + const search = location.search + .substring(1) + .split('&') + .map(param => param.split('=')) + .filter(([ paramName ]) => !rp.includes(decodeURIComponent(paramName))) + .map(pair => pair.join('=')) + .join('&'); // add '?' ? + return { ...location, search }; +}; + +export const addQueryParams = (location, params) => { + const search = queried('', { ...parseQuery(location), ...params }); + return { ...location, search }; +}; + +export const setQueryParams = (location, params) => { + const search = queried('', { ...params }); + return { ...location, search }; +}; + +export const login = () => '/login'; +export const signup = () => '/signup'; + +export const forgotPassword = () => '/reset-password'; + +export const CLIENT_TABS = { + INTEGRATIONS: 'integrations', + PROFILE: 'account', + MANAGE_USERS: 'manage-users', + SITES: 'projects', + CUSTOM_FIELDS: 'metadata', + WEBHOOKS: 'webhooks', + NOTIFICATIONS: 'notifications', +}; +export const CLIENT_DEFAULT_TAB = CLIENT_TABS.PROFILE; +const routerClientTabString = `:activeTab(${ Object.values(CLIENT_TABS).join('|') })`; +export const client = (tab = routerClientTabString) => `/client/${ tab }`; + +export const OB_TABS = { + INSTALLING: 'installing', + IDENTIFY_USERS: 'identify-users', + MANAGE_USERS: 'manage-users', + INTEGRATIONS: 'integrations', +}; +export const OB_DEFAULT_TAB = OB_TABS.INSTALLING; +const routerOBTabString = `:activeTab(${ Object.values(OB_TABS).join('|') })`; + +export const onboarding = (tab = routerOBTabString) => `/onboarding/${ tab }`; + +export const sessions = params => queried('/sessions', params); + +export const session = (sessionId = ':sessionId', hash) => hashed(`/session/${ sessionId }`, hash); +export const liveSession = (sessionId = ':sessionId', hash) => hashed(`/live/session/${ sessionId }`, hash); + +export const errors = params => queried('/errors', params); +export const error = (id = ':errorId', hash) => hashed(`/errors/${ id }`, hash); + +export const funnel = (id = ':funnelId', hash) => hashed(`/funnels/${ id }`, hash); +export const funnelIssue = (id = ':funnelId', issueId = ':issueId', hash) => hashed(`/funnels/${ id }/${ issueId}`, hash); + +export const tests = () => '/tests'; + +export const testBuilderNew = () => '/test-builder'; + +export const testBuilder = (testId = ':testId') => `/test-builder/${ testId }`; + +export const dashboard = () => '/metrics'; + +export const RESULTS_QUERY_KEY = 'results'; +export const METRICS_QUERY_KEY = 'metrics'; +export const SOURCE_QUERY_KEY = 'source'; +export const WIDGET_QUERY_KEY = 'widget'; + +const REQUIRED_SITE_ID_ROUTES = [ liveSession(''), session(''), sessions(), dashboard(''), error(''), errors(), onboarding(''), funnel(''), funnelIssue(''), ]; +const routeNeedsSiteId = path => REQUIRED_SITE_ID_ROUTES.some(r => path.startsWith(r)); +const siteIdToUrl = (siteId = ':siteId') => { + if (Array.isArray(siteId)) { + return `:siteId(${ siteId.join('|') })`; + } + return siteId; +} +export const withSiteId = (route, siteId = ':siteId') => routeNeedsSiteId(route) ? `/${ siteIdToUrl(siteId) }${ route }` : route; +export const hasSiteId = (path) => { + const pathParts = path.split('/'); + if (!isNaN(+pathParts[1]) && // [0] is empty for '/all/paths' + routeNeedsSiteId("/" + pathParts.slice(2).join('/'))) return true; + return false; +} + +export function isRoute(route, path){ + const pathParts = path.split('/'); + const routeParts = withSiteId(route).split('/'); + return routeParts.length === pathParts.length && + routeParts.every((p, i) => p.startsWith(':') || p === pathParts[ i ]); +} + +const SITE_CHANGE_AVALIABLE_ROUTES = [ sessions(), dashboard(), errors(), onboarding('')]; +export const siteChangeAvaliable = path => SITE_CHANGE_AVALIABLE_ROUTES.some(r => isRoute(r, path)); + + +export const redirects = Object.entries({ + [ client('custom-fields') ]: client(CLIENT_TABS.CUSTOM_FIELDS), +}); \ No newline at end of file diff --git a/frontend/app/store.js b/frontend/app/store.js new file mode 100644 index 000000000..f907a579c --- /dev/null +++ b/frontend/app/store.js @@ -0,0 +1,26 @@ +import { createStore, applyMiddleware } from 'redux'; +import thunk from 'redux-thunk'; +import { Map } from 'immutable'; +import indexReducer from './duck'; +import apiMiddleware from './api_middleware'; +import LocalStorage from './local_storage'; + +const storage = new LocalStorage({ + jwt: String, +}); + +const storageState = storage.state(); +const initialState = Map({ + jwt: storageState.jwt, + // TODO: store user +}); + +const store = createStore(indexReducer, initialState, applyMiddleware(thunk, apiMiddleware)); +store.subscribe(() => { + const state = store.getState(); + storage.sync({ + jwt: state.get('jwt') + }); +}); + +export default store; diff --git a/frontend/app/styles/codemirror.css b/frontend/app/styles/codemirror.css new file mode 100644 index 000000000..5cf5bca8a --- /dev/null +++ b/frontend/app/styles/codemirror.css @@ -0,0 +1,59 @@ +.cm-s-yeti.CodeMirror { + background-color: #ffffff !important; + color: #d1c9c0 !important; + border: none; + border-radius: 4px; +} + +.cm-s-yeti .CodeMirror-gutters { + color: #adaba6; + background-color: #ffffff; + border: none; +} + +.cm-s-yeti span.cm-comment { color: #777; } +.cm-s-yeti span.cm-def { color: #00f; } +.cm-s-yeti span.cm-keyword { color: #708; } +.cm-s-yeti span.cm-variable { color: #00f; } +.cm-s-yeti span.cm-string { color: #0a9d0a; } +.cm-s-yeti span.cm-property { color: #607392; } + +.cm-s-custom.CodeMirror { + background-color: transparent !important; + color: #d1c9c0 !important; + border: none; + border-radius: 4px; + height: auto; +} + +.cm-s-custom span.cm-comment { color: #777; } +.cm-s-custom span.cm-def { color: #00f; } +.cm-s-custom span.cm-keyword { color: #708; } +.cm-s-custom span.cm-variable { color: #00f; } +.cm-s-custom span.cm-string { color: #0a9d0a; } +.cm-s-custom span.cm-property { color: #607392; } +.cm-s-custom .CodeMirror-hscrollbar { overflow: hidden !important; } +.cm-s-custom .CodeMirror-sizer { min-width: 100% !important; } +.cm-s-custom pre { max-width: 100% !important; overflow: hidden; } + + +.cm-s-docs.CodeMirror { + background-color: #000 !important; + color: white !important; + border: none; + border-radius: 4px; + height: auto; + padding: 10px; +} + +.cm-s-docs span.cm-comment { color: #777; } +.cm-s-docs span.cm-def { color: rgb(156, 220, 254); } +.cm-s-docs span.cm-keyword { color: rgb(86, 156, 214); } +.cm-s-docs span.cm-variable { color: rgb(156, 220, 254); } +.cm-s-docs span.cm-string { color: rgb(206, 145, 120); } +.cm-s-docs span.cm-number { color: rgb(206, 145, 120); } +.cm-s-docs span.cm-property { color: rgb(156, 220, 254); } +.cm-s-docs span.cm-operator { color: rgb(156, 220, 254); } +.cm-s-docs .CodeMirror-hscrollbar { overflow: hidden !important; } +.cm-s-docs .CodeMirror-sizer { min-width: 100% !important; } +.cm-s-docs pre { max-width: 100% !important; overflow: hidden; } \ No newline at end of file diff --git a/frontend/app/styles/colors-autogen.css b/frontend/app/styles/colors-autogen.css new file mode 100644 index 000000000..37fbd2dbf --- /dev/null +++ b/frontend/app/styles/colors-autogen.css @@ -0,0 +1,114 @@ +/* Auto-generated, DO NOT EDIT */ + + +/* fill */ +.fill-white { fill: $white } +.fill-gray-light-shade { fill: $gray-light-shade } +.fill-gray-lightest { fill: $gray-lightest } +.fill-gray-light { fill: $gray-light } +.fill-gray-medium { fill: $gray-medium } +.fill-gray-dark { fill: $gray-dark } +.fill-gray-darkest { fill: $gray-darkest } +.fill-teal { fill: $teal } +.fill-teal-dark { fill: $teal-dark } +.fill-tealx { fill: $tealx } +.fill-tealx-light { fill: $tealx-light } +.fill-tealx-light-border { fill: $tealx-light-border } +.fill-orange { fill: $orange } +.fill-yellow { fill: $yellow } +.fill-yellow2 { fill: $yellow2 } +.fill-orange-dark { fill: $orange-dark } +.fill-green { fill: $green } +.fill-green2 { fill: $green2 } +.fill-green-dark { fill: $green-dark } +.fill-red { fill: $red } +.fill-red2 { fill: $red2 } +.fill-blue { fill: $blue } +.fill-blue2 { fill: $blue2 } +.fill-active-blue { fill: $active-blue } +.fill-active-blue-border { fill: $active-blue-border } +.fill-pink { fill: $pink } + +/* color */ +.color-white { color: $white } +.color-gray-light-shade { color: $gray-light-shade } +.color-gray-lightest { color: $gray-lightest } +.color-gray-light { color: $gray-light } +.color-gray-medium { color: $gray-medium } +.color-gray-dark { color: $gray-dark } +.color-gray-darkest { color: $gray-darkest } +.color-teal { color: $teal } +.color-teal-dark { color: $teal-dark } +.color-tealx { color: $tealx } +.color-tealx-light { color: $tealx-light } +.color-tealx-light-border { color: $tealx-light-border } +.color-orange { color: $orange } +.color-yellow { color: $yellow } +.color-yellow2 { color: $yellow2 } +.color-orange-dark { color: $orange-dark } +.color-green { color: $green } +.color-green2 { color: $green2 } +.color-green-dark { color: $green-dark } +.color-red { color: $red } +.color-red2 { color: $red2 } +.color-blue { color: $blue } +.color-blue2 { color: $blue2 } +.color-active-blue { color: $active-blue } +.color-active-blue-border { color: $active-blue-border } +.color-pink { color: $pink } + +/* color */ +.hover-white:hover { color: $white } +.hover-gray-light-shade:hover { color: $gray-light-shade } +.hover-gray-lightest:hover { color: $gray-lightest } +.hover-gray-light:hover { color: $gray-light } +.hover-gray-medium:hover { color: $gray-medium } +.hover-gray-dark:hover { color: $gray-dark } +.hover-gray-darkest:hover { color: $gray-darkest } +.hover-teal:hover { color: $teal } +.hover-teal-dark:hover { color: $teal-dark } +.hover-tealx:hover { color: $tealx } +.hover-tealx-light:hover { color: $tealx-light } +.hover-tealx-light-border:hover { color: $tealx-light-border } +.hover-orange:hover { color: $orange } +.hover-yellow:hover { color: $yellow } +.hover-yellow2:hover { color: $yellow2 } +.hover-orange-dark:hover { color: $orange-dark } +.hover-green:hover { color: $green } +.hover-green2:hover { color: $green2 } +.hover-green-dark:hover { color: $green-dark } +.hover-red:hover { color: $red } +.hover-red2:hover { color: $red2 } +.hover-blue:hover { color: $blue } +.hover-blue2:hover { color: $blue2 } +.hover-active-blue:hover { color: $active-blue } +.hover-active-blue-border:hover { color: $active-blue-border } +.hover-pink:hover { color: $pink } + +/* bg */ +.bg-white { background-color: $white } +.bg-gray-light-shade { background-color: $gray-light-shade } +.bg-gray-lightest { background-color: $gray-lightest } +.bg-gray-light { background-color: $gray-light } +.bg-gray-medium { background-color: $gray-medium } +.bg-gray-dark { background-color: $gray-dark } +.bg-gray-darkest { background-color: $gray-darkest } +.bg-teal { background-color: $teal } +.bg-teal-dark { background-color: $teal-dark } +.bg-tealx { background-color: $tealx } +.bg-tealx-light { background-color: $tealx-light } +.bg-tealx-light-border { background-color: $tealx-light-border } +.bg-orange { background-color: $orange } +.bg-yellow { background-color: $yellow } +.bg-yellow2 { background-color: $yellow2 } +.bg-orange-dark { background-color: $orange-dark } +.bg-green { background-color: $green } +.bg-green2 { background-color: $green2 } +.bg-green-dark { background-color: $green-dark } +.bg-red { background-color: $red } +.bg-red2 { background-color: $red2 } +.bg-blue { background-color: $blue } +.bg-blue2 { background-color: $blue2 } +.bg-active-blue { background-color: $active-blue } +.bg-active-blue-border { background-color: $active-blue-border } +.bg-pink { background-color: $pink } diff --git a/frontend/app/styles/flags.css b/frontend/app/styles/flags.css new file mode 100644 index 000000000..e8fbcab85 --- /dev/null +++ b/frontend/app/styles/flags.css @@ -0,0 +1 @@ +span.flag{width:44px;height:30px;display:inline-block}img.flag{width:30px}.flag{background:url(/img/flags_responsive.png) no-repeat;background-size:100%}.flag-ad{background-position:0 .413223%}.flag-ae{background-position:0 .826446%}.flag-af{background-position:0 1.239669%}.flag-ag{background-position:0 1.652893%}.flag-ai{background-position:0 2.066116%}.flag-al{background-position:0 2.479339%}.flag-am{background-position:0 2.892562%}.flag-an{background-position:0 3.305785%}.flag-ao{background-position:0 3.719008%}.flag-aq{background-position:0 4.132231%}.flag-ar{background-position:0 4.545455%}.flag-as{background-position:0 4.958678%}.flag-at{background-position:0 5.371901%}.flag-au{background-position:0 5.785124%}.flag-aw{background-position:0 6.198347%}.flag-az{background-position:0 6.61157%}.flag-ba{background-position:0 7.024793%}.flag-bb{background-position:0 7.438017%}.flag-bd{background-position:0 7.85124%}.flag-be{background-position:0 8.264463%}.flag-bf{background-position:0 8.677686%}.flag-bg{background-position:0 9.090909%}.flag-bh{background-position:0 9.504132%}.flag-bi{background-position:0 9.917355%}.flag-bj{background-position:0 10.330579%}.flag-bm{background-position:0 10.743802%}.flag-bn{background-position:0 11.157025%}.flag-bo{background-position:0 11.570248%}.flag-br{background-position:0 11.983471%}.flag-bs{background-position:0 12.396694%}.flag-bt{background-position:0 12.809917%}.flag-bv{background-position:0 13.22314%}.flag-bw{background-position:0 13.636364%}.flag-by{background-position:0 14.049587%}.flag-bz{background-position:0 14.46281%}.flag-ca{background-position:0 14.876033%}.flag-cc{background-position:0 15.289256%}.flag-cd{background-position:0 15.702479%}.flag-cf{background-position:0 16.115702%}.flag-cg{background-position:0 16.528926%}.flag-ch{background-position:0 16.942149%}.flag-ci{background-position:0 17.355372%}.flag-ck{background-position:0 17.768595%}.flag-cl{background-position:0 18.181818%}.flag-cm{background-position:0 18.595041%}.flag-cn{background-position:0 19.008264%}.flag-co{background-position:0 19.421488%}.flag-cr{background-position:0 19.834711%}.flag-cu{background-position:0 20.247934%}.flag-cv{background-position:0 20.661157%}.flag-cx{background-position:0 21.07438%}.flag-cy{background-position:0 21.487603%}.flag-cz{background-position:0 21.900826%}.flag-de{background-position:0 22.31405%}.flag-dj{background-position:0 22.727273%}.flag-dk{background-position:0 23.140496%}.flag-dm{background-position:0 23.553719%}.flag-do{background-position:0 23.966942%}.flag-dz{background-position:0 24.380165%}.flag-ec{background-position:0 24.793388%}.flag-ee{background-position:0 25.206612%}.flag-eg{background-position:0 25.619835%}.flag-eh{background-position:0 26.033058%}.flag-er{background-position:0 26.446281%}.flag-es{background-position:0 26.859504%}.flag-et{background-position:0 27.272727%}.flag-fi{background-position:0 27.68595%}.flag-fj{background-position:0 28.099174%}.flag-fk{background-position:0 28.512397%}.flag-fm{background-position:0 28.92562%}.flag-fo{background-position:0 29.338843%}.flag-fr{background-position:0 29.752066%}.flag-ga{background-position:0 30.165289%}.flag-gd{background-position:0 30.578512%}.flag-ge{background-position:0 30.991736%}.flag-gf{background-position:0 31.404959%}.flag-gh{background-position:0 31.818182%}.flag-gi{background-position:0 32.231405%}.flag-gl{background-position:0 32.644628%}.flag-gm{background-position:0 33.057851%}.flag-gn{background-position:0 33.471074%}.flag-gp{background-position:0 33.884298%}.flag-gq{background-position:0 34.297521%}.flag-gr{background-position:0 34.710744%}.flag-gs{background-position:0 35.123967%}.flag-gt{background-position:0 35.53719%}.flag-gu{background-position:0 35.950413%}.flag-gw{background-position:0 36.363636%}.flag-gy{background-position:0 36.77686%}.flag-hk{background-position:0 37.190083%}.flag-hm{background-position:0 37.603306%}.flag-hn{background-position:0 38.016529%}.flag-hr{background-position:0 38.429752%}.flag-ht{background-position:0 38.842975%}.flag-hu{background-position:0 39.256198%}.flag-id{background-position:0 39.669421%}.flag-ie{background-position:0 40.082645%}.flag-il{background-position:0 40.495868%}.flag-in{background-position:0 40.909091%}.flag-io{background-position:0 41.322314%}.flag-iq{background-position:0 41.735537%}.flag-ir{background-position:0 42.14876%}.flag-is{background-position:0 42.561983%}.flag-it{background-position:0 42.975207%}.flag-jm{background-position:0 43.38843%}.flag-jo{background-position:0 43.801653%}.flag-jp{background-position:0 44.214876%}.flag-ke{background-position:0 44.628099%}.flag-kg{background-position:0 45.041322%}.flag-kh{background-position:0 45.454545%}.flag-ki{background-position:0 45.867769%}.flag-km{background-position:0 46.280992%}.flag-kn{background-position:0 46.694215%}.flag-kp{background-position:0 47.107438%}.flag-kr{background-position:0 47.520661%}.flag-kw{background-position:0 47.933884%}.flag-ky{background-position:0 48.347107%}.flag-kz{background-position:0 48.760331%}.flag-la{background-position:0 49.173554%}.flag-lb{background-position:0 49.586777%}.flag-lc{background-position:0 50%}.flag-li{background-position:0 50.413223%}.flag-lk{background-position:0 50.826446%}.flag-lr{background-position:0 51.239669%}.flag-ls{background-position:0 51.652893%}.flag-lt{background-position:0 52.066116%}.flag-lu{background-position:0 52.479339%}.flag-lv{background-position:0 52.892562%}.flag-ly{background-position:0 53.305785%}.flag-ma{background-position:0 53.719008%}.flag-mc{background-position:0 54.132231%}.flag-md{background-position:0 54.545455%}.flag-me{background-position:0 54.958678%}.flag-mg{background-position:0 55.371901%}.flag-mh{background-position:0 55.785124%}.flag-mk{background-position:0 56.198347%}.flag-ml{background-position:0 56.61157%}.flag-mm{background-position:0 57.024793%}.flag-mn{background-position:0 57.438017%}.flag-mo{background-position:0 57.85124%}.flag-mp{background-position:0 58.264463%}.flag-mq{background-position:0 58.677686%}.flag-mr{background-position:0 59.090909%}.flag-ms{background-position:0 59.504132%}.flag-mt{background-position:0 59.917355%}.flag-mu{background-position:0 60.330579%}.flag-mv{background-position:0 60.743802%}.flag-mw{background-position:0 61.157025%}.flag-mx{background-position:0 61.570248%}.flag-my{background-position:0 61.983471%}.flag-mz{background-position:0 62.396694%}.flag-na{background-position:0 62.809917%}.flag-nc{background-position:0 63.22314%}.flag-ne{background-position:0 63.636364%}.flag-nf{background-position:0 64.049587%}.flag-ng{background-position:0 64.46281%}.flag-ni{background-position:0 64.876033%}.flag-nl{background-position:0 65.289256%}.flag-no{background-position:0 65.702479%}.flag-np{background-position:0 66.115702%}.flag-nr{background-position:0 66.528926%}.flag-nu{background-position:0 66.942149%}.flag-nz{background-position:0 67.355372%}.flag-om{background-position:0 67.768595%}.flag-pa{background-position:0 68.181818%}.flag-pe{background-position:0 68.595041%}.flag-pf{background-position:0 69.008264%}.flag-pg{background-position:0 69.421488%}.flag-ph{background-position:0 69.834711%}.flag-pk{background-position:0 70.247934%}.flag-pl{background-position:0 70.661157%}.flag-pm{background-position:0 71.07438%}.flag-pn{background-position:0 71.487603%}.flag-pr{background-position:0 71.900826%}.flag-pt{background-position:0 72.31405%}.flag-pw{background-position:0 72.727273%}.flag-py{background-position:0 73.140496%}.flag-qa{background-position:0 73.553719%}.flag-re{background-position:0 73.966942%}.flag-ro{background-position:0 74.380165%}.flag-rs{background-position:0 74.793388%}.flag-ru{background-position:0 75.206612%}.flag-rw{background-position:0 75.619835%}.flag-sa{background-position:0 76.033058%}.flag-sb{background-position:0 76.446281%}.flag-sc{background-position:0 76.859504%}.flag-sd{background-position:0 77.272727%}.flag-se{background-position:0 77.68595%}.flag-sg{background-position:0 78.099174%}.flag-sh{background-position:0 78.512397%}.flag-si{background-position:0 78.92562%}.flag-sj{background-position:0 79.338843%}.flag-sk{background-position:0 79.752066%}.flag-sl{background-position:0 80.165289%}.flag-sm{background-position:0 80.578512%}.flag-sn{background-position:0 80.991736%}.flag-so{background-position:0 81.404959%}.flag-sr{background-position:0 81.818182%}.flag-ss{background-position:0 82.231405%}.flag-st{background-position:0 82.644628%}.flag-sv{background-position:0 83.057851%}.flag-sy{background-position:0 83.471074%}.flag-sz{background-position:0 83.884298%}.flag-tc{background-position:0 84.297521%}.flag-td{background-position:0 84.710744%}.flag-tf{background-position:0 85.123967%}.flag-tg{background-position:0 85.53719%}.flag-th{background-position:0 85.950413%}.flag-tj{background-position:0 86.363636%}.flag-tk{background-position:0 86.77686%}.flag-tl{background-position:0 87.190083%}.flag-tm{background-position:0 87.603306%}.flag-tn{background-position:0 88.016529%}.flag-to{background-position:0 88.429752%}.flag-tp{background-position:0 88.842975%}.flag-tr{background-position:0 89.256198%}.flag-tt{background-position:0 89.669421%}.flag-tv{background-position:0 90.082645%}.flag-tw{background-position:0 90.495868%}.flag-ty{background-position:0 90.909091%}.flag-tz{background-position:0 91.322314%}.flag-ua{background-position:0 91.735537%}.flag-ug{background-position:0 92.14876%}.flag-gb,.flag-uk{background-position:0 92.561983%}.flag-um{background-position:0 92.975207%}.flag-us{background-position:0 93.38843%}.flag-uy{background-position:0 93.801653%}.flag-uz{background-position:0 94.214876%}.flag-va{background-position:0 94.628099%}.flag-vc{background-position:0 95.041322%}.flag-ve{background-position:0 95.454545%}.flag-vg{background-position:0 95.867769%}.flag-vi{background-position:0 96.280992%}.flag-vn{background-position:0 96.694215%}.flag-vu{background-position:0 97.107438%}.flag-wf{background-position:0 97.520661%}.flag-ws{background-position:0 97.933884%}.flag-ye{background-position:0 98.347107%}.flag-za{background-position:0 98.760331%}.flag-zm{background-position:0 99.173554%}.flag-zr{background-position:0 99.586777%}.flag-zw{background-position:0 100%} \ No newline at end of file diff --git a/frontend/app/styles/general.css b/frontend/app/styles/general.css new file mode 100644 index 000000000..e9ad78de4 --- /dev/null +++ b/frontend/app/styles/general.css @@ -0,0 +1,261 @@ +.ml-15 { margin-left: 15px; } + +.ph-10 { padding-left: 10px; padding-right: 10px; } +.ph-20 { padding-left: 20px; padding-right: 20px; } + + +.info.info.info.info.info { /* BAD HACK >:) */ + background-color: #f2f8ff; +} + +.warn.warn.warn.warn { + background-color: #fefaf4; +} + +.error.error.error.error { + background-color: #fcf2f2; +} + + +.thin-scrollbar { + scrollbar-width: thin; + &::-webkit-scrollbar { + width: 4px; + } +} + +.scroll-x { + overflow-x: auto; + scrollbar-width: thin; + &::-webkit-scrollbar { + width: 4px; + } +} +.scroll-y { + overflow-y: auto; + scrollbar-width: thin; + &::-webkit-scrollbar { + width: 4px; + } +} + +.grecaptcha-badge{ + display:none !important; +} + +.divider, +.divider-light { + height: 1px; + background-color: $gray-light; + margin: 25px 0; + + &.m5 { + margin: 5px 0; + } +} + +.divider-light { + border-color: $gray-lightest; + height: 2px; +} + +.font-size-10 { font-size: 10px; } +.font-size-12 { font-size: 12px; } +.font-size-16 { font-size: 16px; } +.font-size-20 { font-size: 20px; } + +.font-weight-regular { font-weight: 400; } +.font-weight-bold { font-weight: 600; } +.font-weight-thin { font-weight: 100; } + +.text-center { text-align: center; } + +.default-hover { + transition: all 0.4s; + &:hover { + /* background-color: $active-blue; */ + color: $teal; + transition: all 0.2s; + & a { + color: $teal; + } + & svg { + fill: $teal; + } + } +} + +.img-crcle { + border-radius: 50%; + box-shadow: 1px 1px 1px 1px rgba(0, 0, 0 0.3); +} + +.active-bg { + background-color: $active-blue; +} + +.border-b-light { + border-bottom: solid thin $gray-light; +} + +.mb-15-imp { + margin-bottom: 15px !important; +} + +.color-red { + color: $red; +} + +.InputContainer .InputElement, +.ElementsApp, .ElementsApp .InputElement { + font-size: 40px; + padding: 20px; + background-color: white !important; + border: solid thin white !important; +} + +.ui.modal>.content { + background-color: white !important; +} +.ui.modal>.actions { + text-align: left !important; + display: flex; + align-items: center; + justify-content: flex-start; +} + +.border-gray-light { + border: solid thin $gray-light +} + +.btn-disabled { + opacity: 0.5; + pointer-events: none; +} + +.code-font { + font-family: 'Menlo', 'monaco', 'consolas', monospace; + font-size: 13px; +} + +::placeholder { + color: $gray-medium !important; + font-size: 14px; +} + +.ui[class*="top fixed"].menu { + background-color: white !important; + border-bottom: solid thin #ddd !important; +} + +.border-radius-3 { + border-radius: 3px; +} + +.muted { + color: $gray-medium; +} + +.thin-gray-border { + border: 1px solid $gray-light; +} +.thin-blue-border { + border: 1px solid $active-blue-border; +} + +.speedIndexPopup { + font-size: 10px !important; + & span { + font-size: 10px; + margin-left: 10px; + } +} + +.fit-content { + width: fit-content; +} + +.gray-hover:hover { + background-color: $gray-light; + transition: all 0.4s; +} + +.quote:before { + position: absolute; + /* font-family: 'FontAwesome'; */ + top: 10px; + left: 0; + + content: "\201C"; + font-size: 140px; + color: rgba(0,0,0,0.1); +} + +.quote:after { + position: absolute; + /* font-family: 'FontAwesome'; */ + bottom: 10px; + right: 0; + + content: "\201E"; + font-size: 140px; + color: rgba(0,0,0,0.1); +} + +.cap-first:first-letter { + text-transform: capitalize +} + +.bg-hover { + transition: all 0.3s; + &:hover { + transition: all 0.2s; + background-color: $active-blue; + } +} + +.ui.progress:last-child { + margin: 0 !important; +} + +.blink-border { + /* border: 1px #ff0000 solid; */ + border-color: #CC0000; + + animation: blink 1s; + animation-iteration-count: 3; +} + +.underline-dashed { + text-decoration: underline; + text-decoration-style: dashed; + text-decoration-thickness: 2px; +} + +@keyframes blink { 50% { border-color:#fff ; } } + + +.highlight-gray { + background-color: $gray-medium; + color: white; + border-radius: 3px; + padding: 1px 2px; +} + +.hljs { + padding: 10px !important; + border-radius: 6px !important; + background-color: $gray-lightest !important; + font-size: 12px !important; +} + +p { + margin-bottom: 10px !important; +} + +.link { + color: $blue !important; + &:hover { + text-decoration: underline !important; + } +} \ No newline at end of file diff --git a/frontend/app/styles/import.css b/frontend/app/styles/import.css new file mode 100644 index 000000000..bc233c135 --- /dev/null +++ b/frontend/app/styles/import.css @@ -0,0 +1,7 @@ +@import 'react-toastify/dist/ReactToastify.css'; +@import 'react-circular-progressbar/dist/styles.css'; +@import 'highlight.js/styles/github-gist.css'; + +@import "tailwindcss/base"; +@import "tailwindcss/components"; +@import "tailwindcss/utilities"; \ No newline at end of file diff --git a/frontend/app/styles/import/animations.css b/frontend/app/styles/import/animations.css new file mode 100644 index 000000000..875415980 --- /dev/null +++ b/frontend/app/styles/import/animations.css @@ -0,0 +1,33 @@ +@keyframes fade { + 0% { opacity: 0} + 100% { opacity: 1} +} + +@keyframes shake { + 10%, 90% { + transform: translate3d(-1px, 0, 0); + } + + 20%, 80% { + transform: translate3d(2px, 0, 0); + } + + 30%, 50%, 70% { + transform: translate3d(-2px, 0, 0); + } + + 40%, 60% { + transform: translate3d(2px, 0, 0); + } +} + +@define-mixin fade $time: 1s { + animation: fade $time; +} + +@define-mixin shake { + animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both; + transform: translate3d(0, 0, 0); + backface-visibility: hidden; + perspective: 1000px; +} \ No newline at end of file diff --git a/frontend/app/styles/import/icons.css b/frontend/app/styles/import/icons.css new file mode 100644 index 000000000..50256ac72 --- /dev/null +++ b/frontend/app/styles/import/icons.css @@ -0,0 +1,22 @@ +@define-mixin icon $name, $color, $size, $display: block { + width: $size; + height: $size; + display: $display; + background-image: svg-load(icons/$(name).svg, fill=$color); + background-repeat: no-repeat; + background-size: contain; + background-position: center center; +} + +@define-mixin icon-before $name, $color, $size { + &::before { + content: ''; + @mixin icon $name, $color, $size, inline-block; + /* vertical-align: text-bottom; */ + margin-right: 5px; + display: inline-block; + vertical-align: middle; + margin-top: -2px; + @mixin-content; + } +} diff --git a/frontend/app/styles/import/mixins.css b/frontend/app/styles/import/mixins.css new file mode 100644 index 000000000..2d593a3d7 --- /dev/null +++ b/frontend/app/styles/import/mixins.css @@ -0,0 +1,69 @@ +@define-mixin shadow-light { + box-shadow: 0 1px 5px 0 $gray-light; +} + +@define-mixin shadow { + box-shadow: 0 2px 10px 0 $gray-light; +} + +@define-mixin shadow-button { + cursor: pointer; + border: 1px solid transparent; + border-radius: 3px; + box-shadow: 0px 1px 3px 0 $gray-light; + + &:hover { + border-color: $active-blue-border; + background-color: $active-blue; + } +} + +@define-mixin defaultHover { + transition: all 0.4s; + &:hover { + background-color: $active-blue; + border: solid thin $active-blue-border; + transition: all 0.2s; + } +} + +@define-mixin card { + padding: 10px 15px; + border-radius: 3px; + margin-bottom: 10px; + border: solid thin transparent; +} + +@define-mixin basicButton { + background-color: white !important; + border: solid thin $active-blue-border !important; + color: $teal !important; + &:hover { + background-color: $active-blue !important; + } +} + +@define-mixin plainButton { + background-color: transparent !important; + border: solid thin transparent !important; + color: $teal !important; + &:hover { + background-color: $active-blue !important; + } +} + +@define-mixin primaryButton { + background-color: $teal !important; + color: white !important; + &:hover { + background-color: $teal-dark !important; + } +} + +@define-mixin cssHighLight { + color: #CC66CC !important; + border-radius: 15px; + padding: 5px 15px; + box-shadow: 0px 1px 3px 0 $gray-light; + background-color: #F8F8F8 !important; +} \ No newline at end of file diff --git a/frontend/app/styles/import/zindex.css b/frontend/app/styles/import/zindex.css new file mode 100644 index 000000000..2ddd35cef --- /dev/null +++ b/frontend/app/styles/import/zindex.css @@ -0,0 +1,4 @@ +$header: 100; +$slideOut: 101; +$codeSnippet: 99; +$positionTracker: 98; \ No newline at end of file diff --git a/frontend/app/styles/main.css b/frontend/app/styles/main.css new file mode 100644 index 000000000..c77533f3c --- /dev/null +++ b/frontend/app/styles/main.css @@ -0,0 +1,109 @@ +#app { + padding: 0; + min-height: 100%; + display: flex; + flex-direction: column; +} + +* { + border-color: #EEEEEE; +} +.page { + padding-top: 50px; +} +.page-margin { + padding-top: 81px; +} + +.container-fit { + margin: 0 30px 0px; +} + +.container { + margin: 0 30px 30px; +} + +@media only screen and (max-width: 1380px) { + .container-70 { + width: 90%; + } +} + +@media only screen and (min-width: 1380px) { + .container-70 { + width: 1280px; + } +} + +.container-70 { + position: relative; + margin: 0 auto; +} + +.container-90 { + width: 98%; + margin: 0 auto; +} + +.side-menu { + width: 250px; + height: calc(100vh - 80px); + overflow-y: auto; + padding-right: 20px; + position: fixed; + top: 81px; + &::-webkit-scrollbar { + width: 0px; + } + &:hover { + &::-webkit-scrollbar { + width: 0px; + } + } +} +.side-menu-margined { + margin-left: 260px; +} + +.top-header { + margin-bottom: 25px; + /* border: dashed thin gray; */ + min-height: 40px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.page-title { + font-size: 22px; + margin-right: 15px; + + & > span { + font-weight: 300; + } + + & .title { + margin-right: 15px; + + & span { + color: $gray-medium; + font-weight: 300; + } + } +} + +.page-title-flex { + display: flex; + align-items: center; +} + +[data-hidden=true] { + display: none !important; +} + +[data-disabled=true] { + pointer-events: none; + opacity: .5; +} + + diff --git a/frontend/app/styles/rc-time-picker.css b/frontend/app/styles/rc-time-picker.css new file mode 100644 index 000000000..f608baebc --- /dev/null +++ b/frontend/app/styles/rc-time-picker.css @@ -0,0 +1,3 @@ +.rc-time-picker .rc-time-picker-input { + color: $gray-darkest; +} \ No newline at end of file diff --git a/frontend/app/styles/react-datepicker.css b/frontend/app/styles/react-datepicker.css new file mode 100644 index 000000000..7a5ab2fd8 --- /dev/null +++ b/frontend/app/styles/react-datepicker.css @@ -0,0 +1,15 @@ +.react-datepicker { + box-shadow: 0px 1px 3px 0 $gray-light; +} +.react-datepicker__triangle, +.react-datepicker__header { + /* background-color: white; */ +} +.react-datepicker__day--selected:hover { + background-color: $teal-dark; +} + +.react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--selected, +.react-datepicker__day--selected { + background-color: $teal; +} \ No newline at end of file diff --git a/frontend/app/styles/react-daterange-picker.css b/frontend/app/styles/react-daterange-picker.css new file mode 100644 index 000000000..cc4b18fac --- /dev/null +++ b/frontend/app/styles/react-daterange-picker.css @@ -0,0 +1,8 @@ +.DateRangePicker__CalendarSelection--is-pending, +.DateRangePicker__CalendarSelection .DateRangePicker__CalendarSelection--start, +.DateRangePicker__CalendarSelection .DateRangePicker__CalendarSelection--segment, +.DateRangePicker__CalendarSelection .DateRangePicker__CalendarSelection--end, +.DateRangePicker__CalendarSelection { + background-color: $teal !important; + border-color: $teal !important; +} \ No newline at end of file diff --git a/frontend/app/styles/react-json-view.css b/frontend/app/styles/react-json-view.css new file mode 100644 index 000000000..126dfe783 --- /dev/null +++ b/frontend/app/styles/react-json-view.css @@ -0,0 +1,6 @@ +.react-json-view { + font-size: 13px !important; + & .node-ellipsis { + font-size: 11px !important; + } +} \ No newline at end of file diff --git a/frontend/app/styles/recharts.css b/frontend/app/styles/recharts.css new file mode 100644 index 000000000..57d18f38d --- /dev/null +++ b/frontend/app/styles/recharts.css @@ -0,0 +1,7 @@ +.recharts-legend-item { + padding: 0 10px; +} + +.recharts-legend-item-text { + user-select: none; +} \ No newline at end of file diff --git a/frontend/app/styles/reset.css b/frontend/app/styles/reset.css new file mode 100644 index 000000000..00c96826b --- /dev/null +++ b/frontend/app/styles/reset.css @@ -0,0 +1,50 @@ +* { + margin: 0; + padding: 0; + border-radius: 0; + text-decoration: none; + outline: none; +} + +body, html { + height: 100%; + background: $gray-lightest; + font-family: 'Roboto', 'ArialMT', 'Arial'; + font-size: 14px; + font-weight: 400; + color: $gray-darkest; +} + +input, button { + background: none; + border: none; + border: solid thin transparent; +} + +button { + font-weight: 400; +} + +textarea:focus, +input:focus { + border: solid thin $teal !important; +} + +body ::-webkit-scrollbar { + width: 2px; + height: 2px; +} + +h1, h2, h3, h4, h5 { + font-family: 'Roboto', 'ArialMT', 'Arial'; + font-weight: 500; +} + +* { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +button:focus { + outline: none; +} diff --git a/frontend/app/styles/semantic.css b/frontend/app/styles/semantic.css new file mode 100644 index 000000000..3998ff6ff --- /dev/null +++ b/frontend/app/styles/semantic.css @@ -0,0 +1,310 @@ +@import "icons.css"; + +.ui.dropdown .menu { + z-index: 1900; +} +.ui.dropdown .menu>.item { + color: #454545; +} +.customDropdownSmall { + min-width: 70px !important; +} + +.customDropdown { + min-height: 0 !important; + height: 30px !important; + padding: 0 !important; + display: flex !important; + align-items: center !important; + padding: 0 8px !important; + font-weight: normal !important; +} +.ui.selection.active.customDropdown .menu { + border-color: $teal !important; +} +.ui.search.customDropdown>input.search, +.ui.search.customDropdown.active>input.search, +.ui.search.customDropdown.visible>input.search { + padding: 6px !important; +} + +.ui.search.customDropdown>.text { + max-width: 90%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.ui.selection.customDropdown>.dropdown.icon { + top: 5px !important; +} + +.ui.selection.customDropdown>.search.icon { + padding: 6px !important; +} + +.customLightDropdown { + min-height: 0 !important; + height: 37px !important; + padding: 0 !important; + display: flex !important; + align-items: center !important; + padding: 0 8px !important; + font-weight: normal !important; + color: $gray-dark !important; + border: solid thin $gray-light !important; +} +.ui.selection.active.customLightDropdown .menu { + border-color: $teal !important; +} +.ui.selection.customLightDropdown>.dropdown.icon { + top: 8px !important; +} +.ui.selection.customLightDropdown:focus { + border-color: $teal !important; +} + +.ui.modal>.header { + border-bottom: none !important; + box-shadow: 0px 1px 3px 0 rgba(0, 0, 0, 1) !important; +} + +.ui.modal>.content { + background-color: $gray-lightest; +} + +.ui.modal>.actions { + background-color: #FFF !important; + border-top: none !important; + text-align: left !important; +} + +.ui.input input { + padding: 8.5px !important; +} + +.ui.form .field { + margin-bottom: 25px; +} +.ui.form .field>label { + font-weight: 500 !important; + font-size: 14px !important; +} + +.ui.searchDropdown .menu>.item { + padding: 0 !important; + border-bottom: solid thin $gray-lightest !important; +} + +.ui.searchDropdown { + & .ui.dropdown { + height: 46px !important; + } + & .ui.input { + width: 100% !important; + height: 46px !important; + font-size: 16px !important; + + & input { + border: none !important; + border-radius: 0; + } + } + &.small .ui.input { + height: 36px !important; + } + & .menu { + width: 100%; + + & .header { + color: $gray-medium; + } + + & > .item { + padding: 0 !important; + color: $gray-dark; + &:hover { + background-color: $active-blue !important; + } + } + } +} + +.ui.customCheckbox { + z-index: 1; +} +.ui.customCheckbox label { + color: $gray-darkest; + font-weight: 400; +} + +.ui.customCheckbox label:after { + font-size: 12px !important; + color: $teal !important; +} + +.ui.radio.customCheckbox input:checked~label:after { + background-color: $teal !important; +} + +.ui.toggle.customCheckbox label:before { + width: 44px; + height: 27px; +} + +.ui.toggle.customCheckbox { + & input~label:after { + top: 1px; + left: 1px; + width: 25px; + height: 25px; + @mixin icon check, $gray-light; + background-size: 15px 15px !important; + padding: 5px; + } + + & input:checked~label:after { + left: 18px; + @mixin icon check, $tealx; + background-size: 15px 15px !important; + } +} + +.ui.toggle.checkbox input:checked~.box:before, +.ui.toggle.checkbox.customCheckbox input:checked~label:before { + background-color: $tealx !important; +} + +.customInput { + height: 29px; + + & .ui.label { + font-weight: 300 !important; + padding: 7px 10px !important; + } +} + +.ui.input input, +.ui.button { + font-family: 'Roboto', 'ArialMT', 'Arial' !important; +} +.ui.small.button { + height: 32px !important; + padding: 5px 10px !important; +} + +.ui.smallest.button { + height: 26px !important; + padding: 3px 10px !important; + font-size: 12px !important; +} + +.ui.button:disabled { + cursor: not-allowed !important; +} + +.ui.button.copy-button { + background-color: #ffff !important; + box-shadow: inset 0px 0px 0px 1px #ddd; + font-weight: 400; + text-transform: uppercase; +} + +.ui.selection.dropdown>.search.icon { + padding: 10px; +} + +.input-small { + height: 30px !important; +} + +.customPopupText { + font-family: 'menlo', 'monaco', 'consolas', monospace !important; + letter-spacing: -.04em; + font-size: .9rem; +} + +.ui.styled.accordion .title { + color: $gray-dark; +} + +.filterDropdown { + padding: 6px !important; + min-height: 28px !important; + font-size: 13px !important; + &.ui.search.selection.dropdown { + & >input.search { + padding: 5px !important; + color: $gray-medium !important; + padding-right: 30px !important; + text-overflow: ellipsis; + } + } + & .ui.label { + background-color: transparent !important; + font-weight: 300; + font-size: 12px; + padding: 4px 12px !important; + } + + & i, + & .search.icon { + color: $gray-medium !important; + top: 3px !important; + right: 8px !important; + }, + + & i, + & .delete.icon { + padding: 0 !important; + } +} + +.ui.multiple.search.dropdown>.text { + padding: 5px !important; + margin: 0 !important; + font-size: 13px !important; +} + +.ui.multiple.search.dropdown> input { + padding: 0 !important; +} + +.ui.dropdown:not(.button) > .default.text { + color: $gray-medium; +} + +.ui.selection.active.dropdown, +.ui.selection.active.dropdown .menu { + border-color: $teal !important; +} + +.ui.toggle.checkbox { + min-height: 1.9rem !important; +} + +.ui { + &.modal { + box-shadow: none; + border: solid thin $gray-light; + &>.header { + border-bottom: solid thin $gray-light !important; + box-shadow: none !important; + } + } + + &.dimmer { + background-color: rgba(0, 0, 0, 0.5); + } +} + +.confirmCustom { + & .actions { + display: flex !important; + flex-direction: row-reverse !important; + justify-content: flex-end !important; + } +} + +a:hover { + color: $teal; +} \ No newline at end of file diff --git a/frontend/app/styles/toastify.css b/frontend/app/styles/toastify.css new file mode 100644 index 000000000..e31b0af39 --- /dev/null +++ b/frontend/app/styles/toastify.css @@ -0,0 +1,33 @@ +.Toastify__close-button { + text-indent: -1000em; + content: ''; + width: 15px; + height: 15px; + display: block; + background-image: svg-load(icons/close.svg, fill=gray-medium) !important; + background-repeat: no-repeat !important; + background-size: contain !important; + background-position: center center !important; +} +.Toastify__toast { + background-color: white !important; + color: $gray-medium; + border-left: solid 5px transparent; + + &.Toastify__toast--default { + border-color: $teal; + } + &.Toastify__toast--info { + border-color: $yellow; + } + &.Toastify__toast--success { + border-color: $teal; + } + &.Toastify__toast--warning { + background: $orange; + } + &.Toastify__toast--error { + background: $red; + border-color: $red; + } +} \ No newline at end of file diff --git a/frontend/app/svg/asayer-animated-logo-preloader.svg b/frontend/app/svg/asayer-animated-logo-preloader.svg new file mode 100644 index 000000000..fce03ad03 --- /dev/null +++ b/frontend/app/svg/asayer-animated-logo-preloader.svg @@ -0,0 +1,12 @@ +<svg viewBox="0 0 60 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="rkM2Lz-JX"><style>@-webkit-keyframes S1XG2Uf-km_Animation{13.33%{opacity: 0;}50%{opacity: 1;}90%{opacity: 0;}0%{opacity: 0;}100%{opacity: 0;}}@keyframes S1XG2Uf-km_Animation{13.33%{opacity: 0;}50%{opacity: 1;}90%{opacity: 0;}0%{opacity: 0;}100%{opacity: 0;}}@-webkit-keyframes S1XG2Uf-km_By9FtGZJm_Animation{13.33%{-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}50%{-webkit-transform: translate(0px, 0px);transform: translate(0px, 0px);}90%{-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}0%{-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}100%{-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}}@keyframes S1XG2Uf-km_By9FtGZJm_Animation{13.33%{-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}50%{-webkit-transform: translate(0px, 0px);transform: translate(0px, 0px);}90%{-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}0%{-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}100%{-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}}@-webkit-keyframes S1XG2Uf-km_BkKXYzZyX_Animation{13.33%{-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}50%{-webkit-transform: scale(1, 1);transform: scale(1, 1);}90%{-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}0%{-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}100%{-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}}@keyframes S1XG2Uf-km_BkKXYzZyX_Animation{13.33%{-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}50%{-webkit-transform: scale(1, 1);transform: scale(1, 1);}90%{-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}0%{-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}100%{-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}}@-webkit-keyframes SkzMhIGbkX_Animation{0%{opacity: 0;}30%{opacity: 1;}80%{opacity: 0;}100%{opacity: 0;}}@keyframes SkzMhIGbkX_Animation{0%{opacity: 0;}30%{opacity: 1;}80%{opacity: 0;}100%{opacity: 0;}}@-webkit-keyframes SkzMhIGbkX_Hk0twGWyQ_Animation{0%{-webkit-transform: scale(0.5, 0.5);transform: scale(0.5, 0.5);}30%{-webkit-transform: scale(1, 1);transform: scale(1, 1);}80%{-webkit-transform: scale(0.5, 0.5);transform: scale(0.5, 0.5);}100%{-webkit-transform: scale(0.5, 0.5);transform: scale(0.5, 0.5);}}@keyframes SkzMhIGbkX_Hk0twGWyQ_Animation{0%{-webkit-transform: scale(0.5, 0.5);transform: scale(0.5, 0.5);}30%{-webkit-transform: scale(1, 1);transform: scale(1, 1);}80%{-webkit-transform: scale(0.5, 0.5);transform: scale(0.5, 0.5);}100%{-webkit-transform: scale(0.5, 0.5);transform: scale(0.5, 0.5);}}#rkM2Lz-JX *{-webkit-animation-duration: 1s;animation-duration: 1s;-webkit-animation-iteration-count: infinite;animation-iteration-count: infinite;-webkit-animation-timing-function: cubic-bezier(0, 0, 1, 1);animation-timing-function: cubic-bezier(0, 0, 1, 1);}#HJgGnUfZ1X{stroke: none;stroke-width: 1;fill: none;}#H1ZMhLG-J7{-webkit-transform: translate(3.000000px, 5.000000px);transform: translate(3.000000px, 5.000000px);}#SkzMhIGbkX{fill: #3EAAAF;-webkit-animation-name: SkzMhIGbkX_Animation;animation-name: SkzMhIGbkX_Animation;-webkit-transform-origin: 50% 50%;transform-origin: 50% 50%;transform-box: fill-box;opacity: 0;}#S1XG2Uf-km{fill: #42AE5E;-webkit-transform: translate(32.500000px, 19.000000px) rotate(-1.000000deg) translate(-32.500000px, -19.000000px);transform: translate(32.500000px, 19.000000px) rotate(-1.000000deg) translate(-32.500000px, -19.000000px);-webkit-transform-origin: 0% 100%;transform-origin: 0% 100%;transform-box: fill-box;-webkit-animation-name: S1XG2Uf-km_Animation;animation-name: S1XG2Uf-km_Animation;opacity: 0;}#SkzMhIGbkX_Hk0twGWyQ{-webkit-animation-name: SkzMhIGbkX_Hk0twGWyQ_Animation;animation-name: SkzMhIGbkX_Hk0twGWyQ_Animation;-webkit-transform-origin: 50% 50%;transform-origin: 50% 50%;transform-box: fill-box;-webkit-transform: scale(0.5, 0.5);transform: scale(0.5, 0.5);}#S1XG2Uf-km_BkKXYzZyX{-webkit-animation-name: S1XG2Uf-km_BkKXYzZyX_Animation;animation-name: S1XG2Uf-km_BkKXYzZyX_Animation;-webkit-transform-origin: 0% 100%;transform-origin: 0% 100%;transform-box: fill-box;-webkit-transform: scale(0.1, 0.1);transform: scale(0.1, 0.1);}#S1XG2Uf-km_By9FtGZJm{-webkit-animation-name: S1XG2Uf-km_By9FtGZJm_Animation;animation-name: S1XG2Uf-km_By9FtGZJm_Animation;-webkit-transform-origin: 0% 100%;transform-origin: 0% 100%;transform-box: fill-box;-webkit-transform: translate(10px, -7px);transform: translate(10px, -7px);}</style> + <!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch --> + <title>Artboard + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/empty-state.svg b/frontend/app/svg/empty-state.svg new file mode 100644 index 000000000..dda1ef2bd --- /dev/null +++ b/frontend/app/svg/empty-state.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/app/svg/icons/alarm-clock.svg b/frontend/app/svg/icons/alarm-clock.svg new file mode 100644 index 000000000..ed50f8525 --- /dev/null +++ b/frontend/app/svg/icons/alarm-clock.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/alarm-plus.svg b/frontend/app/svg/icons/alarm-plus.svg new file mode 100644 index 000000000..1c20d18ff --- /dev/null +++ b/frontend/app/svg/icons/alarm-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/all-sessions.svg b/frontend/app/svg/icons/all-sessions.svg new file mode 100644 index 000000000..76c282172 --- /dev/null +++ b/frontend/app/svg/icons/all-sessions.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/analytics.svg b/frontend/app/svg/icons/analytics.svg new file mode 100644 index 000000000..1308e6f79 --- /dev/null +++ b/frontend/app/svg/icons/analytics.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/anchor.svg b/frontend/app/svg/icons/anchor.svg new file mode 100644 index 000000000..a9b2a323f --- /dev/null +++ b/frontend/app/svg/icons/anchor.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/arrow-alt-square-right.svg b/frontend/app/svg/icons/arrow-alt-square-right.svg new file mode 100644 index 000000000..362d29247 --- /dev/null +++ b/frontend/app/svg/icons/arrow-alt-square-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/arrow-down.svg b/frontend/app/svg/icons/arrow-down.svg new file mode 100644 index 000000000..3d639059e --- /dev/null +++ b/frontend/app/svg/icons/arrow-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/arrow-square-left.svg b/frontend/app/svg/icons/arrow-square-left.svg new file mode 100644 index 000000000..86b9fbbae --- /dev/null +++ b/frontend/app/svg/icons/arrow-square-left.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/arrow-square-right.svg b/frontend/app/svg/icons/arrow-square-right.svg new file mode 100644 index 000000000..3a17ca991 --- /dev/null +++ b/frontend/app/svg/icons/arrow-square-right.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/arrow-up.svg b/frontend/app/svg/icons/arrow-up.svg new file mode 100644 index 000000000..0ae30e0da --- /dev/null +++ b/frontend/app/svg/icons/arrow-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/avatar/icn_bear.svg b/frontend/app/svg/icons/avatar/icn_bear.svg new file mode 100644 index 000000000..9bf25b731 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_bear.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_beaver.svg b/frontend/app/svg/icons/avatar/icn_beaver.svg new file mode 100644 index 000000000..b2d657aaf --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_beaver.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_bird.svg b/frontend/app/svg/icons/avatar/icn_bird.svg new file mode 100644 index 000000000..52f5afc09 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_bird.svg @@ -0,0 +1,20 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_bison.svg b/frontend/app/svg/icons/avatar/icn_bison.svg new file mode 100644 index 000000000..902875628 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_bison.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_camel.svg b/frontend/app/svg/icons/avatar/icn_camel.svg new file mode 100644 index 000000000..68845fa30 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_camel.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_chameleon.svg b/frontend/app/svg/icons/avatar/icn_chameleon.svg new file mode 100644 index 000000000..433664da7 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_chameleon.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_deer.svg b/frontend/app/svg/icons/avatar/icn_deer.svg new file mode 100644 index 000000000..5d99f079f --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_deer.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_dog.svg b/frontend/app/svg/icons/avatar/icn_dog.svg new file mode 100644 index 000000000..df62228f8 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_dog.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_dolphin.svg b/frontend/app/svg/icons/avatar/icn_dolphin.svg new file mode 100644 index 000000000..76b0c270f --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_dolphin.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_elephant.svg b/frontend/app/svg/icons/avatar/icn_elephant.svg new file mode 100644 index 000000000..e8d9b3032 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_elephant.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_fish.svg b/frontend/app/svg/icons/avatar/icn_fish.svg new file mode 100644 index 000000000..c559e63b8 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_fish.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_fox.svg b/frontend/app/svg/icons/avatar/icn_fox.svg new file mode 100644 index 000000000..1b37e2085 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_fox.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_gorilla.svg b/frontend/app/svg/icons/avatar/icn_gorilla.svg new file mode 100644 index 000000000..58de666a5 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_gorilla.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_hippo.svg b/frontend/app/svg/icons/avatar/icn_hippo.svg new file mode 100644 index 000000000..178abb4a7 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_hippo.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_horse.svg b/frontend/app/svg/icons/avatar/icn_horse.svg new file mode 100644 index 000000000..b345d4232 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_horse.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_hyena.svg b/frontend/app/svg/icons/avatar/icn_hyena.svg new file mode 100644 index 000000000..02f14b658 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_hyena.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_kangaroo.svg b/frontend/app/svg/icons/avatar/icn_kangaroo.svg new file mode 100644 index 000000000..83b259f08 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_kangaroo.svg @@ -0,0 +1,32 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_lemur.svg b/frontend/app/svg/icons/avatar/icn_lemur.svg new file mode 100644 index 000000000..6070b0661 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_lemur.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_mammel.svg b/frontend/app/svg/icons/avatar/icn_mammel.svg new file mode 100644 index 000000000..7c751b1e2 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_mammel.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_monkey.svg b/frontend/app/svg/icons/avatar/icn_monkey.svg new file mode 100644 index 000000000..6a4ad3c72 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_monkey.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_moose.svg b/frontend/app/svg/icons/avatar/icn_moose.svg new file mode 100644 index 000000000..64299937d --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_moose.svg @@ -0,0 +1,18 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_panda.svg b/frontend/app/svg/icons/avatar/icn_panda.svg new file mode 100644 index 000000000..48a058420 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_panda.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_penguin.svg b/frontend/app/svg/icons/avatar/icn_penguin.svg new file mode 100644 index 000000000..02d504f1b --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_penguin.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_porcupine.svg b/frontend/app/svg/icons/avatar/icn_porcupine.svg new file mode 100644 index 000000000..35507abab --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_porcupine.svg @@ -0,0 +1,17 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_quail.svg b/frontend/app/svg/icons/avatar/icn_quail.svg new file mode 100644 index 000000000..a5f48cef6 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_quail.svg @@ -0,0 +1,56 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_rabbit.svg b/frontend/app/svg/icons/avatar/icn_rabbit.svg new file mode 100644 index 000000000..6ec7970e4 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_rabbit.svg @@ -0,0 +1,50 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_rhino.svg b/frontend/app/svg/icons/avatar/icn_rhino.svg new file mode 100644 index 000000000..fff01c05a --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_rhino.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_sea_horse.svg b/frontend/app/svg/icons/avatar/icn_sea_horse.svg new file mode 100644 index 000000000..75cca0c89 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_sea_horse.svg @@ -0,0 +1,28 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_sheep.svg b/frontend/app/svg/icons/avatar/icn_sheep.svg new file mode 100644 index 000000000..3d22a87a3 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_sheep.svg @@ -0,0 +1,47 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_snake.svg b/frontend/app/svg/icons/avatar/icn_snake.svg new file mode 100644 index 000000000..9a24b92fc --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_snake.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_squirrel.svg b/frontend/app/svg/icons/avatar/icn_squirrel.svg new file mode 100644 index 000000000..4314fc5ea --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_squirrel.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_tapir.svg b/frontend/app/svg/icons/avatar/icn_tapir.svg new file mode 100644 index 000000000..3edf5886d --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_tapir.svg @@ -0,0 +1,26 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_turtle.svg b/frontend/app/svg/icons/avatar/icn_turtle.svg new file mode 100644 index 000000000..1baca33bf --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_turtle.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_vulture.svg b/frontend/app/svg/icons/avatar/icn_vulture.svg new file mode 100644 index 000000000..02e512800 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_vulture.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_wild1.svg b/frontend/app/svg/icons/avatar/icn_wild1.svg new file mode 100644 index 000000000..9eea2fcdc --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_wild1.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/frontend/app/svg/icons/avatar/icn_wild_bore.svg b/frontend/app/svg/icons/avatar/icn_wild_bore.svg new file mode 100644 index 000000000..62e6f9ed9 --- /dev/null +++ b/frontend/app/svg/icons/avatar/icn_wild_bore.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/app/svg/icons/ban.svg b/frontend/app/svg/icons/ban.svg new file mode 100644 index 000000000..f7033560d --- /dev/null +++ b/frontend/app/svg/icons/ban.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/bell-plus.svg b/frontend/app/svg/icons/bell-plus.svg new file mode 100644 index 000000000..81b12e917 --- /dev/null +++ b/frontend/app/svg/icons/bell-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/bell.svg b/frontend/app/svg/icons/bell.svg new file mode 100644 index 000000000..a29612ab8 --- /dev/null +++ b/frontend/app/svg/icons/bell.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/book.svg b/frontend/app/svg/icons/book.svg new file mode 100644 index 000000000..74b49ecfe --- /dev/null +++ b/frontend/app/svg/icons/book.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/browser/browser.svg b/frontend/app/svg/icons/browser/browser.svg new file mode 100644 index 000000000..9718fa3dc --- /dev/null +++ b/frontend/app/svg/icons/browser/browser.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/browser/chrome.svg b/frontend/app/svg/icons/browser/chrome.svg new file mode 100644 index 000000000..0419c20e4 --- /dev/null +++ b/frontend/app/svg/icons/browser/chrome.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/browser/edge.svg b/frontend/app/svg/icons/browser/edge.svg new file mode 100644 index 000000000..cba374011 --- /dev/null +++ b/frontend/app/svg/icons/browser/edge.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/browser/electron.svg b/frontend/app/svg/icons/browser/electron.svg new file mode 100644 index 000000000..54071ba22 --- /dev/null +++ b/frontend/app/svg/icons/browser/electron.svg @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/browser/facebook.svg b/frontend/app/svg/icons/browser/facebook.svg new file mode 100644 index 000000000..756ca1f2f --- /dev/null +++ b/frontend/app/svg/icons/browser/facebook.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/browser/firefox.svg b/frontend/app/svg/icons/browser/firefox.svg new file mode 100644 index 000000000..0cd9676e7 --- /dev/null +++ b/frontend/app/svg/icons/browser/firefox.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/browser/ie.svg b/frontend/app/svg/icons/browser/ie.svg new file mode 100644 index 000000000..dbae84ee3 --- /dev/null +++ b/frontend/app/svg/icons/browser/ie.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/browser/opera.svg b/frontend/app/svg/icons/browser/opera.svg new file mode 100644 index 000000000..1417ef2c0 --- /dev/null +++ b/frontend/app/svg/icons/browser/opera.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/browser/safari.svg b/frontend/app/svg/icons/browser/safari.svg new file mode 100644 index 000000000..afd65e134 --- /dev/null +++ b/frontend/app/svg/icons/browser/safari.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/bullhorn.svg b/frontend/app/svg/icons/bullhorn.svg new file mode 100644 index 000000000..7ad8a919a --- /dev/null +++ b/frontend/app/svg/icons/bullhorn.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/business-time.svg b/frontend/app/svg/icons/business-time.svg new file mode 100644 index 000000000..0d21e98dd --- /dev/null +++ b/frontend/app/svg/icons/business-time.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/calendar-alt.svg b/frontend/app/svg/icons/calendar-alt.svg new file mode 100644 index 000000000..61374859d --- /dev/null +++ b/frontend/app/svg/icons/calendar-alt.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/calendar-check.svg b/frontend/app/svg/icons/calendar-check.svg new file mode 100644 index 000000000..e82b0e53a --- /dev/null +++ b/frontend/app/svg/icons/calendar-check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/calendar-day.svg b/frontend/app/svg/icons/calendar-day.svg new file mode 100644 index 000000000..5a5141315 --- /dev/null +++ b/frontend/app/svg/icons/calendar-day.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/calendar.svg b/frontend/app/svg/icons/calendar.svg new file mode 100644 index 000000000..ef6a844a7 --- /dev/null +++ b/frontend/app/svg/icons/calendar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/camera-alt.svg b/frontend/app/svg/icons/camera-alt.svg new file mode 100644 index 000000000..3c2e12aac --- /dev/null +++ b/frontend/app/svg/icons/camera-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/camera.svg b/frontend/app/svg/icons/camera.svg new file mode 100644 index 000000000..8859d9af5 --- /dev/null +++ b/frontend/app/svg/icons/camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/caret-down-fill.svg b/frontend/app/svg/icons/caret-down-fill.svg new file mode 100644 index 000000000..b3ee2ea95 --- /dev/null +++ b/frontend/app/svg/icons/caret-down-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/caret-up-fill.svg b/frontend/app/svg/icons/caret-up-fill.svg new file mode 100644 index 000000000..b4c7e5485 --- /dev/null +++ b/frontend/app/svg/icons/caret-up-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/chat-dots.svg b/frontend/app/svg/icons/chat-dots.svg new file mode 100644 index 000000000..a0c2bc338 --- /dev/null +++ b/frontend/app/svg/icons/chat-dots.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/chat-square-quote.svg b/frontend/app/svg/icons/chat-square-quote.svg new file mode 100644 index 000000000..daa9f0141 --- /dev/null +++ b/frontend/app/svg/icons/chat-square-quote.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/check-circle.svg b/frontend/app/svg/icons/check-circle.svg new file mode 100644 index 000000000..8fcffc109 --- /dev/null +++ b/frontend/app/svg/icons/check-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/check.svg b/frontend/app/svg/icons/check.svg new file mode 100644 index 000000000..a9bda1202 --- /dev/null +++ b/frontend/app/svg/icons/check.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/chevron-down.svg b/frontend/app/svg/icons/chevron-down.svg new file mode 100644 index 000000000..315b89ca6 --- /dev/null +++ b/frontend/app/svg/icons/chevron-down.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/chevron-up.svg b/frontend/app/svg/icons/chevron-up.svg new file mode 100644 index 000000000..455b081c0 --- /dev/null +++ b/frontend/app/svg/icons/chevron-up.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/circle.svg b/frontend/app/svg/icons/circle.svg new file mode 100644 index 000000000..c2db0b25c --- /dev/null +++ b/frontend/app/svg/icons/circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/clipboard-list-check.svg b/frontend/app/svg/icons/clipboard-list-check.svg new file mode 100644 index 000000000..b0b8b510f --- /dev/null +++ b/frontend/app/svg/icons/clipboard-list-check.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/clock.svg b/frontend/app/svg/icons/clock.svg new file mode 100644 index 000000000..e5ecc83ef --- /dev/null +++ b/frontend/app/svg/icons/clock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/close.svg b/frontend/app/svg/icons/close.svg new file mode 100644 index 000000000..e1a7e4bc2 --- /dev/null +++ b/frontend/app/svg/icons/close.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/cloud-fog2-fill.svg b/frontend/app/svg/icons/cloud-fog2-fill.svg new file mode 100644 index 000000000..384a70c66 --- /dev/null +++ b/frontend/app/svg/icons/cloud-fog2-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/code.svg b/frontend/app/svg/icons/code.svg new file mode 100644 index 000000000..f1f7a26f3 --- /dev/null +++ b/frontend/app/svg/icons/code.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/cog.svg b/frontend/app/svg/icons/cog.svg new file mode 100644 index 000000000..145821cf8 --- /dev/null +++ b/frontend/app/svg/icons/cog.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/cogs.svg b/frontend/app/svg/icons/cogs.svg new file mode 100644 index 000000000..f85bdeae6 --- /dev/null +++ b/frontend/app/svg/icons/cogs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/collection.svg b/frontend/app/svg/icons/collection.svg new file mode 100644 index 000000000..255077f81 --- /dev/null +++ b/frontend/app/svg/icons/collection.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/console.svg b/frontend/app/svg/icons/console.svg new file mode 100644 index 000000000..ab4563d28 --- /dev/null +++ b/frontend/app/svg/icons/console.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/console/error.svg b/frontend/app/svg/icons/console/error.svg new file mode 100644 index 000000000..a170d1363 --- /dev/null +++ b/frontend/app/svg/icons/console/error.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/console/exception.svg b/frontend/app/svg/icons/console/exception.svg new file mode 100644 index 000000000..ad6aaf10b --- /dev/null +++ b/frontend/app/svg/icons/console/exception.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/console/info.svg b/frontend/app/svg/icons/console/info.svg new file mode 100644 index 000000000..148ce7691 --- /dev/null +++ b/frontend/app/svg/icons/console/info.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/console/warning.svg b/frontend/app/svg/icons/console/warning.svg new file mode 100644 index 000000000..6890621f7 --- /dev/null +++ b/frontend/app/svg/icons/console/warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/cookies.svg b/frontend/app/svg/icons/cookies.svg new file mode 100644 index 000000000..93c58511f --- /dev/null +++ b/frontend/app/svg/icons/cookies.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/app/svg/icons/copy.svg b/frontend/app/svg/icons/copy.svg new file mode 100644 index 000000000..06090e3f0 --- /dev/null +++ b/frontend/app/svg/icons/copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/credit-card-front.svg b/frontend/app/svg/icons/credit-card-front.svg new file mode 100644 index 000000000..057a4a33a --- /dev/null +++ b/frontend/app/svg/icons/credit-card-front.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/cubes.svg b/frontend/app/svg/icons/cubes.svg new file mode 100644 index 000000000..0b5beac00 --- /dev/null +++ b/frontend/app/svg/icons/cubes.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/desktop.svg b/frontend/app/svg/icons/desktop.svg new file mode 100644 index 000000000..60c66668d --- /dev/null +++ b/frontend/app/svg/icons/desktop.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/device.svg b/frontend/app/svg/icons/device.svg new file mode 100644 index 000000000..b453af4aa --- /dev/null +++ b/frontend/app/svg/icons/device.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + \ No newline at end of file diff --git a/frontend/app/svg/icons/dizzy.svg b/frontend/app/svg/icons/dizzy.svg new file mode 100644 index 000000000..4f026cd64 --- /dev/null +++ b/frontend/app/svg/icons/dizzy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/doublecheck.svg b/frontend/app/svg/icons/doublecheck.svg new file mode 100644 index 000000000..d42562169 --- /dev/null +++ b/frontend/app/svg/icons/doublecheck.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/download.svg b/frontend/app/svg/icons/download.svg new file mode 100644 index 000000000..07f59f865 --- /dev/null +++ b/frontend/app/svg/icons/download.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/drag.svg b/frontend/app/svg/icons/drag.svg new file mode 100644 index 000000000..a68f11e24 --- /dev/null +++ b/frontend/app/svg/icons/drag.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/edit.svg b/frontend/app/svg/icons/edit.svg new file mode 100644 index 000000000..5b1878c18 --- /dev/null +++ b/frontend/app/svg/icons/edit.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/ellipsis-v.svg b/frontend/app/svg/icons/ellipsis-v.svg new file mode 100644 index 000000000..1211fb869 --- /dev/null +++ b/frontend/app/svg/icons/ellipsis-v.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/enter.svg b/frontend/app/svg/icons/enter.svg new file mode 100644 index 000000000..bacaadb86 --- /dev/null +++ b/frontend/app/svg/icons/enter.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/frontend/app/svg/icons/envelope.svg b/frontend/app/svg/icons/envelope.svg new file mode 100644 index 000000000..144eca82e --- /dev/null +++ b/frontend/app/svg/icons/envelope.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/click.svg b/frontend/app/svg/icons/event/click.svg new file mode 100644 index 000000000..7a74f82d0 --- /dev/null +++ b/frontend/app/svg/icons/event/click.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/clickrage.svg b/frontend/app/svg/icons/event/clickrage.svg new file mode 100644 index 000000000..3220e339e --- /dev/null +++ b/frontend/app/svg/icons/event/clickrage.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/code.svg b/frontend/app/svg/icons/event/code.svg new file mode 100644 index 000000000..c9c41b0d7 --- /dev/null +++ b/frontend/app/svg/icons/event/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/i-cursor.svg b/frontend/app/svg/icons/event/i-cursor.svg new file mode 100644 index 000000000..ce8709fa8 --- /dev/null +++ b/frontend/app/svg/icons/event/i-cursor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/input.svg b/frontend/app/svg/icons/event/input.svg new file mode 100644 index 000000000..256542f8a --- /dev/null +++ b/frontend/app/svg/icons/event/input.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/link.svg b/frontend/app/svg/icons/event/link.svg new file mode 100644 index 000000000..ee908ebd0 --- /dev/null +++ b/frontend/app/svg/icons/event/link.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/location.svg b/frontend/app/svg/icons/event/location.svg new file mode 100644 index 000000000..499378c6b --- /dev/null +++ b/frontend/app/svg/icons/event/location.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/resize.svg b/frontend/app/svg/icons/event/resize.svg new file mode 100644 index 000000000..ca5a645f8 --- /dev/null +++ b/frontend/app/svg/icons/event/resize.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/event/view.svg b/frontend/app/svg/icons/event/view.svg new file mode 100644 index 000000000..8feb3ec07 --- /dev/null +++ b/frontend/app/svg/icons/event/view.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/exclamation-circle.svg b/frontend/app/svg/icons/exclamation-circle.svg new file mode 100644 index 000000000..a170d1363 --- /dev/null +++ b/frontend/app/svg/icons/exclamation-circle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/expand-wide.svg b/frontend/app/svg/icons/expand-wide.svg new file mode 100644 index 000000000..6008f1251 --- /dev/null +++ b/frontend/app/svg/icons/expand-wide.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/explosion.svg b/frontend/app/svg/icons/explosion.svg new file mode 100644 index 000000000..1da2d961b --- /dev/null +++ b/frontend/app/svg/icons/explosion.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/external-link-alt.svg b/frontend/app/svg/icons/external-link-alt.svg new file mode 100644 index 000000000..d021da418 --- /dev/null +++ b/frontend/app/svg/icons/external-link-alt.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/eye-slash.svg b/frontend/app/svg/icons/eye-slash.svg new file mode 100644 index 000000000..fbd74a147 --- /dev/null +++ b/frontend/app/svg/icons/eye-slash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/eye.svg b/frontend/app/svg/icons/eye.svg new file mode 100644 index 000000000..c803ae411 --- /dev/null +++ b/frontend/app/svg/icons/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/fetch.svg b/frontend/app/svg/icons/fetch.svg new file mode 100644 index 000000000..40cbbbf86 --- /dev/null +++ b/frontend/app/svg/icons/fetch.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/file-code.svg b/frontend/app/svg/icons/file-code.svg new file mode 100644 index 000000000..4f229e357 --- /dev/null +++ b/frontend/app/svg/icons/file-code.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/file-medical-alt.svg b/frontend/app/svg/icons/file-medical-alt.svg new file mode 100644 index 000000000..7c36a109a --- /dev/null +++ b/frontend/app/svg/icons/file-medical-alt.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/file.svg b/frontend/app/svg/icons/file.svg new file mode 100644 index 000000000..c2b4e7c1a --- /dev/null +++ b/frontend/app/svg/icons/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/filter.svg b/frontend/app/svg/icons/filter.svg new file mode 100644 index 000000000..7cfb69d18 --- /dev/null +++ b/frontend/app/svg/icons/filter.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/filters/border-outer.svg b/frontend/app/svg/icons/filters/border-outer.svg new file mode 100644 index 000000000..498e67bb3 --- /dev/null +++ b/frontend/app/svg/icons/filters/border-outer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/filters/click.svg b/frontend/app/svg/icons/filters/click.svg new file mode 100644 index 000000000..7a74f82d0 --- /dev/null +++ b/frontend/app/svg/icons/filters/click.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/filters/console.svg b/frontend/app/svg/icons/filters/console.svg new file mode 100644 index 000000000..f18fe77e1 --- /dev/null +++ b/frontend/app/svg/icons/filters/console.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/filters/file-code.svg b/frontend/app/svg/icons/filters/file-code.svg new file mode 100644 index 000000000..b72a83996 --- /dev/null +++ b/frontend/app/svg/icons/filters/file-code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/filters/metadata.svg b/frontend/app/svg/icons/filters/metadata.svg new file mode 100755 index 000000000..7fabc88a6 --- /dev/null +++ b/frontend/app/svg/icons/filters/metadata.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/filters/phone-laptop.svg b/frontend/app/svg/icons/filters/phone-laptop.svg new file mode 100644 index 000000000..e25db92c9 --- /dev/null +++ b/frontend/app/svg/icons/filters/phone-laptop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/filters/user-alt.svg b/frontend/app/svg/icons/filters/user-alt.svg new file mode 100644 index 000000000..413b396f6 --- /dev/null +++ b/frontend/app/svg/icons/filters/user-alt.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/filters/userid.svg b/frontend/app/svg/icons/filters/userid.svg new file mode 100644 index 000000000..39113e1b7 --- /dev/null +++ b/frontend/app/svg/icons/filters/userid.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/fullscreen.svg b/frontend/app/svg/icons/fullscreen.svg new file mode 100644 index 000000000..0c393261b --- /dev/null +++ b/frontend/app/svg/icons/fullscreen.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/cpu-fill.svg b/frontend/app/svg/icons/funnel/cpu-fill.svg new file mode 100644 index 000000000..4b3bf2640 --- /dev/null +++ b/frontend/app/svg/icons/funnel/cpu-fill.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/emoji-angry-fill.svg b/frontend/app/svg/icons/funnel/emoji-angry-fill.svg new file mode 100644 index 000000000..a4508d5ff --- /dev/null +++ b/frontend/app/svg/icons/funnel/emoji-angry-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/emoji-dizzy-fill.svg b/frontend/app/svg/icons/funnel/emoji-dizzy-fill.svg new file mode 100644 index 000000000..183ddb0a8 --- /dev/null +++ b/frontend/app/svg/icons/funnel/emoji-dizzy-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/exclamation-circle-fill.svg b/frontend/app/svg/icons/funnel/exclamation-circle-fill.svg new file mode 100644 index 000000000..e385f1158 --- /dev/null +++ b/frontend/app/svg/icons/funnel/exclamation-circle-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/exclamation-circle.svg b/frontend/app/svg/icons/funnel/exclamation-circle.svg new file mode 100644 index 000000000..3b32c2a0c --- /dev/null +++ b/frontend/app/svg/icons/funnel/exclamation-circle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/file-earmark-break-fill.svg b/frontend/app/svg/icons/funnel/file-earmark-break-fill.svg new file mode 100644 index 000000000..041c8c1d5 --- /dev/null +++ b/frontend/app/svg/icons/funnel/file-earmark-break-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/file-earmark-minus-fill.svg b/frontend/app/svg/icons/funnel/file-earmark-minus-fill.svg new file mode 100644 index 000000000..2b539c881 --- /dev/null +++ b/frontend/app/svg/icons/funnel/file-earmark-minus-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/file-earmark-minus.svg b/frontend/app/svg/icons/funnel/file-earmark-minus.svg new file mode 100644 index 000000000..acc9af5b6 --- /dev/null +++ b/frontend/app/svg/icons/funnel/file-earmark-minus.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/file-medical-alt.svg b/frontend/app/svg/icons/funnel/file-medical-alt.svg new file mode 100644 index 000000000..7c36a109a --- /dev/null +++ b/frontend/app/svg/icons/funnel/file-medical-alt.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/file-x.svg b/frontend/app/svg/icons/funnel/file-x.svg new file mode 100644 index 000000000..e177d7703 --- /dev/null +++ b/frontend/app/svg/icons/funnel/file-x.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/hdd-fill.svg b/frontend/app/svg/icons/funnel/hdd-fill.svg new file mode 100644 index 000000000..ee39df301 --- /dev/null +++ b/frontend/app/svg/icons/funnel/hdd-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/hourglass-top.svg b/frontend/app/svg/icons/funnel/hourglass-top.svg new file mode 100644 index 000000000..7a2b9a339 --- /dev/null +++ b/frontend/app/svg/icons/funnel/hourglass-top.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/image-fill.svg b/frontend/app/svg/icons/funnel/image-fill.svg new file mode 100644 index 000000000..6fb267b0f --- /dev/null +++ b/frontend/app/svg/icons/funnel/image-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/microchip.svg b/frontend/app/svg/icons/funnel/microchip.svg new file mode 100644 index 000000000..66c617f53 --- /dev/null +++ b/frontend/app/svg/icons/funnel/microchip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/mouse.svg b/frontend/app/svg/icons/funnel/mouse.svg new file mode 100644 index 000000000..0b44559e6 --- /dev/null +++ b/frontend/app/svg/icons/funnel/mouse.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/patch-exclamation-fill.svg b/frontend/app/svg/icons/funnel/patch-exclamation-fill.svg new file mode 100644 index 000000000..31002381f --- /dev/null +++ b/frontend/app/svg/icons/funnel/patch-exclamation-fill.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/funnel/sd-card.svg b/frontend/app/svg/icons/funnel/sd-card.svg new file mode 100644 index 000000000..8d4991cb1 --- /dev/null +++ b/frontend/app/svg/icons/funnel/sd-card.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/geo-alt-fill-custom.svg b/frontend/app/svg/icons/geo-alt-fill-custom.svg new file mode 100644 index 000000000..3fbffc67e --- /dev/null +++ b/frontend/app/svg/icons/geo-alt-fill-custom.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/github.svg b/frontend/app/svg/icons/github.svg new file mode 100644 index 000000000..61aec6540 --- /dev/null +++ b/frontend/app/svg/icons/github.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/grip-horizontal.svg b/frontend/app/svg/icons/grip-horizontal.svg new file mode 100644 index 000000000..e0c8c1dd0 --- /dev/null +++ b/frontend/app/svg/icons/grip-horizontal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/hdd-stack.svg b/frontend/app/svg/icons/hdd-stack.svg new file mode 100644 index 000000000..cc704badd --- /dev/null +++ b/frontend/app/svg/icons/hdd-stack.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/heart-rate.svg b/frontend/app/svg/icons/heart-rate.svg new file mode 100644 index 000000000..8af51c4a1 --- /dev/null +++ b/frontend/app/svg/icons/heart-rate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/high-engagement.svg b/frontend/app/svg/icons/high-engagement.svg new file mode 100644 index 000000000..2d022fffd --- /dev/null +++ b/frontend/app/svg/icons/high-engagement.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/history.svg b/frontend/app/svg/icons/history.svg new file mode 100644 index 000000000..a9d1f4cab --- /dev/null +++ b/frontend/app/svg/icons/history.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/hourglass-start.svg b/frontend/app/svg/icons/hourglass-start.svg new file mode 100644 index 000000000..4e0f60d0d --- /dev/null +++ b/frontend/app/svg/icons/hourglass-start.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/id-card.svg b/frontend/app/svg/icons/id-card.svg new file mode 100644 index 000000000..b84157df6 --- /dev/null +++ b/frontend/app/svg/icons/id-card.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/image.svg b/frontend/app/svg/icons/image.svg new file mode 100644 index 000000000..d98439e04 --- /dev/null +++ b/frontend/app/svg/icons/image.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/info-circle.svg b/frontend/app/svg/icons/info-circle.svg new file mode 100644 index 000000000..dfb82474d --- /dev/null +++ b/frontend/app/svg/icons/info-circle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/info-square.svg b/frontend/app/svg/icons/info-square.svg new file mode 100644 index 000000000..148ce7691 --- /dev/null +++ b/frontend/app/svg/icons/info-square.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/info.svg b/frontend/app/svg/icons/info.svg new file mode 100644 index 000000000..148ce7691 --- /dev/null +++ b/frontend/app/svg/icons/info.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/inspect.svg b/frontend/app/svg/icons/inspect.svg new file mode 100644 index 000000000..7eed4c871 --- /dev/null +++ b/frontend/app/svg/icons/inspect.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/bugsnag-text.svg b/frontend/app/svg/icons/integrations/bugsnag-text.svg new file mode 100644 index 000000000..0d6bf7b29 --- /dev/null +++ b/frontend/app/svg/icons/integrations/bugsnag-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/bugsnag.svg b/frontend/app/svg/icons/integrations/bugsnag.svg new file mode 100644 index 000000000..26a3a13b8 --- /dev/null +++ b/frontend/app/svg/icons/integrations/bugsnag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/cloudwatch-text.svg b/frontend/app/svg/icons/integrations/cloudwatch-text.svg new file mode 100644 index 000000000..2a70f73ea --- /dev/null +++ b/frontend/app/svg/icons/integrations/cloudwatch-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/cloudwatch.svg b/frontend/app/svg/icons/integrations/cloudwatch.svg new file mode 100644 index 000000000..3c6be67f9 --- /dev/null +++ b/frontend/app/svg/icons/integrations/cloudwatch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/datadog.svg b/frontend/app/svg/icons/integrations/datadog.svg new file mode 100644 index 000000000..129dd8309 --- /dev/null +++ b/frontend/app/svg/icons/integrations/datadog.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/frontend/app/svg/icons/integrations/elasticsearch-text.svg b/frontend/app/svg/icons/integrations/elasticsearch-text.svg new file mode 100644 index 000000000..cfa230309 --- /dev/null +++ b/frontend/app/svg/icons/integrations/elasticsearch-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/elasticsearch.svg b/frontend/app/svg/icons/integrations/elasticsearch.svg new file mode 100644 index 000000000..b95507cd5 --- /dev/null +++ b/frontend/app/svg/icons/integrations/elasticsearch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/github.svg b/frontend/app/svg/icons/integrations/github.svg new file mode 100644 index 000000000..53bd7b2d2 --- /dev/null +++ b/frontend/app/svg/icons/integrations/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/graphql.svg b/frontend/app/svg/icons/integrations/graphql.svg new file mode 100644 index 000000000..714f38846 --- /dev/null +++ b/frontend/app/svg/icons/integrations/graphql.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/jira-text.svg b/frontend/app/svg/icons/integrations/jira-text.svg new file mode 100644 index 000000000..defb226cf --- /dev/null +++ b/frontend/app/svg/icons/integrations/jira-text.svg @@ -0,0 +1 @@ +jira-logo-gradient-blue \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/jira.svg b/frontend/app/svg/icons/integrations/jira.svg new file mode 100644 index 000000000..5243225f3 --- /dev/null +++ b/frontend/app/svg/icons/integrations/jira.svg @@ -0,0 +1,23 @@ + + + + Jira Software-blue + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/newrelic-text.svg b/frontend/app/svg/icons/integrations/newrelic-text.svg new file mode 100644 index 000000000..e55e6c81f --- /dev/null +++ b/frontend/app/svg/icons/integrations/newrelic-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/newrelic.svg b/frontend/app/svg/icons/integrations/newrelic.svg new file mode 100644 index 000000000..cc4aea514 --- /dev/null +++ b/frontend/app/svg/icons/integrations/newrelic.svg @@ -0,0 +1 @@ +NewRelic-logo-square \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/ngrx.svg b/frontend/app/svg/icons/integrations/ngrx.svg new file mode 100644 index 000000000..0e9ea2c19 --- /dev/null +++ b/frontend/app/svg/icons/integrations/ngrx.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/openreplay-text.svg b/frontend/app/svg/icons/integrations/openreplay-text.svg new file mode 100644 index 000000000..d5bef5cba --- /dev/null +++ b/frontend/app/svg/icons/integrations/openreplay-text.svg @@ -0,0 +1,13 @@ + + + Open Replay + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/openreplay.svg b/frontend/app/svg/icons/integrations/openreplay.svg new file mode 100644 index 000000000..77fb302b9 --- /dev/null +++ b/frontend/app/svg/icons/integrations/openreplay.svg @@ -0,0 +1,12 @@ + + + Group + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/redux.svg b/frontend/app/svg/icons/integrations/redux.svg new file mode 100644 index 000000000..e02bb3a2d --- /dev/null +++ b/frontend/app/svg/icons/integrations/redux.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/rollbar-text.svg b/frontend/app/svg/icons/integrations/rollbar-text.svg new file mode 100644 index 000000000..d476b8cca --- /dev/null +++ b/frontend/app/svg/icons/integrations/rollbar-text.svg @@ -0,0 +1 @@ +rollbar-logo-color-horiz \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/rollbar.svg b/frontend/app/svg/icons/integrations/rollbar.svg new file mode 100644 index 000000000..2f6538118 --- /dev/null +++ b/frontend/app/svg/icons/integrations/rollbar.svg @@ -0,0 +1,20 @@ + + + + +rollbar-logo-color-vertical + + + + + + + diff --git a/frontend/app/svg/icons/integrations/segment.svg b/frontend/app/svg/icons/integrations/segment.svg new file mode 100644 index 000000000..e631af69b --- /dev/null +++ b/frontend/app/svg/icons/integrations/segment.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/app/svg/icons/integrations/sentry-text.svg b/frontend/app/svg/icons/integrations/sentry-text.svg new file mode 100644 index 000000000..59b79bc58 --- /dev/null +++ b/frontend/app/svg/icons/integrations/sentry-text.svg @@ -0,0 +1 @@ +sentry-logo-black \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/sentry.svg b/frontend/app/svg/icons/integrations/sentry.svg new file mode 100644 index 000000000..ea1955275 --- /dev/null +++ b/frontend/app/svg/icons/integrations/sentry.svg @@ -0,0 +1,6 @@ + + Untitled + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/slack.svg b/frontend/app/svg/icons/integrations/slack.svg new file mode 100644 index 000000000..f65d81b52 --- /dev/null +++ b/frontend/app/svg/icons/integrations/slack.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/app/svg/icons/integrations/stackdriver.svg b/frontend/app/svg/icons/integrations/stackdriver.svg new file mode 100644 index 000000000..2c216468f --- /dev/null +++ b/frontend/app/svg/icons/integrations/stackdriver.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/integrations/sumologic-text.svg b/frontend/app/svg/icons/integrations/sumologic-text.svg new file mode 100644 index 000000000..1acee6027 --- /dev/null +++ b/frontend/app/svg/icons/integrations/sumologic-text.svg @@ -0,0 +1,32 @@ + + + + +Asset 1 + + + + + + diff --git a/frontend/app/svg/icons/integrations/sumologic.svg b/frontend/app/svg/icons/integrations/sumologic.svg new file mode 100644 index 000000000..53d0d8e67 --- /dev/null +++ b/frontend/app/svg/icons/integrations/sumologic.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/frontend/app/svg/icons/integrations/vuejs.svg b/frontend/app/svg/icons/integrations/vuejs.svg new file mode 100644 index 000000000..420bd1140 --- /dev/null +++ b/frontend/app/svg/icons/integrations/vuejs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/journal-code.svg b/frontend/app/svg/icons/journal-code.svg new file mode 100644 index 000000000..2f26a5687 --- /dev/null +++ b/frontend/app/svg/icons/journal-code.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/layer-group.svg b/frontend/app/svg/icons/layer-group.svg new file mode 100644 index 000000000..f66f8769f --- /dev/null +++ b/frontend/app/svg/icons/layer-group.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/lightbulb-on.svg b/frontend/app/svg/icons/lightbulb-on.svg new file mode 100644 index 000000000..7a8288cfe --- /dev/null +++ b/frontend/app/svg/icons/lightbulb-on.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/lightbulb.svg b/frontend/app/svg/icons/lightbulb.svg new file mode 100644 index 000000000..94a8a6d57 --- /dev/null +++ b/frontend/app/svg/icons/lightbulb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/list-alt.svg b/frontend/app/svg/icons/list-alt.svg new file mode 100644 index 000000000..1ff78196c --- /dev/null +++ b/frontend/app/svg/icons/list-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/lock-alt.svg b/frontend/app/svg/icons/lock-alt.svg new file mode 100644 index 000000000..269e23b6a --- /dev/null +++ b/frontend/app/svg/icons/lock-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/map-marker-alt.svg b/frontend/app/svg/icons/map-marker-alt.svg new file mode 100644 index 000000000..f72a9967b --- /dev/null +++ b/frontend/app/svg/icons/map-marker-alt.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/memory.svg b/frontend/app/svg/icons/memory.svg new file mode 100644 index 000000000..5d707d203 --- /dev/null +++ b/frontend/app/svg/icons/memory.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/minus.svg b/frontend/app/svg/icons/minus.svg new file mode 100644 index 000000000..240c26c2e --- /dev/null +++ b/frontend/app/svg/icons/minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/mobile.svg b/frontend/app/svg/icons/mobile.svg new file mode 100644 index 000000000..0e990e9c9 --- /dev/null +++ b/frontend/app/svg/icons/mobile.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/mouse-alt.svg b/frontend/app/svg/icons/mouse-alt.svg new file mode 100644 index 000000000..ff1c689aa --- /dev/null +++ b/frontend/app/svg/icons/mouse-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/next1.svg b/frontend/app/svg/icons/next1.svg new file mode 100644 index 000000000..eb2212fab --- /dev/null +++ b/frontend/app/svg/icons/next1.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/os.svg b/frontend/app/svg/icons/os.svg new file mode 100644 index 000000000..7a2781f28 --- /dev/null +++ b/frontend/app/svg/icons/os.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/os/android.svg b/frontend/app/svg/icons/os/android.svg new file mode 100644 index 000000000..96d80056c --- /dev/null +++ b/frontend/app/svg/icons/os/android.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/os/chrome_os.svg b/frontend/app/svg/icons/os/chrome_os.svg new file mode 100644 index 000000000..0419c20e4 --- /dev/null +++ b/frontend/app/svg/icons/os/chrome_os.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/os/ios.svg b/frontend/app/svg/icons/os/ios.svg new file mode 100644 index 000000000..df4d65705 --- /dev/null +++ b/frontend/app/svg/icons/os/ios.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app/svg/icons/os/linux.svg b/frontend/app/svg/icons/os/linux.svg new file mode 100644 index 000000000..a2c9891e9 --- /dev/null +++ b/frontend/app/svg/icons/os/linux.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/os/mac_os_x.svg b/frontend/app/svg/icons/os/mac_os_x.svg new file mode 100644 index 000000000..7f9c6410e --- /dev/null +++ b/frontend/app/svg/icons/os/mac_os_x.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/os/other.svg b/frontend/app/svg/icons/os/other.svg new file mode 100644 index 000000000..c545057e7 --- /dev/null +++ b/frontend/app/svg/icons/os/other.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/os/ubuntu.svg b/frontend/app/svg/icons/os/ubuntu.svg new file mode 100644 index 000000000..e77efde1c --- /dev/null +++ b/frontend/app/svg/icons/os/ubuntu.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/os/windows.svg b/frontend/app/svg/icons/os/windows.svg new file mode 100644 index 000000000..c545057e7 --- /dev/null +++ b/frontend/app/svg/icons/os/windows.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/pause.svg b/frontend/app/svg/icons/pause.svg new file mode 100644 index 000000000..8c56c464e --- /dev/null +++ b/frontend/app/svg/icons/pause.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/pencil.svg b/frontend/app/svg/icons/pencil.svg new file mode 100644 index 000000000..5b1878c18 --- /dev/null +++ b/frontend/app/svg/icons/pencil.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/play-circle-light.svg b/frontend/app/svg/icons/play-circle-light.svg new file mode 100755 index 000000000..8787bdfb1 --- /dev/null +++ b/frontend/app/svg/icons/play-circle-light.svg @@ -0,0 +1 @@ +icn_play_illustrator \ No newline at end of file diff --git a/frontend/app/svg/icons/play-circle.svg b/frontend/app/svg/icons/play-circle.svg new file mode 100644 index 000000000..6985643a2 --- /dev/null +++ b/frontend/app/svg/icons/play-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/play-fill.svg b/frontend/app/svg/icons/play-fill.svg new file mode 100644 index 000000000..a58e9ed39 --- /dev/null +++ b/frontend/app/svg/icons/play-fill.svg @@ -0,0 +1 @@ +play-fill \ No newline at end of file diff --git a/frontend/app/svg/icons/play.svg b/frontend/app/svg/icons/play.svg new file mode 100644 index 000000000..36780840d --- /dev/null +++ b/frontend/app/svg/icons/play.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/plus-circle.svg b/frontend/app/svg/icons/plus-circle.svg new file mode 100644 index 000000000..7da7e5fbc --- /dev/null +++ b/frontend/app/svg/icons/plus-circle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/plus.svg b/frontend/app/svg/icons/plus.svg new file mode 100644 index 000000000..7270c46a8 --- /dev/null +++ b/frontend/app/svg/icons/plus.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/prev1.svg b/frontend/app/svg/icons/prev1.svg new file mode 100644 index 000000000..bb25d0466 --- /dev/null +++ b/frontend/app/svg/icons/prev1.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/puzzle-piece.svg b/frontend/app/svg/icons/puzzle-piece.svg new file mode 100644 index 000000000..7a74f82d0 --- /dev/null +++ b/frontend/app/svg/icons/puzzle-piece.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/question-circle.svg b/frontend/app/svg/icons/question-circle.svg new file mode 100644 index 000000000..88df404f9 --- /dev/null +++ b/frontend/app/svg/icons/question-circle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/quote-left.svg b/frontend/app/svg/icons/quote-left.svg new file mode 100644 index 000000000..d73aa5e4e --- /dev/null +++ b/frontend/app/svg/icons/quote-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/quote-right.svg b/frontend/app/svg/icons/quote-right.svg new file mode 100644 index 000000000..18537bfe4 --- /dev/null +++ b/frontend/app/svg/icons/quote-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/redo-back.svg b/frontend/app/svg/icons/redo-back.svg new file mode 100644 index 000000000..d97bf579f --- /dev/null +++ b/frontend/app/svg/icons/redo-back.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/redo.svg b/frontend/app/svg/icons/redo.svg new file mode 100644 index 000000000..f52f928d3 --- /dev/null +++ b/frontend/app/svg/icons/redo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/replay-10.svg b/frontend/app/svg/icons/replay-10.svg new file mode 100644 index 000000000..d315359ee --- /dev/null +++ b/frontend/app/svg/icons/replay-10.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/sandglass.svg b/frontend/app/svg/icons/sandglass.svg new file mode 100644 index 000000000..8083465c5 --- /dev/null +++ b/frontend/app/svg/icons/sandglass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/search.svg b/frontend/app/svg/icons/search.svg new file mode 100644 index 000000000..e627cdb6c --- /dev/null +++ b/frontend/app/svg/icons/search.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/search_notification.svg b/frontend/app/svg/icons/search_notification.svg new file mode 100644 index 000000000..c4e1629f8 --- /dev/null +++ b/frontend/app/svg/icons/search_notification.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app/svg/icons/server.svg b/frontend/app/svg/icons/server.svg new file mode 100644 index 000000000..72b852cb2 --- /dev/null +++ b/frontend/app/svg/icons/server.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/share-alt.svg b/frontend/app/svg/icons/share-alt.svg new file mode 100644 index 000000000..50b4ad682 --- /dev/null +++ b/frontend/app/svg/icons/share-alt.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/signup.svg b/frontend/app/svg/icons/signup.svg new file mode 100644 index 000000000..91cead932 --- /dev/null +++ b/frontend/app/svg/icons/signup.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/slash-circle.svg b/frontend/app/svg/icons/slash-circle.svg new file mode 100644 index 000000000..cb8c2886b --- /dev/null +++ b/frontend/app/svg/icons/slash-circle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/social/slack.svg b/frontend/app/svg/icons/social/slack.svg new file mode 100644 index 000000000..15a7b9dbc --- /dev/null +++ b/frontend/app/svg/icons/social/slack.svg @@ -0,0 +1 @@ +Slack icon \ No newline at end of file diff --git a/frontend/app/svg/icons/social/trello.svg b/frontend/app/svg/icons/social/trello.svg new file mode 100644 index 000000000..fdc335344 --- /dev/null +++ b/frontend/app/svg/icons/social/trello.svg @@ -0,0 +1 @@ +Trello icon \ No newline at end of file diff --git a/frontend/app/svg/icons/spinner.svg b/frontend/app/svg/icons/spinner.svg new file mode 100644 index 000000000..42e8ecf39 --- /dev/null +++ b/frontend/app/svg/icons/spinner.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/star-solid.svg b/frontend/app/svg/icons/star-solid.svg new file mode 100644 index 000000000..7cfd13b8a --- /dev/null +++ b/frontend/app/svg/icons/star-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/star.svg b/frontend/app/svg/icons/star.svg new file mode 100644 index 000000000..51330566a --- /dev/null +++ b/frontend/app/svg/icons/star.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/step-forward.svg b/frontend/app/svg/icons/step-forward.svg new file mode 100644 index 000000000..4d396da6b --- /dev/null +++ b/frontend/app/svg/icons/step-forward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/stopwatch.svg b/frontend/app/svg/icons/stopwatch.svg new file mode 100644 index 000000000..734ab45f5 --- /dev/null +++ b/frontend/app/svg/icons/stopwatch.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/store.svg b/frontend/app/svg/icons/store.svg new file mode 100644 index 000000000..b4a93969f --- /dev/null +++ b/frontend/app/svg/icons/store.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/sync-alt.svg b/frontend/app/svg/icons/sync-alt.svg new file mode 100644 index 000000000..808ed4c06 --- /dev/null +++ b/frontend/app/svg/icons/sync-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/tablet-android.svg b/frontend/app/svg/icons/tablet-android.svg new file mode 100644 index 000000000..6ce3946d9 --- /dev/null +++ b/frontend/app/svg/icons/tablet-android.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/tachometer-slow.svg b/frontend/app/svg/icons/tachometer-slow.svg new file mode 100644 index 000000000..61406f836 --- /dev/null +++ b/frontend/app/svg/icons/tachometer-slow.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/tachometer-slowest.svg b/frontend/app/svg/icons/tachometer-slowest.svg new file mode 100644 index 000000000..f7a9fc43b --- /dev/null +++ b/frontend/app/svg/icons/tachometer-slowest.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/tags.svg b/frontend/app/svg/icons/tags.svg new file mode 100644 index 000000000..6f86a7982 --- /dev/null +++ b/frontend/app/svg/icons/tags.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/team-funnel.svg b/frontend/app/svg/icons/team-funnel.svg new file mode 100644 index 000000000..b8d8a4d13 --- /dev/null +++ b/frontend/app/svg/icons/team-funnel.svg @@ -0,0 +1,15 @@ + + + Group + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/tools.svg b/frontend/app/svg/icons/tools.svg new file mode 100644 index 000000000..7130225ab --- /dev/null +++ b/frontend/app/svg/icons/tools.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/trash.svg b/frontend/app/svg/icons/trash.svg new file mode 100644 index 000000000..17b8333c2 --- /dev/null +++ b/frontend/app/svg/icons/trash.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/turtle.svg b/frontend/app/svg/icons/turtle.svg new file mode 100644 index 000000000..0d21e98dd --- /dev/null +++ b/frontend/app/svg/icons/turtle.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/user-alt.svg b/frontend/app/svg/icons/user-alt.svg new file mode 100644 index 000000000..21007ebd0 --- /dev/null +++ b/frontend/app/svg/icons/user-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/user-circle.svg b/frontend/app/svg/icons/user-circle.svg new file mode 100644 index 000000000..c5f2288db --- /dev/null +++ b/frontend/app/svg/icons/user-circle.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/user-friends.svg b/frontend/app/svg/icons/user-friends.svg new file mode 100644 index 000000000..2e43c5983 --- /dev/null +++ b/frontend/app/svg/icons/user-friends.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/users.svg b/frontend/app/svg/icons/users.svg new file mode 100644 index 000000000..a72221054 --- /dev/null +++ b/frontend/app/svg/icons/users.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/vendors/graphql.svg b/frontend/app/svg/icons/vendors/graphql.svg new file mode 100644 index 000000000..86eafbec1 --- /dev/null +++ b/frontend/app/svg/icons/vendors/graphql.svg @@ -0,0 +1 @@ +graphql \ No newline at end of file diff --git a/frontend/app/svg/icons/vendors/mobx.svg b/frontend/app/svg/icons/vendors/mobx.svg new file mode 100644 index 000000000..8cf60e6ff --- /dev/null +++ b/frontend/app/svg/icons/vendors/mobx.svg @@ -0,0 +1 @@ +mobx \ No newline at end of file diff --git a/frontend/app/svg/icons/vendors/ngrx.svg b/frontend/app/svg/icons/vendors/ngrx.svg new file mode 100644 index 000000000..db76aca80 --- /dev/null +++ b/frontend/app/svg/icons/vendors/ngrx.svg @@ -0,0 +1 @@ +NgRx \ No newline at end of file diff --git a/frontend/app/svg/icons/vendors/redux.svg b/frontend/app/svg/icons/vendors/redux.svg new file mode 100644 index 000000000..46650a53a --- /dev/null +++ b/frontend/app/svg/icons/vendors/redux.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/vendors/vuex.svg b/frontend/app/svg/icons/vendors/vuex.svg new file mode 100644 index 000000000..fa22f0a69 --- /dev/null +++ b/frontend/app/svg/icons/vendors/vuex.svg @@ -0,0 +1 @@ +vuex \ No newline at end of file diff --git a/frontend/app/svg/icons/wifi.svg b/frontend/app/svg/icons/wifi.svg new file mode 100644 index 000000000..07f59f865 --- /dev/null +++ b/frontend/app/svg/icons/wifi.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/window-alt.svg b/frontend/app/svg/icons/window-alt.svg new file mode 100644 index 000000000..c645ed7a1 --- /dev/null +++ b/frontend/app/svg/icons/window-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/icons/window-restore.svg b/frontend/app/svg/icons/window-restore.svg new file mode 100644 index 000000000..4d0c93970 --- /dev/null +++ b/frontend/app/svg/icons/window-restore.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/window.svg b/frontend/app/svg/icons/window.svg new file mode 100644 index 000000000..e63dea86d --- /dev/null +++ b/frontend/app/svg/icons/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/logo-small.svg b/frontend/app/svg/logo-small.svg new file mode 100644 index 000000000..667be8f22 --- /dev/null +++ b/frontend/app/svg/logo-small.svg @@ -0,0 +1,12 @@ + + + Group + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/logo-white.svg b/frontend/app/svg/logo-white.svg new file mode 100644 index 000000000..d941bea3e --- /dev/null +++ b/frontend/app/svg/logo-white.svg @@ -0,0 +1,9 @@ + + + Group + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/logo.svg b/frontend/app/svg/logo.svg new file mode 100644 index 000000000..d5bef5cba --- /dev/null +++ b/frontend/app/svg/logo.svg @@ -0,0 +1,13 @@ + + + Open Replay + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/no-results.svg b/frontend/app/svg/no-results.svg new file mode 100644 index 000000000..0e2aa5673 --- /dev/null +++ b/frontend/app/svg/no-results.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/openreplay-preloader.svg b/frontend/app/svg/openreplay-preloader.svg new file mode 100644 index 000000000..6bf6be13f --- /dev/null +++ b/frontend/app/svg/openreplay-preloader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/app/svg/pattern-login.svg b/frontend/app/svg/pattern-login.svg new file mode 100644 index 000000000..549aa9159 --- /dev/null +++ b/frontend/app/svg/pattern-login.svg @@ -0,0 +1,39 @@ + + + pattern-login + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/rehydrate-spinner.svg b/frontend/app/svg/rehydrate-spinner.svg new file mode 100644 index 000000000..a9db0e5c3 --- /dev/null +++ b/frontend/app/svg/rehydrate-spinner.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app/svg/signal-green.svg b/frontend/app/svg/signal-green.svg new file mode 100644 index 000000000..d098280b0 --- /dev/null +++ b/frontend/app/svg/signal-green.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/signal-red.svg b/frontend/app/svg/signal-red.svg new file mode 100644 index 000000000..58adc9f6f --- /dev/null +++ b/frontend/app/svg/signal-red.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/svg/test-graphic.svg b/frontend/app/svg/test-graphic.svg new file mode 100644 index 000000000..7b07c3bd6 --- /dev/null +++ b/frontend/app/svg/test-graphic.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/app/theme/colors.js b/frontend/app/theme/colors.js new file mode 100644 index 000000000..07aca3a8b --- /dev/null +++ b/frontend/app/theme/colors.js @@ -0,0 +1,41 @@ +module.exports = { + main: "#394EFF", + + "gray-light-shade": "#EEEEEE", + "gray-lightest": "#f6f6f6", + "gray-light": "#ddd", + "gray-medium": "#888", + "gray-dark": "#666", + "gray-darkest": "#333", + + teal: "#394EFF", /* blue */ + "teal-dark": "#2331A8", /* "blue-dark" */ + "teal-light": "#D0D4F2", + + tealx: "#3EAAAF", + "tealx-light": "#E2F0EE", + "tealx-light-border": "#C6DCDA", + + orange: "#E28940", + yellow: "#FFFBE5", + yellow2: "#F5A623", + "orange-dark": "#C26822", + green: "#42AE5E", + green2: "#00dc69", + "green-dark": "#2C9848", + red: "#cc0000", + red2: "#F5A623", + blue: "#366CD9", + blue2: "#0076FF", + "active-blue": "#F6F7FF", + "active-blue-border": "#D0D4F2", + pink: "#ffb9b9", + + + white: "#fff", + borderColor: { + default: '#DDDDDD', + 'gray-light-shade': '#EEEEEE', + 'primary': '#3490dc', + } +} \ No newline at end of file diff --git a/frontend/app/types/Record.js b/frontend/app/types/Record.js new file mode 100644 index 000000000..ceb63703c --- /dev/null +++ b/frontend/app/types/Record.js @@ -0,0 +1,63 @@ +const { Record } = require('immutable'); + +Record.prototype.validate = function validate() { return true; }; +Record.prototype.isComplete = function isComplete() { return true; }; +// Record.prototype.toData = function toData() { +// return this.toJS(); +// }; + +export default function createRecordFactory(fields = {}, options = {}) { + const { + idKey = 'key', + keyKey = 'key', + fromJS = v => v, + toData, + validate, + isComplete, + name='record', // = "Record", // gets wrong in production when use as immutable' Record's name + methods = {}, + } = options; + + let uniqueKey = 0xff; + function nextKey() { + uniqueKey += 1; + return `${ name }_${ uniqueKey }`; + } + + const recordFactory = Record({ [ keyKey ]: undefined, ...fields }); + recordFactory.prototype.exists = function exists() { + return !!this[ idKey ]; + }; + + recordFactory.prototype.toData = toData || + function() { + const data = this.toJS(); + delete data[keyKey]; + return data; + }; + if (validate) recordFactory.prototype.validate = validate; + if (isComplete) recordFactory.prototype.isComplete = isComplete; + Object.keys(methods).forEach((methodKey) => { + recordFactory.prototype[ methodKey ] = methods[ methodKey ]; + }); + + function createRecord(values = {}) { + if (Record.isRecord(values)) { + // const descriptiveName = Record.getDescriptiveName(values); + // if (name && descriptiveName !== name) { + // throw new Error(`Wrong record type: ${ name } expected, but got ${ descriptiveName }`); + // } + return values.set(keyKey, nextKey()); + } + return recordFactory({ + [ keyKey ]: nextKey(), + ...fromJS(values), + }); + } + + // TODO: add createRecord to prototype chain + createRecord.extend = (newFields, newOptions = {}) => + createRecordFactory({ ...fields, ...newFields }, { ...options, ...newOptions }); + + return createRecord; +} diff --git a/frontend/app/types/account/account.js b/frontend/app/types/account/account.js new file mode 100644 index 000000000..a0c152bbb --- /dev/null +++ b/frontend/app/types/account/account.js @@ -0,0 +1,17 @@ +import Member from 'Types/member'; +import Appearance from './appearance'; +import Limit from './limit'; + +export default Member.extend({ + changePassword: undefined, + appearance: Appearance(), + limits: Limit(), + banner: undefined, + email: '', + verifiedEmail: undefined +}, { + fromJS: account => ({ + ...account, + appearance: Appearance(account.appearance), + }) +}); \ No newline at end of file diff --git a/frontend/app/types/account/appearance.js b/frontend/app/types/account/appearance.js new file mode 100644 index 000000000..2c401de99 --- /dev/null +++ b/frontend/app/types/account/appearance.js @@ -0,0 +1,86 @@ +import Record from 'Types/Record'; +import { WIDGET_KEYS } from 'Types/dashboard'; + +export const OWNER = 'po'; +export const QANALYST = 'qa'; +export const DEVELOPER = 'dev'; +export const CAGENT = 'agent'; +export const CUSTOM ='CUSTOM'; +export const NOT_SET = 'NOT_SET'; + +export const ROLE_NAMES = { + [ OWNER ]: "Product Owner", + [ QANALYST ]: "Quality Assurance", + [ DEVELOPER ]: "Developer", + [ CAGENT ]: "Customer Success", + [ CUSTOM ]: "Custom Role", +}; + +const dashboardAllTrueValues = WIDGET_KEYS.reduce((values, key) => ({ + ...values, + [ key ]: true, +}), {}); +const dashboardAllFalseValues = WIDGET_KEYS.reduce((values, key) => ({ + ...values, + [ key ]: false, +}), {}); + +const Dashboard = Record(dashboardAllTrueValues); + +const Appearance = Record({ + role: DEVELOPER, + sessionsLive: false, + sessionsDevtools: true, + tests: false, + runs: false, + dashboard: Dashboard().set("userActivity",false), +}, { + fromJS: appearance => ({ + ...appearance, + dashboard: Dashboard(appearance.dashboard), + }), + methods: { + dashboardSome: function() { + return WIDGET_KEYS.some(key => this.dashboard[ key ]); + } + } +}); + +export const PREDEFINED_VALUES = { + [ OWNER ]: Appearance({ + role: OWNER, + sessionsLive: false, + sessionsDevtools: false, + tests: false, + runs: false, + dashboard: Dashboard({ + slowestImages: false, + errorsTrend: false, + }), + }), + [ QANALYST ]: Appearance({ + role: QANALYST, + sessionsLive: false, + dashboard: Dashboard(dashboardAllFalseValues), + }), + [ DEVELOPER ]: Appearance({ + role: DEVELOPER, + sessionsLive: false, + dashboard: Dashboard() + .set('userActivity', false) + .set('sessionsFrustration', false) + .set('sessionsFeedback', false), + }), + [ CAGENT ]: Appearance({ + role: CAGENT, + sessionsDevtools: false, + tests: false, + runs: false, + dashboard: Dashboard(dashboardAllFalseValues), + }), + [ CUSTOM ]: Appearance({ + role: CUSTOM, + }), +} + +export default Appearance; \ No newline at end of file diff --git a/frontend/app/types/account/index.js b/frontend/app/types/account/index.js new file mode 100644 index 000000000..98d31384d --- /dev/null +++ b/frontend/app/types/account/index.js @@ -0,0 +1 @@ +export { default } from './account'; \ No newline at end of file diff --git a/frontend/app/types/account/limit.js b/frontend/app/types/account/limit.js new file mode 100644 index 000000000..f5274f7b0 --- /dev/null +++ b/frontend/app/types/account/limit.js @@ -0,0 +1,10 @@ +import Record from 'Types/Record'; +import { Map } from 'immutable'; + +const defaultValues = Map({ limit: 0, remaining: 0 }); +const Limit = Record({ + teamMember: defaultValues, + sites: defaultValues +}); + +export default Limit; \ No newline at end of file diff --git a/frontend/app/types/address.js b/frontend/app/types/address.js new file mode 100644 index 000000000..8d8e2ccf2 --- /dev/null +++ b/frontend/app/types/address.js @@ -0,0 +1,20 @@ +import Record from 'Types/Record'; + +export default Record({ + line1: '', + postal_code: '', + city: '', + state: '', + country: '', +}, { + methods: { + validate() { + return true; + }, + toData() { + const js = this.toJS(); + delete js.key; + return js; + }, + }, +}); diff --git a/frontend/app/types/alert.js b/frontend/app/types/alert.js new file mode 100644 index 000000000..5065b735c --- /dev/null +++ b/frontend/app/types/alert.js @@ -0,0 +1,109 @@ +import Record from 'Types/Record'; +import { notEmptyString, validateName, validateNumber, validateEmail } from 'App/validate'; +import { List, Map } from 'immutable'; +import { alertMetrics as metrics, alertConditions as conditions } from 'App/constants'; +import { ItemDescription } from 'semantic-ui-react'; +// import Filter from './filter'; + +const metricsMap = {} +const conditionsMap = {} +metrics.forEach(m => { metricsMap[m.value] = m }); +conditions.forEach(c => { conditionsMap[c.value] = c }); + +export default Record({ + alertId: '', + projectId: undefined, + name: 'New Alert', + description: '', + active: true, + currentPeriod: 15, + previousPeriod: 15, + detectionMethod: 'threshold', + change: 'change', + query: Map({ left: '', operator: '', right: ''}), + options: Map({ currentPeriod: 15, previousPeriod: 15 }), + createdAt: undefined, + + slack: false, + slackInput: [], + webhook: false, + webhookInput: [], + email: false, + emailInput: [], + hasNotification: false, + metric: '', + condition: '', +}, { + idKey: 'alertId', + methods: { + validate() { + return notEmptyString(this.name) && + this.query.left && this.query.right && validateNumber(this.query.right) && this.query.right > 0 && this.query.operator && + (this.slack ? this.slackInput.length > 0 : true) && + (this.email ? this.emailInput.length > 0 : true) && + (this.webhook ? this.webhookInput.length > 0 : true); + }, + toData() { + const js = this.toJS(); + + const options = { message: [] } + if (js.slack && js.slackInput) + options.message = options.message.concat(js.slackInput.map(i => ({ type: 'slack', value: i }))) + // options.message.push({ type: 'slack', value: js.slackInput }) + if (js.email && js.emailInput) + options.message = options.message.concat(js.emailInput.map(i => ({ type: 'email', value: i }))) + // options.message.push({ type: 'email', value: js.emailInput }) + if (js.webhook && js.webhookInput) + options.message = options.message.concat(js.webhookInput.map(i => ({ type: 'webhook', value: i }))) + // options.message.push({ type: 'webhook', value: js.webhookInput }) + + options.previousPeriod = js.previousPeriod + options.currentPeriod = js.currentPeriod + + js.detection_method = js.detectionMethod; + delete js.slack; + delete js.webhook; + delete js.email; + delete js.slackInput; + delete js.webhookInput; + delete js.emailInput; + delete js.hasNotification; + delete js.metric; + delete js.condition; + delete js.currentPeriod; + delete js.previousPeriod; + + return { ...js, options: options }; + }, + }, + fromJS: (item) => { + const options = item.options || { currentPeriod: 15, previousPeriod: 15, message: [] }; + const query = item.query || { left: '', operator: '', right: ''}; + + const slack = List(options.message).filter(i => i.type === 'slack'); + const email = List(options.message).filter(i => i.type === 'email'); + const webhook = List(options.message).filter(i => i.type === 'webhook'); + + return { + ...item, + metric: metricsMap[query.left], + condition: item.query ? conditionsMap[item.query.operator] : {}, + detectionMethod: item.detectionMethod || item.detection_method, + query: query, + options: options, + previousPeriod: options.previousPeriod, + currentPeriod: options.currentPeriod, + + slack: slack.size > 0, + slackInput: slack.map(i => parseInt(i.value)).toJS(), + + email: email.size > 0, + emailInput: email.map(i => i.value).toJS(), + + webhook: webhook.size > 0, + webhookInput: webhook.map(i => parseInt(i.value)).toJS(), + + hasNotification: !!slack || !!email || !!webhook + } + }, +}); diff --git a/frontend/app/types/announcement.js b/frontend/app/types/announcement.js new file mode 100644 index 000000000..f73eb0dca --- /dev/null +++ b/frontend/app/types/announcement.js @@ -0,0 +1,20 @@ +import Record from 'Types/Record'; +import { DateTime } from 'luxon'; + +export default Record({ + announcementId: undefined, + type: undefined, + title: undefined, + description: undefined, + imageUrl: undefined, + createdAt: undefined, + viewed: undefined, + buttonUrl: undefined, + buttonText: undefined +}, { + idKey: 'announcementId', + fromJS: ({ createdAt, ...rest }) => ({ + ...rest, + createdAt: createdAt ? DateTime.fromMillis(createdAt) : undefined, + }), +}); diff --git a/frontend/app/types/app/period.js b/frontend/app/types/app/period.js new file mode 100644 index 000000000..5e5e9aba8 --- /dev/null +++ b/frontend/app/types/app/period.js @@ -0,0 +1,107 @@ +import origMoment from 'moment'; +import { extendMoment } from 'moment-range'; +import Record from 'Types/Record'; +const moment = extendMoment(origMoment); + +export const LAST_30_MINUTES = 'LAST_30_MINUTES'; +export const TODAY = 'TODAY'; +export const LAST_24_HOURS = 'LAST_24_HOURS'; +export const YESTERDAY = 'YESTERDAY'; +export const LAST_7_DAYS = 'LAST_7_DAYS'; +export const LAST_30_DAYS = 'LAST_30_DAYS'; +export const THIS_MONTH = 'THIS_MONTH'; +export const LAST_MONTH = 'LAST_MONTH'; +export const THIS_YEAR = 'THIS_YEAR'; +export const CUSTOM_RANGE = 'CUSTOM_RANGE'; + +const RANGE_LABELS = { + [ LAST_30_MINUTES ]: 'Last 30 Minutes', + [ TODAY ]: 'Today', + [ YESTERDAY ]: 'Yesterday', + [ LAST_24_HOURS ]: 'Last 24 Hours', + [ LAST_7_DAYS ]: 'Last 7 Days', + [ LAST_30_DAYS ]: 'Last 30 Days', + [ THIS_MONTH ]: 'This Month', + [ LAST_MONTH ]: 'Last Month', + [ THIS_YEAR ]: 'This Year', +} + +function getRange(rangeName) { + switch (rangeName) { + case TODAY: + return moment.range( + moment().startOf('day'), + moment().endOf('day'), + ); + case YESTERDAY: + return moment.range( + moment().subtract(1, 'days').startOf('day'), + moment().subtract(1, 'days').endOf('day'), + ); + case LAST_24_HOURS: + return moment.range( + moment().startOf('hour').subtract(24, 'hours'), + moment().startOf('hour'), + ); + case LAST_30_MINUTES: + return moment.range( + moment().startOf('hour').subtract(30, 'minutes'), + moment().startOf('hour'), + ); + case LAST_7_DAYS: + return moment.range( + moment().subtract(7, 'days').startOf('day'), + moment().endOf('day'), + ); + case LAST_30_DAYS: + return moment.range( + moment().subtract(30, 'days').startOf('day'), + moment().endOf('day'), + ); + case THIS_MONTH: + return moment().range('month'); + case LAST_MONTH: + return moment().subtract(1, 'months').range('month'); + case THIS_YEAR: + return moment().range('year'); + default: + return moment.range(); + } +} + +export default Record({ + start: 0, + end: 0, + rangeName: CUSTOM_RANGE, + range: moment.range(), +}, { + fromJS: period => { + if (!period.rangeName || period.rangeName === CUSTOM_RANGE) { + const range = moment.range( + moment(period.start || 0), + moment(period.end || 0), + ); + return { + ...period, + range, + start: range.start.unix() * 1000, + end: range.end.unix() * 1000, + }; + } + const range = getRange(period.rangeName); + return { + ...period, + range, + start: range.start.unix() * 1000, + end: range.end.unix() * 1000, + } + }, + methods: { + toTimestamps() { + return { + startTimestamp: this.start, + endTimestamp: this.end, + }; + }, + } +}); \ No newline at end of file diff --git a/frontend/app/types/app/platform.js b/frontend/app/types/app/platform.js new file mode 100644 index 000000000..3c7d69d9d --- /dev/null +++ b/frontend/app/types/app/platform.js @@ -0,0 +1,3 @@ +export const ALL = 'all'; +export const DESKTOP = 'desktop'; +export const MOBILE = 'mobile'; \ No newline at end of file diff --git a/frontend/app/types/appTest.js b/frontend/app/types/appTest.js new file mode 100644 index 000000000..248b759b7 --- /dev/null +++ b/frontend/app/types/appTest.js @@ -0,0 +1,87 @@ +import { Record, List, Set } from 'immutable'; +import { validateName } from 'App/validate'; +import { DateTime } from 'luxon'; +import Run from './run'; +import Step from './step'; + +class Test extends Record({ + testId: undefined, + name: 'Unnamed Test', + steps: List(), + stepsCount: undefined, + framework: 'selenium', + sessionId: undefined, + generated: false, + tags: Set(), + runHistory: List(), + editedAt: undefined, + seqId: undefined, + seqChange: false, + uptime: 0, +}) { + // ???TODO + // idKey = "testId" + + exists() { + return this.testId !== undefined; + } + + validate() { + if (this.steps.size === 0) return false; + + return validateName(this.name, { + empty: false, + admissibleChars: ':-', + }); + } + + isComplete() { + return this.stepsCount === this.steps.size; + } + + // not the best code + toData() { + const js = this + .update('steps', steps => steps.map(step => step.toData())) + .toJS(); + + if (js.seqChange) { + const { testId, seqId } = js; + return { testId, seqId }; + } + + delete js.stepsCount; + delete js.seqChange; + + return js; + } + // not the best code +} + +const fromJS = (test = {}) => { + if (test instanceof Test) return test; + + const stepsLength = test.steps && test.steps.length; // + const editedAt = test.editedAt ? DateTime.fromMillis(test.editedAt) : undefined; + + const lastRun = Run(test.lastRun); + const runHistory = List(test.runHistory) // TODO: GOOD ENDPOINTS + .map(run => { + if (typeof run === 'string') { + return run === lastRun.runId + ? lastRun + : Run({ runId: run }) + } + return Run(run); + }); + + return new Test({ ...test, editedAt, uptime: parseInt(test.passed / test.count * 100) || 0 }) + .set('stepsCount', typeof test.stepsCount === 'number' + ? test.stepsCount + : stepsLength) // + .set('runHistory', runHistory) + .set('steps', List(test.steps).map(Step)) + .set('tags', test.tags && Set(test.tags.map(t => t.toLowerCase()))); +}; + +export default fromJS; diff --git a/frontend/app/types/client/client.js b/frontend/app/types/client/client.js new file mode 100644 index 000000000..c1a33114f --- /dev/null +++ b/frontend/app/types/client/client.js @@ -0,0 +1,24 @@ +import { List } from 'immutable'; +import Record from 'Types/Record'; +import Site from 'Types/site'; +import { DateTime } from 'luxon'; +import LoggerOptions from './loggerOptions'; + +export default Record({ + loggerOptions: LoggerOptions(), + apiKey: undefined, + tenantId: undefined, + name: undefined, + sites: List(), + optOut: true +}, { + fromJS: ({ + projects, + loggerOptions, + ...rest + }) => ({ + ...rest, + loggerOptions: LoggerOptions(loggerOptions), + sites: List(projects).map(Site), + }), +}); diff --git a/frontend/app/types/client/index.js b/frontend/app/types/client/index.js new file mode 100644 index 000000000..3cc01c671 --- /dev/null +++ b/frontend/app/types/client/index.js @@ -0,0 +1 @@ +export { default } from './client'; diff --git a/frontend/app/types/client/loggerOptions.js b/frontend/app/types/client/loggerOptions.js new file mode 100644 index 000000000..b258ba6b8 --- /dev/null +++ b/frontend/app/types/client/loggerOptions.js @@ -0,0 +1,9 @@ +import Record from 'Types/Record'; + +export default Record({ + ipWhitelist: [], + allowedDomains: [], + defaultInputMode: 0, + obscureEmailData: undefined, + obscureNumericData: undefined, +}); \ No newline at end of file diff --git a/frontend/app/types/customField.js b/frontend/app/types/customField.js new file mode 100644 index 000000000..772c3b3d1 --- /dev/null +++ b/frontend/app/types/customField.js @@ -0,0 +1,29 @@ +import Record from 'Types/Record'; +const varRegExp = new RegExp('^[A-Za-z_-][A-Za-z0-9_-]*$'); + +export const BOOLEAN = 'boolean'; +export const STRING = 'string'; +export const NUMBER = 'number'; +export const MAX_COUNT = 20; + +export default Record({ + index: undefined, + key: '', + label: '', + type: STRING, +}, { + idKey: 'index', + keyKey: '_key', + methods: { + validate() { + return varRegExp.test(this.key) && this.type !== ''; + }, + toData() { + const js = this.toJS(); + + delete js._key; + return js; + }, + }, +}); + diff --git a/frontend/app/types/dashboard/applicationActivity.js b/frontend/app/types/dashboard/applicationActivity.js new file mode 100644 index 000000000..f24b063b8 --- /dev/null +++ b/frontend/app/types/dashboard/applicationActivity.js @@ -0,0 +1,21 @@ +import Record from 'Types/Record'; + +export default Record({ + avgPageLoad: 0, + avgPageLoadProgress: 0, + avgImgLoad: 0, + avgImgLoadProgress: 0, + avgReqLoad: 0, + avgReqLoadProgress: 0, +}, { + // fromJS: aa => ({ + // avgPageLoad: aa.avgDom, + // avgPageLoadProgress: aa.avgDomProgress, + // avgImgLoad: aa.avgLoad, + // avgImgLoadProgress: aa.avgLoadProgress, + // avgReqLoad: aa.avgFirstPixel, + // avgReqLoadProgress: aa.avgFirstPixelProgress, + // ...aa, + // }), +}); + diff --git a/frontend/app/types/dashboard/callWithErrors.js b/frontend/app/types/dashboard/callWithErrors.js new file mode 100644 index 000000000..3c3aefd7c --- /dev/null +++ b/frontend/app/types/dashboard/callWithErrors.js @@ -0,0 +1,13 @@ +import Record from 'Types/Record'; + +export default Record({ + method: '', + urlHostpath: '', + allRequests: '', + '4xx': '', + '5xx': '' +}, { + // fromJS: pm => ({ + // ...pm, + // }), +}); \ No newline at end of file diff --git a/frontend/app/types/dashboard/crashes.js b/frontend/app/types/dashboard/crashes.js new file mode 100644 index 000000000..0986dddeb --- /dev/null +++ b/frontend/app/types/dashboard/crashes.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const Crashes = Record({ + chart: [], + browsers: [] +}); + + +function fromJS(data = {}) { + if (data instanceof Crashes) return data; + return new Crashes(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/domBuildingTime copy.js b/frontend/app/types/dashboard/domBuildingTime copy.js new file mode 100644 index 000000000..258902f60 --- /dev/null +++ b/frontend/app/types/dashboard/domBuildingTime copy.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const DomBuildingTime = Record({ + avg: undefined, + chart: [], +}); + + +function fromJS(data = {}) { + if (data instanceof DomBuildingTime) return data; + return new DomBuildingTime(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/domBuildingTime.js b/frontend/app/types/dashboard/domBuildingTime.js new file mode 100644 index 000000000..258902f60 --- /dev/null +++ b/frontend/app/types/dashboard/domBuildingTime.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const DomBuildingTime = Record({ + avg: undefined, + chart: [], +}); + + +function fromJS(data = {}) { + if (data instanceof DomBuildingTime) return data; + return new DomBuildingTime(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/err.js b/frontend/app/types/dashboard/err.js new file mode 100644 index 000000000..cd869b60a --- /dev/null +++ b/frontend/app/types/dashboard/err.js @@ -0,0 +1,23 @@ +import Record from 'Types/Record'; +import { convertNumberRange } from 'App/utils'; + +export default Record({ + error: '', + count: undefined, + sessions: undefined, + firstOccurrenceAt: undefined, + lastOccurrenceAt: undefined, + startTimestamp: undefined, + endTimestamp: undefined, + chart: [], +}, { + fromJS: ({ chart = [], ...err }) => { + const oldMax = [ ...chart ].sort((a, b) => b.count - a.count)[ 0 ].count; + const formattedChart = chart.map(({ count, ...rest }) => + ({ count: convertNumberRange(oldMax, 0, 2, 20, count), ...rest })); + return { + ...err, + chart: formattedChart, + } + } +}); \ No newline at end of file diff --git a/frontend/app/types/dashboard/errors.js b/frontend/app/types/dashboard/errors.js new file mode 100644 index 000000000..8d56e4c33 --- /dev/null +++ b/frontend/app/types/dashboard/errors.js @@ -0,0 +1,16 @@ +import { Record } from 'immutable'; + +const Errors = Record({ + count: undefined, + progress: undefined, + impactedSessions: undefined, + impactedSessionsProgress: undefined, + chart: [], +}); + +function fromJS(errors = {}) { + if (errors instanceof Errors) return errors; + return new Errors(errors); +} + +export default fromJS; diff --git a/frontend/app/types/dashboard/errorsByOrigin.js b/frontend/app/types/dashboard/errorsByOrigin.js new file mode 100644 index 000000000..bdbceab60 --- /dev/null +++ b/frontend/app/types/dashboard/errorsByOrigin.js @@ -0,0 +1,13 @@ +import { Record } from 'immutable'; + +const ErrorsByOrigin = Record({ + chart: [] +}); + + +function fromJS(data = {}) { + if (data instanceof ErrorsByOrigin) return data; + return new ErrorsByOrigin(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/errorsByType.js b/frontend/app/types/dashboard/errorsByType.js new file mode 100644 index 000000000..ccedc566e --- /dev/null +++ b/frontend/app/types/dashboard/errorsByType.js @@ -0,0 +1,13 @@ +import { Record } from 'immutable'; + +const ErrorsByType = Record({ + chart: [], +}); + + +function fromJS(data = {}) { + if (data instanceof ErrorsByType) return data; + return new ErrorsByType(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/helper.js b/frontend/app/types/dashboard/helper.js new file mode 100644 index 000000000..80f406251 --- /dev/null +++ b/frontend/app/types/dashboard/helper.js @@ -0,0 +1,37 @@ + +// const getPerformanceDensity = (period) => { +// switch (period) { +// case HALF_AN_HOUR: +// return 30; +// case WEEK: +// return 84; +// case MONTH: +// return 90; +// case DAY: +// return 48; +// default: +// return 48; +// } +// }; + +const DAY = 1000 * 60 * 60 * 24; +const WEEK = DAY * 8; + +const startWithZero = num => (num < 10 ? `0${ num }` : `${ num }`); +const weekdays = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]; +// const months = [ "January", "February" ]; +export const getTimeString = (ts, period) => { + const date = new Date(ts); + const diff = period.end - period.start; + if (diff <= DAY) { + var isPM = date.getHours() >= 12; + return `${ isPM ? date.getHours() - 12 : date.getHours() }:${ startWithZero(date.getMinutes()) } ${isPM? 'pm' : 'am'}`; + } + if (diff <= WEEK) { + return weekdays[ date.getDay() ]; + } + return `${ date.getDate() }/${ startWithZero(date.getMonth() + 1) } `; +}; + +export const getChartFormatter = period => (data = []) => + data.map(({ timestamp, ...rest }) => ({ time: getTimeString(timestamp, period), ...rest })); \ No newline at end of file diff --git a/frontend/app/types/dashboard/image.js b/frontend/app/types/dashboard/image.js new file mode 100644 index 000000000..57f5f7507 --- /dev/null +++ b/frontend/app/types/dashboard/image.js @@ -0,0 +1,16 @@ +import Record from 'Types/Record'; + +const getName = (url = '') => url.split('/').filter(part => !!part).pop(); + +export default Record({ + avgDuration: undefined, + sessions: undefined, + chart: [], + url: '', + name: '', +}, { + fromJS: (image) => ({ + ...image, + name: getName(image.url), + }) +}); diff --git a/frontend/app/types/dashboard/index.js b/frontend/app/types/dashboard/index.js new file mode 100644 index 000000000..7359334e5 --- /dev/null +++ b/frontend/app/types/dashboard/index.js @@ -0,0 +1,587 @@ +import { Map, List } from 'immutable'; +import Session from 'Types/session'; +import { camelCased } from 'App/utils'; + +import { getChartFormatter } from './helper'; +import ProcessedSessions from './processedSessions'; +import DomBuildingTime from './domBuildingTime'; +import MemoryConsumption from './memoryConsumption'; +import ResponseTime from './responseTime'; +import ErrorsByType from './errorsByType'; +import OverviewWidget from './overviewWidget'; +import TopDomains from './topDomains'; +import SpeedLocation from './speedLocation'; +import SessionsPerBrowser from './sessionsPerBrowser'; +import ErrorsByOrigin from './errorsByOrigin'; +import SlowestResources from './slowestResources'; +import ResponseTimeDistribution from './responseTimeDistribution'; +import SessionsImpactedBySlowRequests from './sessionsImpactedBySlowRequests'; +import TimeToRender from './timeToRender'; +import SessionsImpactedByJSErrors from './sessionsImpactedByJSErrors'; +import ApplicationActivity from './applicationActivity'; +import TopMetrics from './topMetrics'; +import Errors from './errors'; +import UserActivity from './userActivity'; +import Performance from './performance'; +import Crashes from './crashes'; +import PageMetrics from './pageMetrics'; +import SlowestDomains from './slowestDomains'; +import ResourceLoadingTime from './resourceLoadingTime'; + +import Image from './image'; +import Resource from './resource'; +import Err from './err'; +import MissingResource from './missingResource'; + +export const WIDGET_LIST = [{ + key: "sessions", + name: "Processed Sessions", + description: 'Number of recorded user sessions.', + thumb: 'processed_sessions.png', + dataWrapper: (ps, period) => ProcessedSessions(ps) + .update("chart", getChartFormatter(period)), + }, { + key: "applicationActivity", + name: "Application Activity", + description: 'Average loading time of pages, images and browser requests.', + thumb: 'application_activity.png', + dataWrapper: ApplicationActivity, + }, { + key: "errors", + name: "Exceptions", + description: 'Number of errors and impacted user sessions.', + thumb: 'errors.png', + dataWrapper: (e, period) => Errors(e) + .update("chart", getChartFormatter(period)), + }, { + key: "userActivity", + name: "User Activity", + description: 'The average user feedback score, average number of visited pages per session and average session duration.', + thumb: 'user_activity.png', + dataWrapper: UserActivity, + }, { + key: "pageMetrics", + name: "Page Metrics", + description: "Average speed metrics across all pages: First Meaningful Pain and DOM Content Loaded.", + thumb: 'page_metrics.png', + dataWrapper: PageMetrics, + }, { + key: "performance", + name: "Performance", + description: "Compare the average loading times of your web app's resources (pages, images and browser requests)", + thumb: 'performance.png', + dataWrapper: (p, period) => Performance(p) + .update("chart", getChartFormatter(period)), + }, { + key: "slowestImages", + name: "Slowest Images", + description: 'List of images that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + dataWrapper: list => List(list).map(Image).sort((i1, i2) => { + if (i1.sessions < 1000) return i2.sessions -i1.sessions; + const sessionK1 = Math.trunc(i1.sessions/1000); + const sessionK2 = Math.trunc(i2.sessions/1000); + if (sessionK1 !== sessionK2) return sessionK2 - sessionK1; + return i2.avgDuration - i1.avgDuration; + }), + }, + // { + // key: "errorsTrend", + // name: "Most Impactful Errors", + // description: 'List of errors and exceptions, sorted by the number of impacted sessions.', + // thumb: 'most_Impactful_errors.png', + // dataWrapper: list => List(list).map(Err), + // }, + { + key: "sessionsFrustration", + name: "Recent Frustrations", + description: "List of recent sessions where users experienced some kind of frustrations, such as click rage.", + thumb: 'recent_frustrations.png', + dataWrapper: list => List(list).map(Session), + }, + { + key: "sessionsFeedback", + name: "Recent Negative Feedback", + description: "List of recent sessions where users reported an issue or a bad experience.", + thumb: 'negative_feedback.png', + dataWrapper: list => List(list).map(Session), + }, + { + key: "missingResources", + name: "Missing Resources", + description: "List of resources, such as images, that couldn't be loaded.", + thumb: 'missing_resources.png', + type: 'resources', + dataWrapper: list => List(list).map(MissingResource), + }, + // { + // key: "sessionsPerformance", + // name: "Recent Performance Issues", + // description: "", + // dataWrapper: list => List(list).map(Session), + // } + { + key: "slowestResources", + name: "Slowest Resources", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'resources', + dataWrapper: list => List(list).map(SlowestResources) + }, + { + key: "overview", + name: "Overview Widgets", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + dataWrapper: (p, period) => { + return List(p) + .map(item => OverviewWidget({ key: camelCased(item.key), ...item.data})) + .map(widget => widget.update("chart", getChartFormatter(period))) + } + // dataWrapper: (p, period) => List(p) + // .update("chart", getChartFormatter(period)) + }, + { + key: "speedLocation", + name: "Speed Index by Location", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: list => SpeedLocation(list) + }, + { + key: "slowestDomains", + name: "Slowest Domains", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + // dataWrapper: list => List(list).sort((a, b) => a.avg >= b.avg).map(SlowestDomains) + dataWrapper: list => SlowestDomains(list) + .update("partition", (partition) => List(partition).sort((a, b) => b.avg - a.avg)) + }, + { + key: "sessionsPerBrowser", + name: "Sessions per Browser", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: list => SessionsPerBrowser(list) + // .update("chart", (list) => List(list).sort((a, b) => a.count >= b.count)) + }, + { + key: "resourcesLoadingTime", + name: "Resource Fetch Time", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'resources', + dataWrapper: (list, period) => DomBuildingTime(list) + .update("chart", getChartFormatter(period)) + }, + { + key: "timeToRender", + name: "Time To Render", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => TimeToRender(p) + .update("chart", getChartFormatter(period)) + }, + { + key: "impactedSessionsBySlowPages", + name: "Sessions Impacted by Slow Requests", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => SessionsImpactedBySlowRequests({ chart: p}) + .update("chart", getChartFormatter(period)) + }, + { + key: "memoryConsumption", + name: "Memory Consumption", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => MemoryConsumption(p) + // .update("chart", list => list.map((i) => ({...i, avgUsedJsHeapSize: i.avgUsedJsHeapSize/1024/1024 }))) + .update("chart", getChartFormatter(period)) + }, + { + key: "cpu", + name: "CPU Load", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => MemoryConsumption(p) + .update("chart", getChartFormatter(period)), + }, + { + key: "fps", + name: "Framerate", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => MemoryConsumption(p) + .update("chart", getChartFormatter(period)), + }, + { + key: "crashes", + name: "Crashes", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (e, period) => Crashes(e) + .update("chart", getChartFormatter(period)) + }, + { + key: "resourceTypeVsResponseEnd", + name: "Resource Loaded vs Response End", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'resources', + dataWrapper: (p, period) => ErrorsByType({chart: p}) + .update("chart", getChartFormatter(period)) + }, + { + key: "resourcesCountByType", + name: "Breakdown of Loaded Resources", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'resources', + dataWrapper: (p, period) => ErrorsByType({chart: p}) + .update("chart", getChartFormatter(period)) + }, + { + key: "resourcesVsVisuallyComplete", + name: "Resource Loaded vs Visually Complete", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => ErrorsByType({chart: p}) + .update("chart", getChartFormatter(period)) + // .update('chart', (data) => { + // return data.map(i => ({...i, avgTimeToRender: i.avgTimeToRender / 100})); + // }) + }, + { + key: "pagesDomBuildtime", + name: "DOM Build Time", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => DomBuildingTime(p) + .update("chart", getChartFormatter(period)) + }, + { + key: "pagesResponseTime", + name: "Page Response Time", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => ResponseTime(p) + .update("chart", getChartFormatter(period)) + }, + { + key: "pagesResponseTimeDistribution", + name: "Page Response Time Distribution", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'performance', + dataWrapper: (p, period) => ResponseTimeDistribution(p) + .update("chart", getChartFormatter(period)) + .update("extremeValues", list => list.map(i => ({...i, time: 'Extreme Values'}))) + .update("percentiles", list => list.map(i => ({ ...i, responseTime: Math.round(i.responseTime)}))) + }, + { + key: "domainsErrors_4xx", + name: "Top Domains with 4xx Fetch Errors", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'errors', + dataWrapper: (p, period) => TopDomains({ chart: p}) + .update("chart", getChartFormatter(period)) + // .updateIn(["chart", "5xx"], getChartFormatter(period)) + }, + { + key: "domainsErrors_5xx", + name: "Top Domains with 5xx Fetch Errors", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'errors', + dataWrapper: (p, period) => TopDomains({ chart: p}) + .update("chart", getChartFormatter(period)) + // .updateIn(["chart", "5xx"], getChartFormatter(period)) + }, + { + key: "errorsPerDomains", + name: "Errors per Domain", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'errors', + // dataWrapper: list => List(list) + dataWrapper: list => List(list).sort((a, b) => b.errorsCount - a.errorsCount).take(5) + }, + { + key: "callsErrors", + name: "Fetch Calls with Errors", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'errors', + dataWrapper: list => List(list).sort((a, b) => b.allRequests - a.allRequests) + }, + { + key: "errorsPerType", + name: "Errors by Type", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'errors', + dataWrapper: (p, period) => ErrorsByType({chart: p}) + .update("chart", getChartFormatter(period)) + }, + { + key: "resourcesByParty", + name: "Errors by Origin", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'errors', + dataWrapper: (p, period) => ErrorsByOrigin({chart: p}) + .update("chart", getChartFormatter(period)) + }, + { + key: "impactedSessionsByJsErrors", + name: "Sessions Affected by JS Errors", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'errors', + dataWrapper: (p, period) => SessionsImpactedByJSErrors(p) + .update("chart", getChartFormatter(period)) + }, + { + key: "busiestTimeOfDay", + name: "Busiest Time of the Day", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + dataWrapper: list => List(list) + }, + { + key: "topMetrics", + name: "Top Metrics", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + dataWrapper: TopMetrics + }, + + // Overview Widgets + { + key: 'countSessions', + name: 'Captured Sessions', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'New vs Returning', + type: 'overview', + tooltipLabel: "Count", + dataWrapper: list => List(list) + }, + { + key: 'avgTimeToRender', + name: 'Time To Render', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => TimeToRender(list) + }, + { + key: 'avgTimeToInteractive', + name: 'Time To Interactive', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgPageLoadTime', + name: 'Page Load Time', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgImageLoadTime', + name: 'Image Load Time', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgRequestLoadTime', + name: 'Request Load Time', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgDomContentLoadStart', + name: 'DOM Content Loaded', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgPagesDomBuildtime', + name: 'DOM Build Time', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: (list, period) => DomBuildingTime(list) + .update("chart", getChartFormatter(period)) + }, + { + key: 'avgSessionDuration', + name: 'Session Duration', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'min', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgVisitedPages', + name: 'No. of Visited Pages', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgPagesResponseTime', + name: 'Page Response Time', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => ResponseTime(list) + }, + { + key: 'avgTillFirstBit', + name: 'Time Till First Byte', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => ResponseTime(list) + }, + // { + // key: 'avgResponseTime', + // name: 'Response Time', + // description: 'Lorem ipsum...', + // thumb: 'na.png', + // subtext: 'test', + // unit: 'ms', + // type: 'overview', + // dataWrapper: list => List(list) + // }, + // { + // key: 'requestsCount', + // name: 'Request Count', + // description: 'Lorem ipsum...', + // thumb: 'na.png', + // subtext: 'test', + // // unit: 'ms', + // type: 'overview', + // dataWrapper: list => List(list) + // }, + { + key: 'avgFirstContentfulPixel', + name: 'First Meaningful Paint', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgFirstPaint', + name: 'First Paint', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'ms', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgUsedJsHeapSize', + name: 'Memory Consumption', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + unit: 'mb', + type: 'overview', + dataWrapper: list => List(list) + }, + { + key: 'avgCpu', + name: 'CPU Load', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + type: 'overview', + unit: '%', + dataWrapper: list => List(list) + }, + { + key: 'avgFps', + name: 'Framerate', + description: 'Lorem ipsum...', + thumb: 'na.png', + subtext: 'test', + type: 'overview', + dataWrapper: list => List(list) + }, + +]; + +export const WIDGET_KEYS = WIDGET_LIST.map(({ key }) => key); + +const WIDGET_MAP = {}; +WIDGET_LIST.forEach(w => { WIDGET_MAP[ w.key ] = w; }); + +const OVERVIEW_WIDGET_MAP = {}; +WIDGET_LIST.filter(w => w.type === 'overview').forEach(w => { OVERVIEW_WIDGET_MAP[ w.key ] = w; }); + +export { + WIDGET_MAP, + OVERVIEW_WIDGET_MAP, + ProcessedSessions, + ApplicationActivity, + Errors, + UserActivity, + Performance, + PageMetrics, + Image, + Err, + SlowestDomains, + ResourceLoadingTime +}; diff --git a/frontend/app/types/dashboard/memoryConsumption.js b/frontend/app/types/dashboard/memoryConsumption.js new file mode 100644 index 000000000..f585ac4fd --- /dev/null +++ b/frontend/app/types/dashboard/memoryConsumption.js @@ -0,0 +1,16 @@ +import { Record } from 'immutable'; + +const MemoryConsumption = Record({ + avgFps: undefined, + avgUsedJsHeapSize: undefined, + avgCpu: undefined, + chart: [], +}); + +function fromJS(data = {}) { + const size = data.avgUsedJsHeapSize && data.avgUsedJsHeapSize / 1024 / 1024 + if (data instanceof MemoryConsumption) return data; + return new MemoryConsumption({...data, avgUsedJsHeapSize: size}); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/missingResource.js b/frontend/app/types/dashboard/missingResource.js new file mode 100644 index 000000000..8ca975973 --- /dev/null +++ b/frontend/app/types/dashboard/missingResource.js @@ -0,0 +1,26 @@ +import Record from 'Types/Record'; +import { convertNumberRange, getResourceName } from 'App/utils'; + + +export default Record({ + url: '', + name: '', + count: undefined, + sessions: undefined, + startedAt: undefined, + endedAt: undefined, + startTimestamp: undefined, + endTimestamp: undefined, + chart: [], +}, { + fromJS: ({ chart = [], ...missingResource }) => { + const oldMax = [ ...chart ].sort((a, b) => b.count - a.count)[ 0 ].count; + const formattedChart = chart.map(({ count, ...rest }) => + ({ count: convertNumberRange(oldMax, 0, 2, 20, count), ...rest })); + return { + ...missingResource, + chart: formattedChart, + name: getResourceName(missingResource.url), + } + } +}); \ No newline at end of file diff --git a/frontend/app/types/dashboard/overviewWidget.js b/frontend/app/types/dashboard/overviewWidget.js new file mode 100644 index 000000000..6133c5946 --- /dev/null +++ b/frontend/app/types/dashboard/overviewWidget.js @@ -0,0 +1,20 @@ +import { Record } from 'immutable'; + +const OverviewWidget = Record({ + key: undefined, + value: undefined, + progress: undefined, + chart: [], +}); + + +function fromJS(data = {}) { + if (data instanceof OverviewWidget) return data; + + if (data.key === "avgSessionDuration") { + data.value = data.value / 100000 + } + return new OverviewWidget(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/pageMetrics.js b/frontend/app/types/dashboard/pageMetrics.js new file mode 100644 index 000000000..9c92d9486 --- /dev/null +++ b/frontend/app/types/dashboard/pageMetrics.js @@ -0,0 +1,14 @@ +import Record from 'Types/Record'; + +export default Record({ + avgLoad: 0, + avgLoadProgress: 0, + avgFirstContentfulPixel: 0, + avgFirstContentfulPixelProgress: 0, +}, { + fromJS: pm => ({ + ...pm, + avgFirstContentfulPixel: pm.avgFirstContentfulPixel || pm.avgFirstPixel, + avgFirstContentfulPixelProgress: pm.avgFirstContentfulPixelProgress || pm.avgFirstPixelProgress, + }), +}); \ No newline at end of file diff --git a/frontend/app/types/dashboard/performance.js b/frontend/app/types/dashboard/performance.js new file mode 100644 index 000000000..88932f22b --- /dev/null +++ b/frontend/app/types/dashboard/performance.js @@ -0,0 +1,13 @@ +import { Record } from 'immutable'; + +const Performance = Record({ + chart: [], +}); + + +function fromJS(performance = {}) { + if (performance instanceof Performance) return performance; + return new Performance(performance); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/processedSessions.js b/frontend/app/types/dashboard/processedSessions.js new file mode 100644 index 000000000..2f719648f --- /dev/null +++ b/frontend/app/types/dashboard/processedSessions.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const ProcessedSessions = Record({ + count: undefined, + progress: undefined, + chart: [], +}); + +function fromJS(processedSessions = {}) { + if (processedSessions instanceof ProcessedSessions) return processedSessions; + return new ProcessedSessions(processedSessions); +} + +export default fromJS; diff --git a/frontend/app/types/dashboard/resource.js b/frontend/app/types/dashboard/resource.js new file mode 100644 index 000000000..341ef8e47 --- /dev/null +++ b/frontend/app/types/dashboard/resource.js @@ -0,0 +1,16 @@ +import Record from 'Types/Record'; + +const getName = (url = '') => url.split('/').filter(part => !!part).pop(); + +export default Record({ + avgDuration: undefined, + sessions: undefined, + chart: [], + url: '', + name: '', +}, { + fromJS: (resource) => ({ + ...resource, + name: getName(resource.url), + }) +}); diff --git a/frontend/app/types/dashboard/resourceLoadingTime.js b/frontend/app/types/dashboard/resourceLoadingTime.js new file mode 100644 index 000000000..cc23bdae9 --- /dev/null +++ b/frontend/app/types/dashboard/resourceLoadingTime.js @@ -0,0 +1,13 @@ +import { Record } from 'immutable'; + +const ResourceLoadingTime = Record({ + avg: undefined, + timestamp: undefined +}); + +function fromJS(resourceLoadingTime = {}) { + if (resourceLoadingTime instanceof ResourceLoadingTime) return resourceLoadingTime; + return new ResourceLoadingTime(resourceLoadingTime); +} + +export default fromJS; diff --git a/frontend/app/types/dashboard/responseTime.js b/frontend/app/types/dashboard/responseTime.js new file mode 100644 index 000000000..961eda42b --- /dev/null +++ b/frontend/app/types/dashboard/responseTime.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const ResponseTime = Record({ + avg: undefined, + chart: [], +}); + + +function fromJS(data = {}) { + if (data instanceof ResponseTime) return data; + return new ResponseTime(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/responseTimeDistribution.js b/frontend/app/types/dashboard/responseTimeDistribution.js new file mode 100644 index 000000000..a53f3555f --- /dev/null +++ b/frontend/app/types/dashboard/responseTimeDistribution.js @@ -0,0 +1,17 @@ +import { Record } from 'immutable'; + +const ResponseTimeDistribution = Record({ + chart: [], + avg: undefined, + percentiles: [], + extremeValues: [], + total: undefined +}); + + +function fromJS(data = {}) { + if (data instanceof ResponseTimeDistribution) return data; + return new ResponseTimeDistribution(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/sessionsImpactedByJSErrors.js b/frontend/app/types/dashboard/sessionsImpactedByJSErrors.js new file mode 100644 index 000000000..c0368744d --- /dev/null +++ b/frontend/app/types/dashboard/sessionsImpactedByJSErrors.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const SessionsImpactedByJSErrors = Record({ + errorsCount: undefined, + chart: [] +}); + + +function fromJS(data = {}) { + if (data instanceof SessionsImpactedByJSErrors) return data; + return new SessionsImpactedByJSErrors(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/sessionsImpactedBySlowRequests.js b/frontend/app/types/dashboard/sessionsImpactedBySlowRequests.js new file mode 100644 index 000000000..4d5d5fc61 --- /dev/null +++ b/frontend/app/types/dashboard/sessionsImpactedBySlowRequests.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const SessionsImpactedBySlowRequests = Record({ + avg: undefined, + chart: [], +}); + + +function fromJS(data = {}) { + if (data instanceof SessionsImpactedBySlowRequests) return data; + return new SessionsImpactedBySlowRequests(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/sessionsPerBrowser.js b/frontend/app/types/dashboard/sessionsPerBrowser.js new file mode 100644 index 000000000..cd8662b13 --- /dev/null +++ b/frontend/app/types/dashboard/sessionsPerBrowser.js @@ -0,0 +1,13 @@ +import { Record } from 'immutable'; + +const SessionsPerBrowser = Record({ + count: undefined, + chart: [], +}); + +function fromJS(sessionsPerBrowser = {}) { + if (sessionsPerBrowser instanceof SessionsPerBrowser) return sessionsPerBrowser; + return new SessionsPerBrowser({...sessionsPerBrowser, avg: Math.round(sessionsPerBrowser.avg)}); +} + +export default fromJS; diff --git a/frontend/app/types/dashboard/slowestDomains.js b/frontend/app/types/dashboard/slowestDomains.js new file mode 100644 index 000000000..fc15ed831 --- /dev/null +++ b/frontend/app/types/dashboard/slowestDomains.js @@ -0,0 +1,13 @@ +import { Record } from 'immutable'; + +const SlowestDomains = Record({ + partition: [], + avg: undefined, +}); + +function fromJS(slowestDomains = {}) { + if (slowestDomains instanceof SlowestDomains) return slowestDomains; + return new SlowestDomains({...slowestDomains, avg: Math.round(slowestDomains.avg)}); +} + +export default fromJS; diff --git a/frontend/app/types/dashboard/slowestResources.js b/frontend/app/types/dashboard/slowestResources.js new file mode 100644 index 000000000..54e00984b --- /dev/null +++ b/frontend/app/types/dashboard/slowestResources.js @@ -0,0 +1,21 @@ +import Record from 'Types/Record'; +import { fileType, fileName } from 'App/utils'; + +const validTypes = ['jpg', 'jpeg', 'js', 'css', 'woff', 'css', 'png', 'gif', 'svg'] + +export default Record({ + avg: 0, + url: '', + type: '', + name: '', + chart: [], +}, { + fromJS: pm => { + const type = fileType(pm.url).toLowerCase(); + return { + ...pm, + // type: validTypes.includes(type) ? type : 'n/a', + // fileName: fileName(pm.url) + } + }, +}); \ No newline at end of file diff --git a/frontend/app/types/dashboard/speedLocation.js b/frontend/app/types/dashboard/speedLocation.js new file mode 100644 index 000000000..f1774eba0 --- /dev/null +++ b/frontend/app/types/dashboard/speedLocation.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const SpeedLocation = Record({ + avg: undefined, + chart: [], +}); + + +function fromJS(data = {}) { + if (data instanceof SpeedLocation) return data; + return new SpeedLocation(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/timeToRender.js b/frontend/app/types/dashboard/timeToRender.js new file mode 100644 index 000000000..e07521498 --- /dev/null +++ b/frontend/app/types/dashboard/timeToRender.js @@ -0,0 +1,13 @@ +import { Record } from 'immutable'; + +const TimeToRender = Record({ + avg: undefined, + chart: [], +}); + +function fromJS(data = {}) { + if (data instanceof TimeToRender) return data; + return new TimeToRender(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/topDomains.js b/frontend/app/types/dashboard/topDomains.js new file mode 100644 index 000000000..fa92db397 --- /dev/null +++ b/frontend/app/types/dashboard/topDomains.js @@ -0,0 +1,12 @@ +import { Record } from 'immutable'; + +const TopDomains = Record({ + chart: [] +}); + +function fromJS(data = {}) { + if (data instanceof TopDomains) return data; + return new TopDomains(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/dashboard/topMetrics.js b/frontend/app/types/dashboard/topMetrics.js new file mode 100644 index 000000000..221f65d6c --- /dev/null +++ b/frontend/app/types/dashboard/topMetrics.js @@ -0,0 +1,19 @@ +import Record from 'Types/Record'; + +export default Record({ + avgResponseTime: 0, + requestsCount: 0, + avgTimeTilFirstBite: 0, + avgDomCompleteTime: 0 +}, { + // fromJS: aa => ({ + // avgPageLoad: aa.avgDom, + // avgPageLoadProgress: aa.avgDomProgress, + // avgImgLoad: aa.avgLoad, + // avgImgLoadProgress: aa.avgLoadProgress, + // avgReqLoad: aa.avgFirstPixel, + // avgReqLoadProgress: aa.avgFirstPixelProgress, + // ...aa, + // }), +}); + diff --git a/frontend/app/types/dashboard/userActivity.js b/frontend/app/types/dashboard/userActivity.js new file mode 100644 index 000000000..788349337 --- /dev/null +++ b/frontend/app/types/dashboard/userActivity.js @@ -0,0 +1,10 @@ +import Record from 'Types/Record'; + +export default Record({ + avgVisitedPages: undefined, + avgVisitedPagesProgress: undefined, + avgDuration: undefined, + avgDurationProgress: undefined, + avgEmotionalRating: undefined, + avgEmotionalRatingProgress: undefined, +}); \ No newline at end of file diff --git a/frontend/app/types/environment.js b/frontend/app/types/environment.js new file mode 100644 index 000000000..f0b575ba6 --- /dev/null +++ b/frontend/app/types/environment.js @@ -0,0 +1,16 @@ +import Record from 'Types/Record'; +import { validateURL, validateName } from 'App/validate'; + +export default Record({ + environmentId: undefined, + url: '', + name: '', + default: undefined, +}, { + idKey: 'environmentId', + methods: { + validate() { + return validateURL(this.url) && validateName(this.name, { empty: false }); + }, + }, +}); diff --git a/frontend/app/types/errorInfo.js b/frontend/app/types/errorInfo.js new file mode 100644 index 000000000..efcb5154e --- /dev/null +++ b/frontend/app/types/errorInfo.js @@ -0,0 +1,47 @@ +import { List } from 'immutable'; +import Record from './Record'; +import Session from './session'; + +export const RESOLVED = "resolved"; +export const UNRESOLVED = "unresolved"; +export const IGNORED = "ignored"; + + +function getStck0InfoString(stack) { + const stack0 = stack[0]; + if (!stack0) return ""; + let s = stack0.function || ""; + if (stack0.url) { + s += ` (${stack0.url})`; + } + return s; +} + +const ErrorInfo = Record({ + errorId: undefined, + favorite: false, + viewed: false, + source: "", + name: "", + message: "", + stack0InfoString: '', + status: "", + parentErrorId: "", + users: 8, + sessions: 25, + lastOccurrence: 1587744479000, + firstOccurrence: 1585213274000, + chart: [], + chart24: [], + chart30: [], + tags: [], + lastHydratedSession: Session(), +}, { + fromJS: ({ stack, lastHydratedSession, ...other }) => ({ + ...other, + lastHydratedSession: Session(lastHydratedSession), + stack0InfoString: getStck0InfoString(stack || []), + }) +}); + +export default ErrorInfo; diff --git a/frontend/app/types/feedbackOptions.js b/frontend/app/types/feedbackOptions.js new file mode 100644 index 000000000..b764eb990 --- /dev/null +++ b/frontend/app/types/feedbackOptions.js @@ -0,0 +1,20 @@ +import Record from 'Types/Record'; + +export default Record({ + feedbackButtonText: 'Feedback', + feedbackButtonPosition: 'right', + feedbackButtonBackgroundColor: '#3EAAAF', + feedbackButtonBorderColor: '#3EAAAF', + feedbackButtonFontColor: '#FFFFFF', + feedbackButtonBackgroundColorHover: '#3EAAAF', + feedbackButtonBorderColorHover: '#3EAAAF', + + feedbackTitleText: 'How would you rate your experience.', + // labels: 'Hate,Dislike,Neutral,Happy,Love', + feedbackSubmitText: 'Send', + feedbackSubmitBackgroundColor: '#3EAAAF', + feedbackSubmitBorderColor: '#3EAAAF', + feedbackSubmitFontColor: '#FFFFFF', + feedbackSubmitBackgroundColorHover: '#3EAAAF', + feedbackSubmitBorderColorHover: '#3EAAAF', +}); diff --git a/frontend/app/types/filter/customFilter.js b/frontend/app/types/filter/customFilter.js new file mode 100644 index 000000000..950c1b61a --- /dev/null +++ b/frontend/app/types/filter/customFilter.js @@ -0,0 +1,110 @@ +import Record from 'Types/Record'; +import Target from 'Types/target'; +import { camelCased } from 'App/utils'; +// import { getEventIcon } from 'Types/filter'; + +const CLICK = 'CLICK'; +const INPUT = 'INPUT'; +const LOCATION = 'LOCATION'; +const VIEW = 'VIEW_IOS'; +const CONSOLE = 'ERROR'; +const METADATA = 'METADATA'; +const CUSTOM = 'CUSTOM'; +const URL = 'URL'; +const CLICK_RAGE = 'CLICKRAGE'; +const USER_BROWSER = 'USERBROWSER'; +const USER_OS = 'USEROS'; +const USER_COUNTRY = 'USERCOUNTRY'; +const USER_DEVICE = 'USERDEVICE'; +const PLATFORM = 'PLATFORM'; +const DURATION = 'DURATION'; +const REFERRER = 'REFERRER'; +const ERROR = 'ERROR'; +const MISSING_RESOURCE = 'MISSINGRESOURCE'; +const SLOW_SESSION = 'SLOWSESSION'; +const JOURNEY = 'JOUNRNEY'; +const FETCH = 'REQUEST'; +const GRAPHQL = 'GRAPHQL'; +const STATEACTION = 'STATEACTION'; +const REVID = 'REVID'; +const USERANONYMOUSID = 'USERANONYMOUSID'; +const USERID = 'USERID'; + +export const KEYS = { + ERROR, + MISSING_RESOURCE, + SLOW_SESSION, + CLICK_RAGE, + CLICK, + INPUT, + LOCATION, + VIEW, + CONSOLE, + METADATA, + CUSTOM, + URL, + USER_BROWSER, + USER_OS, + USER_DEVICE, + PLATFORM, + DURATION, + REFERRER, + USER_COUNTRY, + JOURNEY, + FETCH, + GRAPHQL, + STATEACTION, + REVID, + USERANONYMOUSID, + USERID +}; + +const getOperatorDefault = (type) => { + if (type === KEYS.MISSING_RESOURCE) return 'true'; + if (type === KEYS.SLOW_SESSION) return 'true'; + if (type === KEYS.CLICK_RAGE) return 'true'; + if (type === KEYS.CLICK) return 'on'; + + return 'is'; +} + +const getLabel = (event) => { + if (event.type === KEYS.USER_COUNTRY) return 'Country'; + if (event.type === KEYS.USER_BROWSER) return 'Browser'; + if (event.type === KEYS.USERID) return 'User Id'; + if (event.type === KEYS.USER_DEVICE) return 'Device'; + if (event.type === KEYS.REFERRER) return 'Referrer'; + + return event.label || event.type || event.key; +} + +export default Record({ + timestamp: 0, + key: '', + operator: 'is', + label: '', + icon: '', + type: '', + value: '', + custom: '', + target: Target(), + level: '', + source: null, + hasNoValue: false, + isFilter: false, + icon: '', + actualValue: '', +}, { + keyKey: "_key", + fromJS: ({ value, target, ...event }) => ({ + ...event, + type: event.type, // camelCased(event.type.toLowerCase()), + key: event.type === METADATA ? event.label : event.key || event.type, // || camelCased(event.type.toLowerCase()), + label: getLabel(event), + target: Target(target), + operator: event.operator || getOperatorDefault(event.type), + // value: target ? target.label : event.value, + value: typeof value === 'string' ? [value] : value, + icon: 'filters/metadata' + }), +}) diff --git a/frontend/app/types/filter/event.js b/frontend/app/types/filter/event.js new file mode 100644 index 000000000..2a6f54da6 --- /dev/null +++ b/frontend/app/types/filter/event.js @@ -0,0 +1,88 @@ +import Record from 'Types/Record'; +import Target from 'Types/target'; +import { defaultOperator, getEventIcon } from 'Types/filter'; + +const CONSOLE = 'ERROR'; +const FETCH = 'REQUEST'; +const GRAPHQL = 'GRAPHQL'; +const STATEACTION = 'STATEACTION'; +const REVID = 'REVID'; +const CLICK = 'CLICK'; +const INPUT = 'INPUT'; +const LOCATION = 'LOCATION'; +const VIEW = 'VIEW'; +const CUSTOM = 'CUSTOM'; +const METADATA = 'METADATA'; +const USERANONYMOUSID = 'USERANONYMOUSID'; +const USERID = 'USERID'; +const ERROR = 'ERROR'; + +export const TYPES = { + CONSOLE, + GRAPHQL, + STATEACTION, + FETCH, + REVID, + CLICK, + INPUT, + LOCATION, + VIEW, + CUSTOM, + METADATA, + USERANONYMOUSID, + USERID, + ERROR +}; + +function getLabelText(type, source) { + if (type === TYPES.CLICK) return 'Click'; + if (type === TYPES.LOCATION) return 'Page'; + if (type === TYPES.VIEW) return 'View'; + if (type === TYPES.INPUT) return 'Input'; + // if (type === TYPES.CONSOLE) return 'Console'; + if (type === TYPES.METADATA) return 'Metadata'; + if (type === TYPES.GRAPHQL) return 'GraphQL'; + if (type === TYPES.STATEACTION) return 'Store Action'; + if (type === TYPES.FETCH) return 'Fetch'; + if (type === TYPES.REVID) return 'Rev ID'; + if (type === TYPES.ERROR) return 'Error'; + if (type === TYPES.USERID) return 'User Id'; + if (type === TYPES.USERANONYMOUSID) return 'User Anonymous Id'; + if (type === TYPES.REVID) return 'Rev ID'; + if (type === TYPES.CUSTOM) { + if (!source) return 'Custom'; + return source; + } + return '?'; +} + +export default Record({ + timestamp: 0, + key: '', + label: '', + operator: 'on', + type: '', + searchType: '', + value: '', + custom: '', + inputValue: '', + target: Target(), + level: '', + source: null, + icon: '', +}, { + keyKey: "_key", + fromJS: ({ target, type = "" , ...event }) => { + const viewType = type.split('_')[0]; + return { + ...event, + type: viewType, + searchType: event.searchType || type, + label: getLabelText(viewType, event.source), + target: Target(target), + operator: event.operator || defaultOperator(event), + // value: target ? target.label : event.value, + icon: event.icon || getEventIcon({...event, type: viewType }) + }; + } +}) diff --git a/frontend/app/types/filter/filter.js b/frontend/app/types/filter/filter.js new file mode 100644 index 000000000..8ff34b584 --- /dev/null +++ b/frontend/app/types/filter/filter.js @@ -0,0 +1,146 @@ +import { List, Map } from 'immutable'; +import Record from 'Types/Record'; +import { KEYS } from 'Types/filter/customFilter'; +import { TYPES } from 'Types/filter/event'; +import { + DATE_RANGE_VALUES, + CUSTOM_RANGE, + dateRangeValues, + getDateRangeFromValue +} from 'App/dateRange'; +import Event from './event'; +import CustomFilter from './customFilter'; + +const rangeValue = DATE_RANGE_VALUES.LAST_7_DAYS; +const range = getDateRangeFromValue(rangeValue); +const startDate = range.start.unix() * 1000; +const endDate = range.end.unix() * 1000; + +export default Record({ + name: undefined, + id: undefined, + referrer: undefined, + userBrowser: undefined, + userOs: undefined, + userCountry: undefined, + userDevice: undefined, + fid0: undefined, + events: List(), + filters: List(), + minDuration: undefined, + maxDuration: undefined, + custom: Map(), + rangeValue, + startDate, + endDate, + + sort: undefined, + order: undefined, + + viewed: undefined, + consoleLogCount: undefined, + eventsCount: undefined, + + suspicious: undefined, + consoleLevel: undefined, + strict: false, +}, { + fromJS({ filters, events, custom, ...filter }) { + let startDate; + let endDate; + const rValue = filter.rangeValue || rangeValue; + if (rValue !== CUSTOM_RANGE) { + const range = getDateRangeFromValue(rValue); + startDate = range.start.unix() * 1000; + endDate = range.end.unix() * 1000; + } + return { + ...filter, + startDate, + endDate, + events: List(events).map(Event), + filters: List(filters).map(CustomFilter), + custom: Map(custom), + } + } +}); + +export const preloadedFilters = []; + +export const defaultFilters = [ + { + category: 'Interactions', + type: 'default', + keys: [ + { label: 'Click', key: KEYS.CLICK, type: KEYS.CLICK, filterKey: KEYS.CLICK, icon: 'filters/click', isFilter: false }, + { label: 'Input', key: KEYS.INPUT, type: KEYS.INPUT, filterKey: KEYS.INPUT, icon: 'event/input', isFilter: false }, + { label: 'Page', key: KEYS.LOCATION, type: KEYS.LOCATION, filterKey: KEYS.LOCATION, icon: 'event/link', isFilter: false }, + { label: 'View', key: KEYS.VIEW, type: KEYS.VIEW, filterKey: KEYS.VIEW, icon: 'event/view', isFilter: false } + ] + }, + { + category: 'Gear', + type: 'default', + keys: [ + { label: 'OS', key: KEYS.USER_OS, type: KEYS.USER_OS, filterKey: KEYS.USER_OS, icon: 'os', isFilter: true }, + { label: 'Browser', key: KEYS.USER_BROWSER, type: KEYS.USER_BROWSER, filterKey: KEYS.USER_BROWSER, icon: 'window', isFilter: true }, + { label: 'Device', key: KEYS.USER_DEVICE, type: KEYS.USER_DEVICE, filterKey: KEYS.USER_DEVICE, icon: 'device', isFilter: true }, + { label: 'Rev ID', key: KEYS.REVID, type: KEYS.REVID, filterKey: KEYS.REVID, icon: 'filters/border-outer', isFilter: true }, + { label: 'Platform', key: KEYS.PLATFORM, type: KEYS.PLATFORM, filterKey: KEYS.PLATFORM, icon: 'filters/phone-laptop', isFilter: true } + ] + }, + { + category: 'Recording Attributes', + type: 'default', + keys: [ + { label: 'Referrer', key: KEYS.REFERRER, type: KEYS.REFERRER, filterKey: KEYS.REFERRER, icon: 'chat-square-quote', isFilter: true }, + { label: 'Duration', key: KEYS.DURATION, type: KEYS.DURATION, filterKey: KEYS.DURATION, icon: 'clock', isFilter: true }, + { label: 'Country', key: KEYS.USER_COUNTRY, type: KEYS.USER_COUNTRY, filterKey: KEYS.USER_COUNTRY, icon: 'map-marker-alt', isFilter: true }, + ] + }, + { + category: 'Javascript', + type: 'default', + keys: [ + { label: 'Errors', key: KEYS.ERROR, type: KEYS.ERROR, filterKey: KEYS.ERROR, icon: 'exclamation-circle', isFilter: false }, + { label: 'Fetch Requests', key: KEYS.FETCH, type: KEYS.FETCH, filterKey: KEYS.FETCH, icon: 'fetch', isFilter: false }, + { label: 'GraphQL Queries', key: KEYS.GRAPHQL, type: KEYS.GRAPHQL, filterKey: KEYS.GRAPHQL, icon: 'vendors/graphql', isFilter: false }, + { label: 'Store Actions', key: KEYS.STATEACTION, type: KEYS.STATEACTION, filterKey: KEYS.STATEACTION, icon: 'store', isFilter: false }, + { label: 'Custom Events', key: KEYS.CUSTOM, type: KEYS.CUSTOM, filterKey: KEYS.CUSTOM, icon: 'filters/file-code', isFilter: false }, + ] + }, + { + category: 'User', + type: 'default', + keys: [ + { label: 'User ID', key: KEYS.USERID, type: KEYS.USERID, filterKey: KEYS.USERID, icon: 'filters/user-alt', isFilter: true }, + { label: 'Anonymous ID', key: KEYS.USERANONYMOUSID, type: KEYS.USERANONYMOUSID, filterKey: KEYS.USERANONYMOUSID, icon: 'filters/userid', isFilter: true }, + ] + } +]; + +export const getEventIcon = (filter) => { + let { type, key, source } = filter; + type = type || key; + if (type === KEYS.USER_COUNTRY) return 'map-marker-alt'; + if (type === KEYS.USER_BROWSER) return 'window'; + if (type === KEYS.PLATFORM) return 'window'; + + if (type === TYPES.CLICK) return 'filters/click'; + if (type === TYPES.LOCATION) return 'map-marker-alt'; + if (type === TYPES.VIEW) return 'event/view'; + if (type === TYPES.INPUT) return 'event/input'; + if (type === TYPES.CONSOLE) return 'filters/console'; + if (type === TYPES.METADATA) return 'filters/metadata'; + if (type === TYPES.ERROR) return 'filters/error'; + if (type === TYPES.USERID) return 'filters/userid'; + if (type === TYPES.USERANONYMOUSID) return 'filters/useranonymousid'; + if (type === TYPES.FETCH) return 'fetch'; + if (type === TYPES.GRAPHQL) return 'vendors/graphql'; + if (type === TYPES.STATEACTION) return 'store'; + if (type === TYPES.CUSTOM) { + if (!source) return 'Custom'; + return 'integrations/' + source; + } + return ''; +} \ No newline at end of file diff --git a/frontend/app/types/filter/index.js b/frontend/app/types/filter/index.js new file mode 100644 index 000000000..dba5512db --- /dev/null +++ b/frontend/app/types/filter/index.js @@ -0,0 +1,233 @@ +import { KEYS } from 'Types/filter/customFilter'; +import { TYPES } from 'Types/filter/event'; + +export { default } from './filter'; +export * from './filter'; + + +const filterKeys = ['is', 'isNot']; +const stringFilterKeys = ['is', 'isNot', 'contains']; +const targetFilterKeys = ['on', 'notOn']; +const signUpStatusFilterKeys = ['isSignedUp', 'notSignedUp']; +const rangeFilterKeys = ['before', 'after', 'on', 'inRange', 'notInRange', 'withInLast', 'notWithInLast']; + +const options = [ + { + key: 'is', + text: 'is', + value: 'is' + }, { + key: 'isNot', + text: 'is not', + value: 'isNot' + }, { + key: 'startsWith', + text: 'starts with', + value: 'startsWith' + }, { + key: 'endsWith', + text: 'ends with', + value: 'endsWith' + }, { + key: 'contains', + text: 'contains', + value: 'contains' + }, { + key: 'doesNotContain', + text: 'does not contain', + value: 'doesNotContain' + }, { + key: 'hasAnyValue', + text: 'has any value', + value: 'hasAnyValue' + }, { + key: 'hasNoValue', + text: 'has no value', + value: 'hasNoValue' + }, + + + { + key: 'isSignedUp', + text: 'is signed up', + value: 'isSignedUp' + }, { + key: 'notSignedUp', + text: 'not signed up', + value: 'notSignedUp' + }, + + + { + key: 'before', + text: 'before', + value: 'before' + }, { + key: 'after', + text: 'after', + value: 'after' + }, { + key: 'on', + text: 'on', + value: 'on' + }, { + key: 'notOn', + text: 'not on', + value: 'notOn' + }, { + key: 'inRage', + text: 'in rage', + value: 'inRage' + }, { + key: 'notInRage', + text: 'not in rage', + value: 'notInRage' + }, { + key: 'withinLast', + text: 'within last', + value: 'withinLast' + }, { + key: 'notWithinLast', + text: 'not within last', + value: 'notWithinLast' + }, + + { + key: 'greaterThan', + text: 'greater than', + value: 'greaterThan' + }, { + key: 'lessThan', + text: 'less than', + value: 'lessThan' + }, { + key: 'equal', + text: 'equal', + value: 'equal' + }, { + key: 'not equal', + text: 'not equal', + value: 'not equal' + }, + + + { + key: 'onSelector', + text: 'on selector', + value: 'onSelector' + }, { + key: 'onText', + text: 'on text', + value: 'onText' + }, { + key: 'onComponent', + text: 'on component', + value: 'onComponent' + }, + + + { + key: 'onAnything', + text: 'on anything', + value: 'onAnything' + } +]; + +export const filterOptions = options.filter(({key}) => filterKeys.includes(key)); +export const stringFilterOptions = options.filter(({key}) => stringFilterKeys.includes(key)); +export const targetFilterOptions = options.filter(({key}) => targetFilterKeys.includes(key)); +export const booleanOptions = [ + { key: 'true', text: 'true', value: 'true' }, + { key: 'false', text: 'false', value: 'false' }, +] + +export const defaultOperator = (filter) => { + let { type, key } = filter; + type = type || key; + + switch(type) { + // on element + case (TYPES.CLICK): + return 'on'; + + // string + case TYPES.CUSTOM: + case TYPES.CONSOLE: + case TYPES.GRAPHQL: + case TYPES.STATEACTION: + case TYPES.FETCH: + case TYPES.REVID: + case TYPES.USERID: + case TYPES.USERANONYMOUSID: + case TYPES.ERROR: + case TYPES.INPUT: + case TYPES.URL: + case TYPES.USER_BROWSER: + case TYPES.USER_DEVICE: + case TYPES.USER_OS: + case TYPES.REFERRER: + case TYPES.DURATION: + case TYPES.USER_COUNTRY: + case TYPES.METADATA: + case 'metadata': + case TYPES.CUSTOM: + case TYPES.LOCATION: + case TYPES.VIEW: + return 'is'; + + // boolean + case KEYS.SLOW_SESSION: + case KEYS.MISSING_RESOURCE: // true/false + return 'true'; + case KEYS.CLICK_RAGE: + return 'onAnything'; + default: + return 'is'; + } +} + +export const operatorOptions = (filter) => { + let { type, key } = filter; + type = type || key; + + switch (type) { + // on element + case TYPES.CLICK: + return targetFilterOptions; + + // string + case TYPES.LOCATION: + case TYPES.VIEW: + case TYPES.METADATA: + case TYPES.CUSTOM: + case TYPES.CONSOLE: + case TYPES.GRAPHQL: + case TYPES.STATEACTION: + case TYPES.FETCH: + case TYPES.USERID: + case TYPES.USERANONYMOUSID: + case TYPES.REVID: + case 'metadata': + case KEYS.ERROR: + return stringFilterOptions; + + case TYPES.INPUT: + case KEYS.URL: + case KEYS.USER_BROWSER: + case KEYS.PLATFORM: + case KEYS.USER_DEVICE: + case KEYS.USER_OS: + case KEYS.REFERRER: + case KEYS.DURATION: + case KEYS.USER_COUNTRY: + return filterOptions; + + // boolean + case KEYS.SLOW_SESSION: + return [{ key: 'true', text: 'true', value: 'true' }]; + case KEYS.MISSING_RESOURCE: // true/false + return [{ key: 'inImages', text: 'in images', value: 'true' }]; + case KEYS.CLICK_RAGE: + return [{ key: 'onAnything', text: 'on anything', value: 'true' }] + } +} \ No newline at end of file diff --git a/frontend/app/types/filter/savedFilter.js b/frontend/app/types/filter/savedFilter.js new file mode 100644 index 000000000..00f7db7fe --- /dev/null +++ b/frontend/app/types/filter/savedFilter.js @@ -0,0 +1,30 @@ +import Record from 'Types/Record'; +import Filter from './filter'; +import { List } from 'immutable'; + +export default Record({ + filterId: undefined, + projectId: undefined, + userId: undefined, + name: undefined, + filter: Filter(), + createdAt: undefined, + count: 0, + watchdogs: List() +}, { + idKey: 'filterId', + methods: { + toData() { + const js = this.toJS(); + js.filter.filters = js.filter.filters.map(f => ({...f, value: Array.isArray(f.value) ? f.value : [f.value]})) + + return js; + }, + }, + fromJS({ filter, ...rest }) { + return { + ...rest, + filter: Filter(filter) + } + } +}); \ No newline at end of file diff --git a/frontend/app/types/funnel.js b/frontend/app/types/funnel.js new file mode 100644 index 000000000..a76136460 --- /dev/null +++ b/frontend/app/types/funnel.js @@ -0,0 +1,89 @@ +import Record from 'Types/Record'; +import Filter from 'Types/filter'; +import { truncate } from 'App/utils'; +// import { validateURL, validateName } from 'App/validate'; + +const getRedableName = ({ type, value, operator }) => { + let str = ''; + switch (type) { + case "LOCATION": + str = 'Visited URL'; + break; + case "CLICK": + str = 'Clicked' + break; + case "INPUT": + str = 'Entered'; + break; + } + + return `${str} ${operator}`; +} + +export default Record({ + funnelId: undefined, + projectId: undefined, + userId: undefined, + name: '', + stages: [], + filter: Filter(), + createdAt: undefined, + sessionsCount: 0, + criticalIssuesCount: undefined, + conversions: 0, + stepsCount: 0, + isPublic: false, + affectedUsers: 0, + lostConversions: 0, + conversionImpact: 0, + firstStage: '', + lastStage: '', + totalDropDueToIssues: 0 +}, { + idKey: 'funnelId', + methods: { + validate() { + return true; + }, + toData() { + const js = this.toJS(); + return js; + } + }, + fromJS: ({ stages = [], filter, activeStages = null, ...rest }) => { + let _stages = stages.map(stage => { + stage.label = getRedableName(stage.type, stage.value); + return stage; + }); + + let firstStage = _stages.length > 0 ? _stages[0] : {}; + let lastStage = _stages ? _stages[_stages.length - 1] : {}; + + if (activeStages && activeStages.length === 2) { + firstStage = _stages[activeStages[0]]; + lastStage = _stages[activeStages[1]]; + } + + const affectedUsers = firstStage.usersCount ? firstStage.usersCount - lastStage.usersCount : 0; + const lostConversions = rest.totalDropDueToIssues; + const conversionImpact = lostConversions ? Math.round((lostConversions / firstStage.sessionsCount) * 100) : 0; + + return { + ...rest, + stages: _stages.length > 0 ? _stages.map(stage => { + if (!stage) return; + stage.label = getRedableName(stage); + return stage; + }) : [], + affectedUsers, + lostConversions, + conversionImpact, + firstStage: firstStage && firstStage.label + ' ' + truncate(firstStage.value || '', 10) || '', + lastStage: lastStage && lastStage.label + ' ' + truncate(lastStage.value || '', 10) || '', + filter: Filter(filter), + sessionsCount: lastStage && lastStage.sessionsCount, + stepsCount: stages ? stages.length : 0, + conversions: 100 - conversionImpact + } + } +}); diff --git a/frontend/app/types/funnelIssue.js b/frontend/app/types/funnelIssue.js new file mode 100644 index 000000000..becf7067d --- /dev/null +++ b/frontend/app/types/funnelIssue.js @@ -0,0 +1,78 @@ +import Record from 'Types/Record'; + +const getIconDetails = (type) => { + // const randomColor = colors[Math.floor(Math.random() * colors.length) ]; + + switch(type) { + case 'click_rage': + return { icon: 'funnel/emoji-angry-fill', color: '#CC0000' }; + case 'dead_click': + return { icon: 'funnel/emoji-dizzy-fill', color: '#9C001F' }; + case 'excessive_scrolling': + return { icon: 'funnel/mouse', color: '#D3545F' }; + case 'bad_request': + return { icon: 'funnel/patch-exclamation-fill', color: '#D70072' }; + case 'missing_resource': + return { icon: 'funnel/image-fill', color: '#B89C50' }; + case 'memory': + return { icon: 'funnel/cpu-fill', color: '#8A5A83' }; + case 'cpu': + return { icon: 'funnel/hdd-fill', color: '#8A5A83' }; + case 'slow_resource': + return { icon: 'funnel/hourglass-top', color: '#8B006D' }; + case 'slow_page_load': + return { icon: 'funnel/hourglass-top', color: '#8B006D' }; + case 'custom_event_error': + case 'custom': + return { icon: 'funnel/exclamation-circle-fill', color: '#BF6C00' }; + case 'crash': + return { icon: 'funnel/file-x', color: '#BF2D00' }; + case 'js_exception': + return { icon: 'funnel/exclamation-circle', color: '#BF2D00' }; + } + + return { + icon: 'info', + color: 'red' + } +} + +export default Record({ + issueId: undefined, + name: undefined, + title: undefined, + icon: '', + type: undefined, + contextString: undefined, + affectedUsers: 0, + conversionImpact: 0, + lostConversions: 0, + affectedSessions: 0, + unaffectedSessions: 0, + lostConversionsPer: 0, + affectedSessionsPer: 0, + unaffectedSessionsPer: 0 +}, { + idKey: 'issueId', + methods: { + validate() { + return true; + }, + }, + fromJS: ({ contextString, type, ...rest }) => { + const total = rest.lostConversions + rest.affectedSessions + rest.unaffectedSessions; + const lostConversionsPer = parseInt(rest.lostConversions * 100 / total); + const affectedSessionsPer = parseInt(rest.affectedSessions * 100 / total); + const unaffectedSessionsPer = parseInt(rest.unaffectedSessions * 100 / total); + return { + ...rest, + icon: getIconDetails(type), + type, + contextString: contextString || 'NA', + // name: type && type.replace('_', ' '), + lostConversionsPer: lostConversionsPer < 10 ? 10 : lostConversionsPer, + affectedSessionsPer: affectedSessionsPer < 10 ? 10 : affectedSessionsPer, + unaffectedSessionsPer: unaffectedSessionsPer < 10 ? 10 : unaffectedSessionsPer + } + } +}); diff --git a/frontend/app/types/index.js b/frontend/app/types/index.js new file mode 100644 index 000000000..d58b7449e --- /dev/null +++ b/frontend/app/types/index.js @@ -0,0 +1,4 @@ +import Run from './run'; + +export const Results = results => Run(results); + diff --git a/frontend/app/types/integrations/bugsnagConfig.js b/frontend/app/types/integrations/bugsnagConfig.js new file mode 100644 index 000000000..9430b0b5f --- /dev/null +++ b/frontend/app/types/integrations/bugsnagConfig.js @@ -0,0 +1,23 @@ +import Record from 'Types/Record'; + +export const tokenRE = /^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$/i; + +export default Record({ + projectId: undefined, + authorizationToken: '', + bugsnagProjectId: '', +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + return this.bugsnagProjectId !== '' && tokenRE.test(this.authorizationToken); + }, + exists() { + return this.projectId !== undefined; + } + } +}); diff --git a/frontend/app/types/integrations/cloudwatchConfig.js b/frontend/app/types/integrations/cloudwatchConfig.js new file mode 100644 index 000000000..852a31d78 --- /dev/null +++ b/frontend/app/types/integrations/cloudwatchConfig.js @@ -0,0 +1,50 @@ +import Record from 'Types/Record'; + +export const SECRET_ACCESS_KEY_LENGTH = 40; +export const ACCESS_KEY_ID_LENGTH = 20; + +export default Record({ + projectId: undefined, + awsAccessKeyId: '', + awsSecretAccessKey: '', + logGroupName: '', + region: 'us-east-1', +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + return this.awsAccessKeyId !== '' && + this.awsSecretAccessKey !== '' && + this.logGroupName !== '' && + this.region !== ''; + }, + exists() { + return this.projectId !== undefined; + } + } +}); + +export const regionLabels = { + "us-east-1": "US East (N. Virginia)", + "us-east-2": "US East (Ohio)", + "us-west-1": "US West (N. California)", + "us-west-2": "US West (Oregon)", + "ap-east-1": "Asia Pacific (Hong Kong)", + "ap-south-1": "Asia Pacific (Mumbai)", + "ap-northeast-2": "Asia Pacific (Seoul)", + "ap-southeast-1": "Asia Pacific (Singapore)", + "ap-southeast-2": "Asia Pacific (Sydney)", + "ap-northeast-1": "Asia Pacific (Tokyo)", + "ca-central-1": "Canada (Central)", + "eu-central-1": "EU (Frankfurt)", + "eu-west-1": "EU (Ireland)", + "eu-west-2": "EU (London)", + "eu-west-3": "EU (Paris)", + "eu-north-1": "EU (Stockholm)", + "me-south-1": "Middle East (Bahrain)", + "sa-east-1": "South America (São Paulo)" +}; diff --git a/frontend/app/types/integrations/datadogConfig.js b/frontend/app/types/integrations/datadogConfig.js new file mode 100644 index 000000000..555c8c4fb --- /dev/null +++ b/frontend/app/types/integrations/datadogConfig.js @@ -0,0 +1,21 @@ +import Record from 'Types/Record'; + +export default Record({ + projectId: undefined, + apiKey: '', + applicationKey: '', +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + return this.applicationKey !== '' && this.apiKey !== ''; + }, + exists() { + return this.projectId >= 0; + } + } +}); diff --git a/frontend/app/types/integrations/elasticsearchConfig.js b/frontend/app/types/integrations/elasticsearchConfig.js new file mode 100644 index 000000000..f8a22df32 --- /dev/null +++ b/frontend/app/types/integrations/elasticsearchConfig.js @@ -0,0 +1,33 @@ +import Record from 'Types/Record'; +import { validateIP } from 'App/validate' + +export const API_KEY_ID_LENGTH = 20; +export const API_KEY_LENGTH = 22; + +export default Record({ + projectId: undefined, + host: "", + apiKeyId: "", + apiKey: "", + indexes: "*log*", + port: 9200, + isValid: false, +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validateKeys() { + return this.apiKeyId.length === API_KEY_ID_LENGTH && this.apiKey.length === API_KEY_LENGTH && validateIP(this.host); + }, + validate() { + return this.host !== '' && this.apiKeyId !== '' && this.apiKey !== '' && this.indexes !== '' && !!this.port && + this.isValid && this.validateKeys(); + }, + exists() { + return this.projectId >= 0; + } + } +}); diff --git a/frontend/app/types/integrations/githubConfig.js b/frontend/app/types/integrations/githubConfig.js new file mode 100644 index 000000000..5407f17d8 --- /dev/null +++ b/frontend/app/types/integrations/githubConfig.js @@ -0,0 +1,47 @@ +import Record from 'Types/Record'; +// import { validateURL } from 'App/validate'; + +export const SECRET_ACCESS_KEY_LENGTH = 40; +export const ACCESS_KEY_ID_LENGTH = 20; + +export default Record({ + projectId: undefined, + provider: 'github', + token: '' +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + // return this.jiraProjectId !== '' && this.username !== '' && this.token !== '' && validateURL(this.url); + return this.token !== ''; + }, + exists() { + return this.projectId !== undefined; + } + } +}); + +export const regionLabels = { + "us-east-1": "US East (N. Virginia)", + "us-east-2": "US East (Ohio)", + "us-west-1": "US West (N. California)", + "us-west-2": "US West (Oregon)", + "ap-east-1": "Asia Pacific (Hong Kong)", + "ap-south-1": "Asia Pacific (Mumbai)", + "ap-northeast-2": "Asia Pacific (Seoul)", + "ap-southeast-1": "Asia Pacific (Singapore)", + "ap-southeast-2": "Asia Pacific (Sydney)", + "ap-northeast-1": "Asia Pacific (Tokyo)", + "ca-central-1": "Canada (Central)", + "eu-central-1": "EU (Frankfurt)", + "eu-west-1": "EU (Ireland)", + "eu-west-2": "EU (London)", + "eu-west-3": "EU (Paris)", + "eu-north-1": "EU (Stockholm)", + "me-south-1": "Middle East (Bahrain)", + "sa-east-1": "South America (São Paulo)" +}; diff --git a/frontend/app/types/integrations/issueTracker.js b/frontend/app/types/integrations/issueTracker.js new file mode 100644 index 000000000..ef53b01f1 --- /dev/null +++ b/frontend/app/types/integrations/issueTracker.js @@ -0,0 +1,30 @@ +import Record from 'Types/Record'; +import { validateURL } from 'App/validate'; + +export const SECRET_ACCESS_KEY_LENGTH = 40; +export const ACCESS_KEY_ID_LENGTH = 20; + +export default Record({ + username: undefined, + token: undefined, + provider: undefined, + url: undefined, + provider: 'jira' +}, { + // idKey: 'projectId', + fromJS: ({ ...config }) => ({ + ...config, + // projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validateFetchProjects() { + return this.username !== '' && this.token !== '' && validateURL(this.url); + }, + validate() { + return true; + }, + exists() { + return this.token !== undefined; + } + } +}); \ No newline at end of file diff --git a/frontend/app/types/integrations/jiraConfig.js b/frontend/app/types/integrations/jiraConfig.js new file mode 100644 index 000000000..60968745b --- /dev/null +++ b/frontend/app/types/integrations/jiraConfig.js @@ -0,0 +1,51 @@ +import Record from 'Types/Record'; +import { validateURL } from 'App/validate'; + +export const SECRET_ACCESS_KEY_LENGTH = 40; +export const ACCESS_KEY_ID_LENGTH = 20; + +export default Record({ + projectId: undefined, + username: '', + token: '', + url: '', + // jiraProjectId: '', +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validateFetchProjects() { + return this.username !== '' && this.token !== '' && validateURL(this.url); + }, + validate() { + return this.username !== '' && this.token !== '' && validateURL(this.url); + }, + exists() { + return this.projectId !== undefined; + } + } +}); + +export const regionLabels = { + "us-east-1": "US East (N. Virginia)", + "us-east-2": "US East (Ohio)", + "us-west-1": "US West (N. California)", + "us-west-2": "US West (Oregon)", + "ap-east-1": "Asia Pacific (Hong Kong)", + "ap-south-1": "Asia Pacific (Mumbai)", + "ap-northeast-2": "Asia Pacific (Seoul)", + "ap-southeast-1": "Asia Pacific (Singapore)", + "ap-southeast-2": "Asia Pacific (Sydney)", + "ap-northeast-1": "Asia Pacific (Tokyo)", + "ca-central-1": "Canada (Central)", + "eu-central-1": "EU (Frankfurt)", + "eu-west-1": "EU (Ireland)", + "eu-west-2": "EU (London)", + "eu-west-3": "EU (Paris)", + "eu-north-1": "EU (Stockholm)", + "me-south-1": "Middle East (Bahrain)", + "sa-east-1": "South America (São Paulo)" +}; diff --git a/frontend/app/types/integrations/newrelicConfig.js b/frontend/app/types/integrations/newrelicConfig.js new file mode 100644 index 000000000..cf12a927a --- /dev/null +++ b/frontend/app/types/integrations/newrelicConfig.js @@ -0,0 +1,22 @@ +import Record from 'Types/Record'; + +export default Record({ + projectId: undefined, + applicationId: '', + xQueryKey: '', + region: true +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + return this.applicationId !== '' && this.xQueryKey !== ''; + }, + exists() { + return this.projectId >= 0; + } + } +}); diff --git a/frontend/app/types/integrations/rollbarConfig.js b/frontend/app/types/integrations/rollbarConfig.js new file mode 100644 index 000000000..5bf72bd37 --- /dev/null +++ b/frontend/app/types/integrations/rollbarConfig.js @@ -0,0 +1,20 @@ +import Record from 'Types/Record'; + +export default Record({ + projectId: undefined, + accessToken: '', +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + return this.accessToken !== ''; + }, + exists() { + return this.projectId !== undefined; + } + } +}); diff --git a/frontend/app/types/integrations/sentryConfig.js b/frontend/app/types/integrations/sentryConfig.js new file mode 100644 index 000000000..727cb03d1 --- /dev/null +++ b/frontend/app/types/integrations/sentryConfig.js @@ -0,0 +1,22 @@ +import Record from 'Types/Record'; + +export default Record({ + projectId: undefined, + organizationSlug: '', + projectSlug: '', + token: '', +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + return this.organizationSlug !== '' && this.projectSlug !== '' && this.token !== ''; + }, + exists() { + return this.projectId >= 0; + } + } +}); diff --git a/frontend/app/types/integrations/slackConfig.js b/frontend/app/types/integrations/slackConfig.js new file mode 100644 index 000000000..09627103d --- /dev/null +++ b/frontend/app/types/integrations/slackConfig.js @@ -0,0 +1,27 @@ +import Record from 'Types/Record'; +import { validateURL } from 'App/validate'; + +export default Record({ + // id: undefined, + endpoint: '', + name: '', + webhookId: undefined +}, { + idKey: 'webhookId', + methods: { + validate() { + return this.endpoint !== '' && this.name != '' && validateURL(this.endpoint); + }, + exists() { + return !!this.webhookId; + }, + toData() { + const js = this.toJS(); + js.url = this.endpoint; + + delete js.key; + delete js.endpoint; + return js; + }, + } +}); diff --git a/frontend/app/types/integrations/stackdriverConfig.js b/frontend/app/types/integrations/stackdriverConfig.js new file mode 100644 index 000000000..19fb8e722 --- /dev/null +++ b/frontend/app/types/integrations/stackdriverConfig.js @@ -0,0 +1,21 @@ +import Record from 'Types/Record'; + +export default Record({ + projectId: undefined, + logName: '', + serviceAccountCredentials: '', +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + return this.serviceAccountCredentials !== '' && this.logName !== ''; + }, + exists() { + return !!this.projectId; + } + } +}); diff --git a/frontend/app/types/integrations/sumoLogicConfig.js b/frontend/app/types/integrations/sumoLogicConfig.js new file mode 100644 index 000000000..81bf35469 --- /dev/null +++ b/frontend/app/types/integrations/sumoLogicConfig.js @@ -0,0 +1,34 @@ +import Record from 'Types/Record'; + +export default Record({ + projectId: undefined, + accessId: '', + accessKey: '', + region: 'au' +}, { + idKey: 'projectId', + fromJS: ({ projectId, ...config }) => ({ + ...config, + projectId: projectId === undefined ? projectId : `${ projectId }`, + }), + methods: { + validate() { + return this.accessKey !== '' && this.accessId !== ''; + }, + exists() { + return this.projectId >= 0; + } + } +}); + +export const regionLabels = { + "au": "Asia Pacific (Sydney)", + "ca": "Canada (Central)", + "de": "EU (Frankfurt)", + "eu": "EU (Ireland)", + "fed": "US East (N. Virginia)", + "in": "Asia Pacific (Mumbai)", + "jp": "Asia Pacific (Tokyo)", + "us1": "US East (N. Virginia)", + "us2": "US West (Oregon)" +}; \ No newline at end of file diff --git a/frontend/app/types/issue/issueUser.js b/frontend/app/types/issue/issueUser.js new file mode 100644 index 000000000..ede9efeeb --- /dev/null +++ b/frontend/app/types/issue/issueUser.js @@ -0,0 +1,8 @@ +import Record from 'Types/Record'; + +export default Record({ + id: undefined, + name: undefined, + email: undefined, +}, { +}) diff --git a/frontend/app/types/issue/issuesType.js b/frontend/app/types/issue/issuesType.js new file mode 100644 index 000000000..1f0679d5a --- /dev/null +++ b/frontend/app/types/issue/issuesType.js @@ -0,0 +1,8 @@ +import Record from 'Types/Record'; + +export default Record({ + id: undefined, + name: undefined, + iconUrl: undefined +}, { +}) diff --git a/frontend/app/types/member.js b/frontend/app/types/member.js new file mode 100644 index 000000000..2cbea16d4 --- /dev/null +++ b/frontend/app/types/member.js @@ -0,0 +1,30 @@ +import Record from 'Types/Record'; +import { DateTime } from 'luxon'; +import { validateEmail, validateName } from 'App/validate'; + +export default Record({ + id: undefined, + name: '', + email: '', + createdAt: undefined, + admin: false, + superAdmin: false, +}, { + idKey: 'id', + methods: { + validate() { + return validateEmail(this.email) && validateName(this.name, { diacritics: true }); + }, + + toData() { + const js = this.toJS(); + + delete js.createdAt; + return js; + }, + }, + fromJS: ({ createdAt, ...rest }) => ({ + ...rest, + createdAt: createdAt && DateTime.fromISO(createdAt || 0), + }), +}); diff --git a/frontend/app/types/notification.js b/frontend/app/types/notification.js new file mode 100644 index 000000000..9fb10e9a6 --- /dev/null +++ b/frontend/app/types/notification.js @@ -0,0 +1,54 @@ +import { DateTime } from 'luxon'; +import { Record } from 'immutable'; +import { Map } from 'immutable'; + +const ALERT = 'alert'; + +export const LEVEL = { + ALERT, +}; + +class Notification extends Record({ + notificationId: '', + level: '', + editedAt: '', + createdAt: '', + text: '', + link: '', + viewed: undefined, + title: '', + description: '', + type: '', + filterKey: '', + options: Map({ source: '', sourceId: '', projectId: '', sourceMeta: ''}) +}) { + idKey = 'notificationId' +} + +function getFilterKey(type) { + let filterKey = '' + if (type === 'threshold' || type === 'change') + filterKey = 'alert'; + else if (type === 'scheduled') + filterKey = 'synthetic'; + + return filterKey; +} + +function fromJS(notification = {}) { + if (notification instanceof Notification) return notification; + + const createdAt = DateTime.fromMillis(notification.createdAt ? notification.createdAt : 0); + const options = notification.options ? notification.options : Map({ source: '', sourceId: '', projectId: '', sourceMeta: ''}); + + if (options.sourceMeta === 'scheduler') // TODO should be fixed in API + options.sourceMeta = 'scheduled' + + return new Notification({ + ...notification, + createdAt, + filterKey: getFilterKey(options.sourceMeta), + }); +} + +export default fromJS; diff --git a/frontend/app/types/rehydrateJob.js b/frontend/app/types/rehydrateJob.js new file mode 100644 index 000000000..a9188ba35 --- /dev/null +++ b/frontend/app/types/rehydrateJob.js @@ -0,0 +1,33 @@ +import Record from 'Types/Record'; +import { DateTime } from 'luxon'; + +export default Record({ + rehydrationId: undefined, + name: '', + startAt: '', + endAt: '', + createdAt: undefined, + state: undefined, // in_progress, fail, succeess + createdBy: undefined, + sessionsCount: undefined +}, { + idKey: 'rehydrationId', + methods: { + validate() { + return this.name !== ''; + }, + period() { + return this.startAt.toFormat('LLL dd, yyyy') + ' - ' + this.endAt.toFormat('LLL dd, yyyy'); + }, + isInProgress() { + return this.state === 'in progress'; + } + }, + fromJS: ({ startTs, endTs, createdAt, userId, ...rest }) => ({ + ...rest, + createdBy: userId, + createdAt: createdAt && DateTime.fromMillis(createdAt || 0), + endAt: endTs && DateTime.fromMillis(endTs || 0), + startAt: startTs && DateTime.fromMillis(startTs || 0), + }), +}); diff --git a/frontend/app/types/resource.js b/frontend/app/types/resource.js new file mode 100644 index 000000000..d57e01bf6 --- /dev/null +++ b/frontend/app/types/resource.js @@ -0,0 +1,23 @@ +import { Record } from 'immutable'; + +const IMAGE = "IMG"; +const REQUEST = "REQUEST"; +const PAGE = "LOCATION"; + +export const TYPES = { + IMAGE, + REQUEST, + PAGE, +}; + +const Resource = Record({ + value: "", + type: "", +}); + +function fromJS(resource = {}) { + if (resource instanceof Resource) return resource; + return new Resource(resource); +} + +export default fromJS; diff --git a/frontend/app/types/run/index.js b/frontend/app/types/run/index.js new file mode 100644 index 000000000..658043461 --- /dev/null +++ b/frontend/app/types/run/index.js @@ -0,0 +1,4 @@ +import fromJS from './run'; + +export * from './run'; +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/run/run.js b/frontend/app/types/run/run.js new file mode 100644 index 000000000..b084a25fe --- /dev/null +++ b/frontend/app/types/run/run.js @@ -0,0 +1,187 @@ +import { Record, List, Map } from 'immutable'; +import { DateTime } from 'luxon'; +import Environment from 'Types/environment'; +import stepFromJS from './step'; +import seleniumStepFromJS from './seleniumStep'; +import Resource from '../session/resource'; +import Log from '../session/log'; + +export const NOT_FETCHED = undefined; +export const QUEUED = 'queued'; +export const INITIALIZING = 'initializing'; +export const RUNNING = 'running'; +export const COMPLETED = 'completed'; +export const PASSED = 'passed'; +export const FAILED = 'failed'; +export const STOPPED = 'stopped'; +export const CRASHED = 'crashed'; +export const EXPIRED = 'expired'; + +export const STATUS = { + NOT_FETCHED, + QUEUED, + INITIALIZING, + RUNNING, + COMPLETED, + PASSED, + FAILED, + STOPPED, + CRASHED, + EXPIRED, +} + +class Run extends Record({ + runId: undefined, + testId: undefined, + name: '', + tags: List(), + environment: Environment(), + scheduled: false, + schedulerId: undefined, + browser: undefined, + sessionId: undefined, + startedAt: undefined, + url_video: undefined, + finishedAt: undefined, + steps: List(), + resources: [], + logs: [], + seleniumSteps: List(), + url_browser_logs: undefined, + url_logs: undefined, + url_selenium_project: undefined, + sourceCode: undefined, + screenshotUrl: undefined, + clientId: undefined, + state: NOT_FETCHED, + baseRunId: undefined, + lastExecutedString: undefined, + durationString: undefined, + hour: undefined, // TODO: fine API + day: undefined, + location: undefined, + deviceType: undefined, + advancedOptions: undefined, + harfile: undefined, + lighthouseHtmlFile: undefined, + resultsFile: undefined, + lighthouseJsonFile: undefined, + totalStepsCount: undefined, + auditsPerformance: Map(), + auditsAd: Map(), + transferredSize: undefined, + resourcesSize: undefined, + domBuildingTime: undefined, + domContentLoadedTime: undefined, + loadTime: undefined, + starter: undefined, + // { + // "id": '', + // "title": '', + // "description": '', + // "score": 0, + // "scoreDisplayMode": '', + // "numericValue": 0, + // "numericUnit": '', + // "displayValue": '' + // } +}) { + idKey = 'runId'; + isRunning() { + return this.state === RUNNING; + } + isQueued() { + return this.state === QUEUED; + } + isPassed() { + return this.state === PASSED; + } +} + +// eslint-disable-next-line complexity +function fromJS(run = {}) { + if (run instanceof Run) return run; + + const startedAt = run.startedAt && DateTime.fromMillis(run.startedAt); + const finishedAt = run.finishedAt && DateTime.fromMillis(run.finishedAt); + let durationString; + let lastExecutedString; + if (run.state === 'running') { + durationString = 'Running...'; + lastExecutedString = 'Now'; + } else if (startedAt && finishedAt) { + const _duration = Math.floor(finishedAt - startedAt); + if (_duration > 10000) { + const min = Math.floor(_duration / 60000); + durationString = `${ min < 1 ? 1 : min } min`; + } else { + durationString = `${ Math.floor(_duration / 1000) } secs`; + } + const diff = startedAt.diffNow([ 'days', 'hours', 'minutes', 'seconds' ]).negate(); + if (diff.days > 0) { + lastExecutedString = `${ Math.round(diff.days) } day${ diff.days > 1 ? 's' : '' } ago`; + } else if (diff.hours > 0) { + lastExecutedString = `${ Math.round(diff.hours) } hrs ago`; + } else if (diff.minutes > 0) { + lastExecutedString = `${ Math.round(diff.minutes) } min ago`; + } else { + lastExecutedString = `${ Math.round(diff.seconds) } sec ago`; + } + } + + const steps = List(run.steps).map(stepFromJS); + const seleniumSteps = List(run.seleniumSteps).map(seleniumStepFromJS); + const tags = List(run.tags); + const environment = Environment(run.environment); + + let resources = List(run.network) + .map(i => Resource({ + ...i, + // success: 1, + // time: i.timestamp, + // type: 'xhr', + // headerSize: 1200, + // timings: {}, + })); + const firstResourceTime = resources.map(r => r.time).reduce((a,b)=>Math.min(a,b), Number.MAX_SAFE_INTEGER); + resources = resources + .map(r => r.set("time", r.time - firstResourceTime)) + .sort((r1, r2) => r1.time - r2.time).toArray() + + const logs = List(run.console).map(Log); + const screenshotUrl = run.screenshot_url || + seleniumSteps.find(({ screenshotUrl }) => !!screenshotUrl, null, {}).screenshotUrl; + + const state = run.state === 'completed' ? PASSED : run.state; + const networkOverview = run.networkOverview || {}; + + return new Run({ + ...run, + startedAt, + finishedAt, + durationString, + lastExecutedString, + steps, + resources, + logs, + seleniumSteps, + tags, + environment, + screenshotUrl, + state, + deviceType: run.device || run.deviceType, + auditsPerformance: run.lighthouseJson && run.lighthouseJson.performance, + auditsAd: run.lighthouseJson && run.lighthouseJson.ad, + transferredSize: networkOverview.transferredSize, + resourcesSize: networkOverview.resourcesSize, + domBuildingTime: networkOverview.domBuildingTime, + domContentLoadedTime: networkOverview.domContentLoadedTime, + loadTime: networkOverview.loadTime, + }); +} + +Run.prototype.exists = function () { + return this.runId !== undefined; +}; + +export default fromJS; diff --git a/frontend/app/types/run/seleniumStep.js b/frontend/app/types/run/seleniumStep.js new file mode 100644 index 000000000..5178240c7 --- /dev/null +++ b/frontend/app/types/run/seleniumStep.js @@ -0,0 +1,29 @@ +import { Record, List } from 'immutable'; +import { DateTime, Duration } from 'luxon'; + +const Step = Record({ + duration: undefined, + startedAt: undefined, + label: undefined, + input: undefined, + info: undefined, + order: undefined, + screenshotUrl: undefined, + steps: List(), +}); + +function fromJS(step = {}) { + const startedAt = step.startedAt && DateTime.fromMillis(step.startedAt * 1000); + const duration = step.executionTime && Duration.fromMillis(step.executionTime); + const steps = List(step.steps).map(Step); + const screenshotUrl = step.screenshot_url; + return new Step({ + ...step, + steps, + startedAt, + duration, + screenshotUrl, + }); +}; + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/run/step.js b/frontend/app/types/run/step.js new file mode 100644 index 000000000..5358c0985 --- /dev/null +++ b/frontend/app/types/run/step.js @@ -0,0 +1,31 @@ +import { Record, List } from 'immutable'; +import { DateTime, Duration } from 'luxon'; + +const Step = Record({ + duration: undefined, + startedAt: undefined, + label: undefined, + input: undefined, + info: undefined, + order: undefined, + status: undefined, + title: undefined, + screenshotUrl: undefined, + steps: List(), +}); + +function fromJS(step = {}) { + const startedAt = step.startedAt && DateTime.fromMillis(step.startedAt); + const duration = step.executionTime && Duration.fromMillis(step.executionTime); + const steps = List(step.steps).map(Step); + const screenshotUrl = step.screenshot; + return new Step({ + ...step, + steps, + startedAt, + duration, + screenshotUrl, + }); +}; + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/schedule.js b/frontend/app/types/schedule.js new file mode 100644 index 000000000..87b38eb6d --- /dev/null +++ b/frontend/app/types/schedule.js @@ -0,0 +1,228 @@ +import { Record, List, Map } from 'immutable'; +import { DateTime } from 'luxon'; +import { + CHANNEL, + DAYS, + HOURS, + EMAIL, + SLACK, + WEBHOOK +} from 'App/constants/schedule'; +// import runFromJS from './run'; +import { validateEmail } from 'App/validate'; + +export const DEFAULT_ENV_VALUE = '_'; +const Schedule = Record({ + minutes: 30, + hour: 0, + day: -2, + testId: '', + sourceCode: '', + name: '', + nextExecutionTime: undefined, + numberOFExecutions: undefined, + schedulerId: undefined, + environmentId: DEFAULT_ENV_VALUE, + device: 'desktop', + locations: [], + + advancedOptions: false, + headers: [{}], + cookies: [{}], + basicAuth: {}, + network: 'wifi', + bypassCSP: false, + + slack: false, + slackInput: [], + webhook: false, + webhookInput: [], + email: false, + emailInput: [], + hasNotification: false, + options: Map({ message: [], device: 'desktop' }), + + extraCaps: {}, + + validateEvery() { + if (this.day > -2) return true; + return this.minutes >= 5 && this.minutes <= 1440; + }, + validateWebhookEmail() { + if (this.channel !== EMAIL) return true; + return validateEmail(this.webhookEmail); + }, + validateWebhook() { + if (this.channel !== WEBHOOK) return true; + return this.webhookId !== ''; + } +}); + +function fromJS(schedule = {}) { + if (schedule instanceof Schedule) return schedule; + const options = schedule.options || { message: [] }; + const extraCaps = options.extraCaps || { }; + + let channel = ''; + if (schedule.webhookEmail) { + channel = EMAIL; + } else if (schedule.webhookId && schedule.webhook) { + channel = schedule.webhook.type === 'slack' ? SLACK : WEBHOOK; + } + + const nextExecutionTime = schedule.nextExecutionTime ? + DateTime.fromMillis(schedule.nextExecutionTime) : undefined; + + + let { day, minutes } = schedule; + let hour; + if (day !== -2) { + const utcOffset = new Date().getTimezoneOffset(); + minutes = minutes - utcOffset + minutes = minutes >= 1440 ? (minutes - 1440) : minutes; + hour = Math.floor(minutes / 60); + } + // if (day !== -2) { + // const utcOffset = new Date().getTimezoneOffset(); + // const hourOffset = Math.floor(utcOffset / 60); + // const minuteOffset = utcOffset - 60*hourOffset; + + // minutes -= minuteOffset; + // hour -= hourOffset; + // if (day !== -1) { + // const dayOffset = Math.floor(hour/24); // +/-1 + // day = (day + dayOffset + 7) % 7; + // } + // hour = (hour + 24) % 24; + // } + + const slack = List(options.message).filter(i => i.type === 'slack'); + const email = List(options.message).filter(i => i.type === 'email'); + const webhook = List(options.message).filter(i => i.type === 'webhook'); + + const headers = extraCaps.headers ? Object.keys(extraCaps.headers).map(k => ({ name: k, value: extraCaps.headers[k] })) : [{}]; + const cookies = extraCaps.cookies ? Object.keys(extraCaps.cookies).map(k => ({ name: k, value: extraCaps.cookies[k] })) : [{}]; + + return new Schedule({ + ...schedule, + day, + minutes, + hour, + channel, + nextExecutionTime, + device: options.device, + options, + advancedOptions: !!options.extraCaps, + bypassCSP: options.bypassCSP, + network: options.network, + headers, + cookies, + basicAuth: extraCaps.basicAuth, + + slack: slack.size > 0, + slackInput: slack.map(i => parseInt(i.value)).toJS(), + + email: email.size > 0, + emailInput: email.map(i => i.value).toJS(), + + webhook: webhook.size > 0, + webhookInput: webhook.map(i => parseInt(i.value)).toJS(), + + hasNotification: !!slack || !!email || !!webhook + }); +} + +function getObjetctFromArr(arr) { + const obj = {} + for (var i = 0; i < arr.length; i++) { + const temp = arr[i]; + obj[temp.name] = temp.value + } + return obj; +} + +Schedule.prototype.toData = function toData() { + const { + name, schedulerId, environmentId, device, options, bypassCSP, network, headers, cookies, basicAuth + } = this; + + const js = this.toJS(); + options.device = device; + options.bypassCSP = bypassCSP; + options.network = network; + + options.extraCaps = { + headers: getObjetctFromArr(headers), + cookies: getObjetctFromArr(cookies), + basicAuth + }; + + if (js.slack && js.slackInput) + options.message = js.slackInput.map(i => ({ type: 'slack', value: i })) + if (js.email && js.emailInput) + options.message = options.message.concat(js.emailInput.map(i => ({ type: 'email', value: i }))) + if (js.webhook && js.webhookInput) + options.message = options.message.concat(js.webhookInput.map(i => ({ type: 'webhook', value: i }))) + + let day = this.day; + let hour = undefined; + let minutes = this.minutes; + if (day !== -2) { + const utcOffset = new Date().getTimezoneOffset(); + minutes = (this.hour * 60) + utcOffset; + // minutes += utcOffset; + minutes = minutes < 0 ? minutes + 1440 : minutes; + } + // if (day !== -2) { + // const utcOffset = new Date().getTimezoneOffset(); + // const hourOffset = Math.floor(utcOffset / 60); + // const minuteOffset = utcOffset - 60*hourOffset; + + // minutes = minuteOffset; + // hour = this.hour + hourOffset; + // if (day !== -1) { + // const dayOffset = Math.floor(hour/24); // +/-1 + // day = (day + dayOffset + 7) % 7; + // } + // hour = (hour + 24) % 24; + // } + + delete js.slack; + delete js.webhook; + delete js.email; + delete js.slackInput; + delete js.webhookInput; + delete js.emailInput; + delete js.hasNotification; + delete js.headers; + delete js.cookies; + + delete js.device; + delete js.extraCaps; + + // return { + // day, hour, name, minutes, schedulerId, environment, + // }; + return { ...js, day, hour, name, minutes, schedulerId, environmentId, options: options }; +}; + +Schedule.prototype.exists = function exists() { + return this.schedulerId !== undefined; +}; + +Schedule.prototype.valid = function validate() { + return this.validateEvery; +}; + +Schedule.prototype.getInterval = function getInterval() { + const DAY = List(DAYS).filter(item => item.value === this.day).first(); + + if (DAY.value === -2) { + return DAY.text + ' ' + this.minutes + ' Minutes'; // Every 30 minutes + } + + const HOUR = List(HOURS).filter(item => item.value === this.hour).first(); + return DAY.text + ' ' + HOUR.text; // Everyday/Sunday 2 AM; +}; + +export default fromJS; diff --git a/frontend/app/types/session/activity.js b/frontend/app/types/session/activity.js new file mode 100644 index 000000000..bb9be45fa --- /dev/null +++ b/frontend/app/types/session/activity.js @@ -0,0 +1,53 @@ +import Record from 'Types/Record'; +import { DateTime } from 'luxon'; + +const ASSIGN = 'assign'; +const MESSAGE = 'message'; +const OPEN = 'open'; +const CLOSE = 'close'; + +export const TYPES = { ASSIGN, MESSAGE, OPEN, CLOSE }; + +const Activity = Record({ + id: undefined, + type: '', + author: '', + // thread_id: undefined, + createdAt: undefined, + // assigned_to: undefined, + // user_id: undefined, + message: '', + user: '' +}) + +// const Assign = Activity.extend({ +// type: ASSIGN, +// }) + +// const Message = Activity.extend({ +// type: MESSAGE, +// }) + +// const Open = Activity.extend({ +// type: OPEN, +// }) + +// const Close = Activity.extend({ +// type: CLOSE, +// }) + +// const Open = Activity.extend({ +// type: OPEN, +// }) + +export default function(activity = {}) { + // if (activity.type === ASSIGN) return Assign(activity); + // if (activity.type === MESSAGE) return Message(activity); + // if (activity.type === OPEN) return Open(activity); + // if (activity.type === CLOSE) return Close(activity); + return Activity({ + ...activity, + createdAt: activity.createdAt ? DateTime.fromMillis(activity.createdAt, {}).toUTC() : undefined, + }); +} + diff --git a/frontend/app/types/session/assignment.js b/frontend/app/types/session/assignment.js new file mode 100644 index 000000000..0c599c85c --- /dev/null +++ b/frontend/app/types/session/assignment.js @@ -0,0 +1,47 @@ +import Record from 'Types/Record'; +import Activity from './activity'; +import { List } from 'immutable'; +import { DateTime } from 'luxon'; +import { validateName, notEmptyString } from 'App/validate'; + +export default Record({ + id: undefined, + title: '', + timestamp: undefined, + creatorId: undefined, + sessionId: undefined, + projectId: '', + siteId: undefined, + activities: List(), + closed: false, + assignee: '', + commentsCount: undefined, + issueType: '', + description: '', + iconUrl: '' +}, { + fromJS: (assignment) => ({ + ...assignment, + timestamp: assignment.createdAt ? DateTime.fromISO(assignment.createdAt) : undefined, + activities: assignment.comments ? List(assignment.comments).map(activity => { + if (assignment.users) { + activity.user = assignment.users.filter(user => user.id === activity.author).first(); + } + return Activity(activity) + }) : List() + }), + methods: { + validate: function() { + return !!this.projectId && !!this.issueType && + notEmptyString(this.title) && notEmptyString(this.description) + }, + toCreate: function() { + return { + title: this.title, + description: this.description, + assignee: this.assignee, + issueType: this.issueType + } + } + } +}) diff --git a/frontend/app/types/session/author.js b/frontend/app/types/session/author.js new file mode 100644 index 000000000..12edc3c1e --- /dev/null +++ b/frontend/app/types/session/author.js @@ -0,0 +1,11 @@ +import Record from 'Types/Record'; + +export default Record({ + id: undefined, + avatarUrls: undefined, + name: undefined, +}, { + fromJS: author => ({ + ...author, + }) +}) diff --git a/frontend/app/types/session/customField.js b/frontend/app/types/session/customField.js new file mode 100644 index 000000000..79f26b914 --- /dev/null +++ b/frontend/app/types/session/customField.js @@ -0,0 +1,5 @@ +import CustomField from 'Types/customField'; + +export default CustomField.extend({ + value: undefined, +}); \ No newline at end of file diff --git a/frontend/app/types/session/error.js b/frontend/app/types/session/error.js new file mode 100644 index 000000000..9b0fcb278 --- /dev/null +++ b/frontend/app/types/session/error.js @@ -0,0 +1,32 @@ +import Record from 'Types/Record'; + + +function getStck0InfoString(stack) { + const stack0 = stack[0]; + if (!stack0) return ""; + let s = stack0.function || ""; + if (stack0.url) { + s += ` (${stack0.url})`; + } + return s; +} + + +export default Record({ + sessionId: undefined, + messageId: undefined, + timestamp: undefined, + errorId: undefined, + projectId: undefined, + source: undefined, + name: undefined, + message: undefined, + time: undefined, + function: '?', +}, { + fromJS: ({ stack, ...rest }) => ({ + ...rest, + stack0InfoString: getStck0InfoString(stack || []), + function: (stack && stack[0] && stack[0].function) || '?', + }), +}); diff --git a/frontend/app/types/session/errorStack.js b/frontend/app/types/session/errorStack.js new file mode 100644 index 000000000..b92610229 --- /dev/null +++ b/frontend/app/types/session/errorStack.js @@ -0,0 +1,13 @@ +import Record from 'Types/Record'; + +export default Record({ + // url: undefined, + absPath: undefined, + filename: undefined, + // args: [], + function: undefined, + lineNo: undefined, + colNo: undefined, + offset: 0, + context: undefined +}); diff --git a/frontend/app/types/session/event.js b/frontend/app/types/session/event.js new file mode 100644 index 000000000..b64744bcb --- /dev/null +++ b/frontend/app/types/session/event.js @@ -0,0 +1,90 @@ +import Record from 'Types/Record'; +import Target from 'Types/target'; + +const CONSOLE = 'CONSOLE'; +const CLICK = 'CLICK'; +const INPUT = 'INPUT'; +const LOCATION = 'LOCATION'; +const CUSTOM = 'CUSTOM'; +const CLICKRAGE = 'CLICKRAGE'; +const IOS_VIEW = 'VIEW'; +export const TYPES = { CONSOLE, CLICK, INPUT, LOCATION, CUSTOM, CLICKRAGE, IOS_VIEW}; + + +const Event = Record({ + time: 0, + label: '' +}, { + fromJS: event => ({ + ...event, + target: Target(event.target || { path: event.targetPath }), + }) +}) + +const Console = Event.extend({ + type: CONSOLE, + subtype: '', // level ??? + value: '', +},{ + name: 'Console' +}) + +const Click = Event.extend({ + type: CLICK, + targetContent: '', + target: Target(), + count: undefined +}, { + name: 'Click' +}); + +const Input = Event.extend({ + type: INPUT, + target: Target(), + value: '', +},{ + name: 'Input' +}); + +const View = Event.extend({ + type: IOS_VIEW, + name: '', +},{ + name: 'View' +}) + +const Location = Event.extend({ + type: LOCATION, + url: '', + pageLoad: false, + fcpTime: undefined, + //fpTime: undefined, + loadTime: undefined, + domContentLoadedTime: undefined, + domBuildingTime: undefined, + speedIndex: undefined, + visuallyComplete: undefined, + timeToInteractive: undefined, + referrer: '', +}, { + fromJS: event => ({ + ...event, + //fpTime: event.firstPaintTime, + fcpTime: event.firstContentfulPaintTime || event.firstPaintTime, + }), + name: 'Location' +}); + +const TYPE_CONSTRUCTOR_MAP = { + [CONSOLE]: Console, + [CLICK]: Click, + [INPUT]: Input, + [LOCATION]: Location, + [CLICKRAGE]: Click, + [IOS_VIEW]: View, +} + +export default function(event = {}) { + return (TYPE_CONSTRUCTOR_MAP[event.type] || Event)(event); +} + diff --git a/frontend/app/types/session/index.js b/frontend/app/types/session/index.js new file mode 100644 index 000000000..976623abf --- /dev/null +++ b/frontend/app/types/session/index.js @@ -0,0 +1 @@ +export { default } from './session'; \ No newline at end of file diff --git a/frontend/app/types/session/log.js b/frontend/app/types/session/log.js new file mode 100644 index 000000000..4c24f9141 --- /dev/null +++ b/frontend/app/types/session/log.js @@ -0,0 +1,38 @@ +import Record from 'Types/Record'; + +export const INFO = 'info'; +export const LOG = 'log'; +export const WARNING = 'warning'; +export const WARN = 'warn'; +export const ERROR = 'error'; +export const EXCEPTION = 'exception'; +export const LEVEL = { + INFO, + LOG, + WARNING, + WARN, + ERROR, + EXCEPTION, +} + +export function isRed(log) { + return log.level === EXCEPTION || log.level === ERROR; +} + +export default Record({ + level: '', + value: '', + time: undefined, + index: undefined, +}, { + methods: { + isRed() { + return isRed(this); + }, + isYellow() { + return this.level === WARNING; + } + } +}); + + diff --git a/frontend/app/types/session/profile.js b/frontend/app/types/session/profile.js new file mode 100644 index 000000000..98b9bc345 --- /dev/null +++ b/frontend/app/types/session/profile.js @@ -0,0 +1,20 @@ +import { List } from 'immutable'; +import Record from 'Types/Record'; + +export default Record({ + name: '', + args: List(), + result: undefined, + time: undefined, + index: undefined, + duration: undefined, +}, { + fromJS: ({ start_time, end_time, args, ...profile }) => ({ + ...profile, + args: List(args), + time: Math.round(start_time), + duration: Math.round(end_time - start_time || 0), + }), +}); + + diff --git a/frontend/app/types/session/reduxAction.js b/frontend/app/types/session/reduxAction.js new file mode 100644 index 000000000..e03ab9ce9 --- /dev/null +++ b/frontend/app/types/session/reduxAction.js @@ -0,0 +1,12 @@ +import Record from 'Types/Record'; + +export default Record({ + time: undefined, + index: undefined, + action: {}, + state: undefined, + diff: [], + duration: undefined, +}); + + diff --git a/frontend/app/types/session/resource.js b/frontend/app/types/session/resource.js new file mode 100644 index 000000000..c0cd7b83f --- /dev/null +++ b/frontend/app/types/session/resource.js @@ -0,0 +1,119 @@ +import { List } from 'immutable'; +import Record from 'Types/Record'; +import { getResourceName } from 'App/utils'; +// import { List } from 'semantic-ui-react'; + +const XHR = 'xhr'; +const JS = 'script'; +const CSS = 'css'; +const IMG = 'img'; +const MEDIA = 'media'; +const OTHER = 'other'; +// +const FETCH = 'tracked_fetch'; +// +// const IMG_EXTENTIONS = [ "png", "gif", "jpg", "jpeg", "svg" ]; +// const MEDIA_EXTENTIONS = [ 'mp4', 'mkv', 'ogg', 'webm', 'avi', 'mp3' ]; +// +// function getResourceType(type, initiator, url) { +// if (type === 'xmlhttprequest') return XHR; // bad? +// if (type !== undefined) return type; +// if (initiator === 'xmlhttprequest' || initiator === 'fetch') return XHR; +// if (initiator === 'img') return IMG; +// const pathnameSplit = new URL(url).pathname.split('.'); +// if (pathnameSplit.length > 1) { +// const extention = pathnameSplit.pop(); +// if (extention === 'css') return CSS; +// if (extention === 'js') return JS; +// if (IMG_EXTENTIONS.includes(extention)) return IMG +// if (MEDIA_EXTENTIONS.includes(extention)) return MEDIA; +// } +// return OTHER; +// } + +const TYPES_MAP = { + "stylesheet": CSS, + "fetch": XHR, +} + +function getResourceStatus(status, success) { + if (status !== undefined) return status; + if (typeof success === 'boolean' || typeof success === 'number') { + return !!success + ? '2xx-3xx' + : '4xx-5xx'; + } + return '2xx-3xx'; +} + +function getResourceSuccess(success, status) { + if (success !== undefined) return !!success; + if (status !== undefined) return status >= 200 && status < 300; +} + +export const TYPES = { + XHR, + JS, + CSS, + IMG, + MEDIA, + OTHER, + FETCH, +} + +const YELLOW_BOUND = 10; +const RED_BOUND = 80; + +export function isRed(r) { + return !r.success || r.score >= RED_BOUND; +} +export function isYellow(r) { + return r.score < RED_BOUND && r.score >= YELLOW_BOUND; +} + +export default Record({ + type: OTHER, + url: '', + name: '', + status: '2xx-3xx', + duration: 0, + index: undefined, + time: undefined, + ttfb: 0, + timewidth: 0, + success: true, + score: 0, + // initiator: "other", + // pagePath: "", + method: '', + payload:'', + response: '', + headerSize: 0, + encodedBodySize: 0, + decodedBodySize: 0, + responseBodySize: 0, + timings: List(), +}, { + fromJS: ({ responseBody, response, type, initiator, status, success, time, datetime, timestamp, timings, ...resource }) => ({ + ...resource, + type: TYPES_MAP[type] || type, + name: getResourceName(resource.url), + status: getResourceStatus(status, success), + success: getResourceSuccess(success, status), + time: typeof time === 'number' ? time : datetime || timestamp, + response: responseBody || response, + ttfb: timings && timings.ttfb, + timewidth: timings && timings.timewidth, + timings, + }), + name: 'Resource', + methods: { + isRed() { + return isRed(this); + }, + isYellow() { + return isYellow(this); + } + } +}); + diff --git a/frontend/app/types/session/session.js b/frontend/app/types/session/session.js new file mode 100644 index 000000000..daa2f4ae0 --- /dev/null +++ b/frontend/app/types/session/session.js @@ -0,0 +1,134 @@ +import Record from 'Types/Record'; +import { List, Map } from 'immutable'; +import { DateTime, Duration } from 'luxon'; +import SessionEvent, { TYPES } from './event'; +import Log from './log'; +import StackEvent from './stackEvent'; +import Resource from './resource'; +import CustomField from './customField'; +import SessionError from './error'; + + +const SOURCE_JS = 'js_exception'; + +const HASH_MOD = 1610612741; +const HASH_P = 53; +function hashString(s: string): number { + let mul = 1; + let hash = 0; + for (let i = 0; i < s.length; i++) { + hash = (hash + s.charCodeAt(i) * mul) % HASH_MOD; + mul = (mul*HASH_P) % HASH_MOD; + } + return hash; +} + +export default Record({ + sessionId: '', + siteId: '', + live: false, + startedAt: 0, + duration: 0, + events: List(), + logs: List(), + stackEvents: List(), + resources: List(), + missedResources: List(), + metadata: List(), + favorite: false, + filterId: '', + messagesUrl: '', + mobsUrl: '', + userBrowser: '', + userBrowserVersion: '?', + userCountry: '', + userDevice: '', + userDeviceType: '', + isMobile: false, + userOs: '', + userOsVersion: '', + userId: '', + userAnonymousId: '', + userUuid: undefined, + userDisplayName: "", + userNumericHash: 0, + viewed: false, + consoleLogCount: '?', + eventsCount: '?', + pagesCount: '?', + clickRage: undefined, + clickRageTime: undefined, + resourcesScore: 0, + consoleError: undefined, + resourceError: undefined, + returningLocation: undefined, + returningLocationTime: undefined, + errorsCount: 0, + watchdogs: [], + issueTypes: [], + userDeviceHeapSize: 0, + userDeviceMemorySize: 0, + errors: List(), + crashes: [], + socket: null, + isIOS: false, +}, { + fromJS:({ + startTs=0, + backendErrors=0, + consoleErrors=0, + projectId, + errors, + stackEvents = [], + ...session + }) => { + const duration = Duration.fromMillis(session.duration < 1000 ? 1000 : session.duration); + const startedAt = +startTs; + + const userDevice = session.userDevice || session.userDeviceType || 'Other'; + const userDeviceType = session.userDeviceType || 'other'; + const isMobile = [ 'console', 'mobile', 'tablet' ].includes(userDeviceType) + + const events = List(session.events) + .map(e => SessionEvent({ ...e, time: e.timestamp - startedAt })) + .filter(({ type }) => type !== TYPES.CONSOLE); + + let resources = List(session.resources) + .map(Resource); + // this code shoud die. + const firstResourceTime = resources.map(r => r.time).reduce((a,b)=>Math.min(a,b), Number.MAX_SAFE_INTEGER); + resources = resources + .map(r => r.set("time", r.time - firstResourceTime)) + .sort((r1, r2) => r1.time - r2.time); + const missedResources = resources.filter(({ success }) => !success); + const logs = List(session.logs).map(Log); + + const stackEventsList = List(stackEvents) + .concat(List(session.userEvents)) + .sortBy(se => se.timestamp) + .map(se => StackEvent({ ...se, time: se.timestamp - startedAt })); + const exceptions = List(errors) + .map(SessionError) + return { + ...session, + isIOS: session.platform === "ios", + watchdogs: session.watchdogs || [], + errors: exceptions, + siteId: projectId, + events, + logs, + stackEvents: stackEventsList, + resources, + missedResources, + userDevice, + userDeviceType, + isMobile, + startedAt, + duration, + userNumericHash: hashString(session.userId || session.userAnonymousId || session.userUuid || ""), + userDisplayName: session.userId || session.userAnonymousId || 'Anonymous User', + firstResourceTime, + }; + }, + idKey: "sessionId", +}); diff --git a/frontend/app/types/session/stackEvent.js b/frontend/app/types/session/stackEvent.js new file mode 100644 index 000000000..762407916 --- /dev/null +++ b/frontend/app/types/session/stackEvent.js @@ -0,0 +1,59 @@ +import Record from 'Types/Record'; + +export const OPENREPLAY = 'openreplay'; +export const SENTRY = 'sentry'; +export const DATADOG = 'datadog'; +export const STACKDRIVER = 'stackdriver'; +export const ROLLBAR = 'rollbar'; +export const NEWRELIC = 'newrelic'; +export const BUGSNAG = 'bugsnag'; +export const CLOUDWATCH = 'cloudwatch'; +export const ELASTICSEARCH = 'elasticsearch'; +export const SUMOLOGIC = 'sumologic'; + +export const typeList = [ OPENREPLAY, SENTRY, DATADOG, STACKDRIVER, ROLLBAR, BUGSNAG, CLOUDWATCH, ELASTICSEARCH, SUMOLOGIC ]; + +export function isRed(event) { + if (!event.payload) return false; + switch(event.source) { + case SENTRY: + return event.payload['event.type'] === 'error'; + case DATADOG: + return true; + case STACKDRIVER: + return false; + case ROLLBAR: + return true; + case NEWRELIC: + return true; + case BUGSNAG: + return true; + case CLOUDWATCH: + return true; + case SUMOLOGIC: + return false; + default: + return event.level==='error'; + } +} + +export default Record({ + time: undefined, + index: undefined, + name: '', + message: "", + payload: null, + source: null, + level: "", +}, { + fromJS: ue => ({ + ...ue, + source: ue.source || OPENREPLAY, + }), + methods: { + isRed() { + return isRed(this); + } + } +}); + diff --git a/frontend/app/types/site/gdpr.js b/frontend/app/types/site/gdpr.js new file mode 100644 index 000000000..9b6c58fd4 --- /dev/null +++ b/frontend/app/types/site/gdpr.js @@ -0,0 +1,19 @@ +import Record from 'Types/Record'; + +export default Record({ + id: undefined, + maskEmails: false, + maskNumbers: false, + defaultInputMode: 'plain', + sampleRate: 0, +}, { + idKey: 'id', + methods: { + toData() { + const js = this.toJS(); + + delete js.key; + return js; + }, + }, +}); diff --git a/frontend/app/types/site/index.js b/frontend/app/types/site/index.js new file mode 100644 index 000000000..fab20bc7a --- /dev/null +++ b/frontend/app/types/site/index.js @@ -0,0 +1,2 @@ +export { default } from './site'; +export * from './site'; \ No newline at end of file diff --git a/frontend/app/types/site/site.js b/frontend/app/types/site/site.js new file mode 100644 index 000000000..5a0fee5bd --- /dev/null +++ b/frontend/app/types/site/site.js @@ -0,0 +1,46 @@ +import Record from 'Types/Record'; +import GDPR from './gdpr'; + +export const RED = 'red'; +export const YELLOW = 'yellow'; +export const GREEN = 'green'; + +export const STATUS_COLOR_MAP = { + [ RED ]: 'red', + [ YELLOW ]: 'orange', + [ GREEN ]: 'green', +} + +export default Record({ + id: undefined, + name: '', + host: '', + status: RED, + lastRecordedSessionAt: undefined, + gdpr: GDPR(), + recorded: undefined, + stackIntegrations: false, + projectKey: undefined, +}, { + idKey: 'id', + methods: { + validate() { + return this.host.length > 0; + }, + + toData() { + const js = this.toJS(); + + delete js.key; + delete js.gdpr; + return js; + }, + }, + fromJS: ({ gdpr, projectId, name, ...rest }) => ({ + ...rest, + host: name, + name: name, + id: projectId === undefined ? undefined : `${ projectId }`, //?!?!?!?!? + gdpr: GDPR(gdpr), + }) +}); diff --git a/frontend/app/types/step.js b/frontend/app/types/step.js new file mode 100644 index 000000000..438b403d8 --- /dev/null +++ b/frontend/app/types/step.js @@ -0,0 +1,152 @@ +import { Record, List, Set, isImmutable } from 'immutable'; +import { TYPES as EVENT_TYPES } from 'Types/session/event'; + +export const CUSTOM = 'custom'; +export const CLICK = 'click'; +export const INPUT = 'input'; +export const NAVIGATE = 'navigate'; +export const TEST = 'test'; + +export const TYPES = { + CLICK, + INPUT, + CUSTOM, + NAVIGATE, + TEST, +}; + + +const Step = defaultValues => class extends Record({ + key: undefined, + name: '', + imported: false, + isDisabled: false, + importTestId: undefined, + ...defaultValues, +}) { + hasTarget() { + return this.type === CLICK || this.type === INPUT; + } + + isTest() { + return this.type === TEST; + } + + getEventType() { + switch (this.type) { + case INPUT: + return EVENT_TYPES.INPUT; + case CLICK: + return EVENT_TYPES.CLICK; + case NAVIGATE: + return EVENT_TYPES.LOCATION; + default: + return null; + } + } + + validate() { + const selectorsOK = this.selectors && this.selectors.size > 0; + const valueOK = this.value && this.value.trim().length > 0; + switch (this.type) { + case INPUT: + return selectorsOK; + case CLICK: + return selectorsOK; + case NAVIGATE: + return valueOK; + case CUSTOM: + // if (this.name.length === 0) return false; + /* if (window.JSHINT) { + window.JSHINT(this.code, { esversion: 6 }); + const noErrors = window.JSHINT.errors.every(({ code }) => code && code.startsWith('W')); + return noErrors; + } */ + return this.code && this.code.length > 0; + default: + return true; + } + } + + toData() { + const { + value, + ...step + } = this.toJS(); + delete step.key; + return { + values: value && [ value ], + ...step, + }; + } +}; + +const Custom = Step({ + type: CUSTOM, + code: '', + framework: 'any', + template: '', +}); + +const Click = Step({ + type: CLICK, + selectors: List(), + customSelector: true, +}); + +const Input = Step({ + type: INPUT, + selectors: List(), + value: '', + customSelector: true, +}); + +const Navigate = Step({ + type: NAVIGATE, + value: '', +}); + +const TestAsStep = Step({ + type: TEST, + testId: '', + name: '', + stepsCount: '', + steps: List(), +}); + +const EmptyStep = Step(); + +let uniqueKey = 0xff; +function nextKey() { + uniqueKey += 1; + return `${ uniqueKey }`; +} + +function fromJS(initStep = {}) { + // TODO: more clear + if (initStep.importTestId) return new TestAsStep(initStep).set('steps', List(initStep.steps ? initStep.steps : initStep.test.steps).map(fromJS)); + // todo: ? + if (isImmutable(initStep)) return initStep.set('key', nextKey()); + + const values = initStep.values && initStep.values.length > 0 && initStep.values[ 0 ]; + + // bad code + const step = { + ...initStep, + selectors: Set(initStep.selectors).toList(), // to List not nrcrssary. TODO: check + value: initStep.value ? [initStep.value] : values, + key: nextKey(), + isDisabled: initStep.disabled + }; + // bad code + + if (step.type === CUSTOM) return new Custom(step); + if (step.type === CLICK) return new Click(step); + if (step.type === INPUT) return new Input(step); + if (step.type === NAVIGATE) return new Navigate(step); + + return new EmptyStep(); + // throw new Error(`Unknown step type: ${step.type}`); +} + +export default fromJS; diff --git a/frontend/app/types/synthetics/domBuildingTime.js b/frontend/app/types/synthetics/domBuildingTime.js new file mode 100644 index 000000000..258902f60 --- /dev/null +++ b/frontend/app/types/synthetics/domBuildingTime.js @@ -0,0 +1,14 @@ +import { Record } from 'immutable'; + +const DomBuildingTime = Record({ + avg: undefined, + chart: [], +}); + + +function fromJS(data = {}) { + if (data instanceof DomBuildingTime) return data; + return new DomBuildingTime(data); +} + +export default fromJS; \ No newline at end of file diff --git a/frontend/app/types/synthetics/index.js b/frontend/app/types/synthetics/index.js new file mode 100644 index 000000000..1c693ae88 --- /dev/null +++ b/frontend/app/types/synthetics/index.js @@ -0,0 +1,32 @@ +import { Map, List } from 'immutable'; +import Session from 'Types/session'; +import { camelCased } from 'App/utils'; + +import { getChartFormatter } from './helper'; +import DomBuildingTime from './domBuildingTime'; +import ResourceLoadingTime from './resourceLoadingTime'; + +export const WIDGET_LIST = [ + { + key: "resourcesLoadingTime", + name: "Resource Fetch Time", + description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.', + thumb: 'na.png', + type: 'resources', + dataWrapper: (list, period) => DomBuildingTime(list) + .update("chart", getChartFormatter(period)) + }, +]; + +export const WIDGET_KEYS = WIDGET_LIST.map(({ key }) => key); + +const WIDGET_MAP = {}; +WIDGET_LIST.forEach(w => { WIDGET_MAP[ w.key ] = w; }); + +const OVERVIEW_WIDGET_MAP = {}; +WIDGET_LIST.filter(w => w.type === 'overview').forEach(w => { OVERVIEW_WIDGET_MAP[ w.key ] = w; }); + +export { + WIDGET_MAP, + OVERVIEW_WIDGET_MAP +}; diff --git a/frontend/app/types/target.js b/frontend/app/types/target.js new file mode 100644 index 000000000..3817f028c --- /dev/null +++ b/frontend/app/types/target.js @@ -0,0 +1,8 @@ +import Record from './Record'; + +const Target = Record({ + path: '', + label: null, +}); + +export default Target; diff --git a/frontend/app/types/targetCustom.js b/frontend/app/types/targetCustom.js new file mode 100644 index 000000000..795710580 --- /dev/null +++ b/frontend/app/types/targetCustom.js @@ -0,0 +1,18 @@ +import Record from 'Types/Record'; + +const TargetCustom = Record({ + targetId: '', + label: '', + path: null, + isCustom: true, + location: '', +}, { + fromJS: (target) => ({ + ...target, + label: target.label || target.targetLabel, + path: target.path || target.targetSelector, + }), + idKey: 'targetId', +}); + +export default TargetCustom; \ No newline at end of file diff --git a/frontend/app/types/template.js b/frontend/app/types/template.js new file mode 100644 index 000000000..9a05e0fa4 --- /dev/null +++ b/frontend/app/types/template.js @@ -0,0 +1,17 @@ +import Record from 'Types/Record'; + +export default Record({ + templateId: undefined, + name: '', + code: '', + framework: 'selenium', // TODO extend + custom: false, + tenantId: undefined, +}, { + idKey: 'templateId', + methods: { + validate() { + return this.code !== ''; + }, + }, +}); diff --git a/frontend/app/types/variable.js b/frontend/app/types/variable.js new file mode 100644 index 000000000..72343c3a4 --- /dev/null +++ b/frontend/app/types/variable.js @@ -0,0 +1,16 @@ +import Record from 'Types/Record'; + +const varRegExp = new RegExp('^[A-Za-z_][A-Za-z0-9_]*$'); + +export default Record({ + variableId: undefined, + value: '', + name: '', +}, { + idKey: 'variableId', + methods: { + validate() { + return varRegExp.test(this.name) && this.value !== ''; + }, + }, +}); diff --git a/frontend/app/types/watchdog.js b/frontend/app/types/watchdog.js new file mode 100644 index 000000000..76d874c64 --- /dev/null +++ b/frontend/app/types/watchdog.js @@ -0,0 +1,100 @@ +import Record from 'Types/Record'; +import { Map } from 'immutable'; + + +const + ERRORS = 'errors', + BAD_REQUEST = 'bad_request', + MISSING_IMAGE = 'missing_image', + SLOW_SESSION = 'slow_session', + HIGH_ENGAGEMENT = 'high_engagement', + CLICKRAGE = 'clickrage', + PERFORMANCE_ISSUES = 'performance_issues'; + +const WATCHDOG_TYPES = [ + ERRORS, + BAD_REQUEST, + MISSING_IMAGE, + SLOW_SESSION, + HIGH_ENGAGEMENT, + CLICKRAGE, + PERFORMANCE_ISSUES, +] + +export const names = { + // 'all' : { label: 'All', icon: 'all' }, + 'js_exception' : { label: 'JS Exceptions', icon: 'funnel/exclamation-circle' }, + 'bad_request': { label: 'Bad Request', icon: 'funnel/patch-exclamation-fill' }, + 'missing_resource': { label: 'Missing Resources', icon: 'funnel/image-fill' }, + 'memory': { label: 'Memory', icon: 'funnel/cpu-fill' }, + 'click_rage': { label: 'Click Rage', icon: 'funnel/emoji-angry-fill' }, + 'slow_page_load': { label: 'Slow Page Load', icon: 'funnel/hourglass-top' }, + 'crash': { label: 'Crashes', icon: 'funnel/file-x' }, + 'cpu': { label: 'CPU', icon: 'funnel/hdd-fill' }, + 'dead_click': { label: 'Dead Click', icon: 'funnel/emoji-dizzy-fill' }, + 'custom': { label: 'Custom', icon: 'funnel/exclamation-circle-fill' }, + + // 'errors' : { label: 'Errors', icon: 'console/error' }, + // 'missing_image': { label: 'Missing Images', icon: 'image' }, + // 'slow_session': { label: 'Slow Sessions', icon: 'turtle' }, + // 'high_engagement': { label: 'High Engagements', icon: 'high-engagement' }, + // 'performance_issues': { label: 'Mem/CPU Issues', icon: 'tachometer-slowest' }, + // 'default': { label: 'Default', icon: 'window-alt' }, +} + +const CONJUGATED_ISSUE_TYPES = { + 'errors': [ 'crash' ], + 'bad_request': [ 'bad_request'], + 'missing_image': [ 'missing_resource' ], + 'slow_session': [ 'slow_page_load', 'slow_resource', 'ml_slow_resources' ], + 'high_engagement': [], + 'clickrage': [ 'click_rage', 'ml_click_rage' ], // 'dead_click', 'excessive_scrolling', 'ml_dead_click', 'ml_mouse_thrashing', 'ml_excessive_scrolling' + 'crashes': [ 'crash' ], + 'performance_issues': [ 'memory', 'cpu', 'slow_resource', 'ml_cpu', 'ml_memory', 'ml_slow_resources' ], +} + +export function getSessionWatchdogTypes(session) { + if (!session.issueTypes) return session.errorsCount > 0 ? [ERRORS] : []; + return WATCHDOG_TYPES.filter(wt => wt=== ERRORS && session.errorsCount> 0 || CONJUGATED_ISSUE_TYPES[wt].some(it => session.issueTypes.includes(it))); +} + + +export default Record({ + watchdogId: undefined, + name: '', + type: '', + icon: 'info', + ruleId: '', + ruleConfig: {}, + enabled: undefined, + projectId: undefined, + payload: Map({ captureAll: false, rate: 0 }), + visible: undefined +}, { + idKey: 'watchdogId', + methods: { + validate() { + return this.name !== '' && this.ruleId !== ''; + }, + exists() { + return this.id !== undefined; + }, + fits(session) { + if (session.issueTypes && session.issueTypes.includes(this.type)) { + return true; + } + if (session.errorsCount > 0 && this.type===ERRORS) { + return true; + } + if (!!session.issueTypes && !!CONJUGATED_ISSUE_TYPES[this.type]) { + return session.issueTypes.some(it => CONJUGATED_ISSUE_TYPES[this.type].includes(it)); + } + return false; + } + }, + fromJS: (item) => ({ + ...item, + name: item.name, + icon: names[item.type] ? names[item.type].icon : 'turtle' + }), +}); diff --git a/frontend/app/types/webhook.js b/frontend/app/types/webhook.js new file mode 100644 index 000000000..5024411f4 --- /dev/null +++ b/frontend/app/types/webhook.js @@ -0,0 +1,22 @@ +import Record from 'Types/Record'; +import { validateName, validateURL } from 'App/validate'; + +export default Record({ + webhookId: undefined, + type: undefined, + name: '', + endpoint: '', + authHeader: '', +}, { + idKey: 'webhookId', + methods: { + validate() { + return !!this.name && validateName(this.name) && !!this.endpoint && validateURL(this.endpoint); + }, + toData() { + const js = this.toJS(); + delete js.key; + return js; + }, + }, +}); diff --git a/frontend/app/utils.js b/frontend/app/utils.js new file mode 100644 index 000000000..45a8c3356 --- /dev/null +++ b/frontend/app/utils.js @@ -0,0 +1,206 @@ +import JSBI from 'jsbi'; +import { scale } from "d3"; + +export function debounce(callback, wait, context = this) { + let timeout = null; + let callbackArgs = null; + + const later = () => callback.apply(context, callbackArgs); + + return function (...args) { + callbackArgs = args; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} + +export function getResourceName(url = '') { + return url.split('/').filter(s => s!== '').pop(); +} + +/* eslint-disable no-mixed-operators */ +export function randomInt(a, b) { + const min = (b ? a : 0) - 0.5; + const max = b || a || Number.MAX_SAFE_INTEGER; + const rand = min - 0.5 + (Math.random() * (max - min + 1)); + return Math.round(rand); +} + +export const toUnderscore = s => s.split(/(?=[A-Z])/).join('_').toLowerCase(); + +export const getUniqueFilter = keys => + (item, i, list) => + !list.some((item2, j) => j < i && + keys.every(key => item[ key ] === item2[ key ] && item[ key ] !== undefined)); + +export const numberWithCommas = (x) => x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + +export const numberCompact = (x) => x >= 1000 ? x / 1000 + 'k': x; + +export const cutURL = (url, prefix = '.../') => `${ prefix + url.split('/').slice(3).join('/') }`; + +export const escapeRegExp = string => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + +export function getRE(string, options) { + let re; + try { + re = new RegExp(string, options); + } catch(e){ + re = new RegExp(escapeRegExp(string), options); + } + return re; +} + +export const getStateColor = (state) => { + switch (state) { + case 'passed': + return 'green'; + case 'failed': + return 'red'; + default: + return 'gray-medium'; + } +}; + +export const convertNumberRange = (oldMax, oldMin, newMin, newMax, currentValue) => { + let newValue; + let newRange; + const oldRange = (oldMax - oldMin); + + if (oldRange === 0) { + newValue = newMin; + } else { + newRange = (newMax - newMin); + newValue = (((currentValue - oldMin) * newRange) / oldRange) + newMin; + } + return newValue; +}; + +export const prorata = ({ + parts, elements, startDivisorFn, divisorFn, +}) => { + const byElement = Object.entries(elements) + .reduce((ack, [ element, numElements ]) => ({ + ...ack, + [ element ]: { parts: 0, elements: numElements, divisor: startDivisorFn(numElements) }, + }), {}); + + while (parts > 0) { + const element = Object.entries(byElement).reduce((a, [ k, v ]) => (a.divisor > v.divisor ? a : v), { divisor: 0 }); + // eslint-disable-next-line no-plusplus + element.parts++; + element.divisor = divisorFn(element.elements, element.parts); + // eslint-disable-next-line no-plusplus + parts--; + } + return Object.entries(byElement).reduce((a, [ k, v ]) => ({ ...a, [ k ]: v.parts }), {}); +}; + +export const titleCase = (str) => { + str = str.toLowerCase(); + str = str.split('_'); + for (var i = 0; i < str.length; i++) { + str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); + } + + return str.join(' '); +} + +export const confirm = (message, callback) => { + const sure = window.confirm(message); + if (!sure) return; + callback() +} + +const KB = 1<<10; +const MB = KB<<10; +const GB = MB<<10; +export function formatBytes(bt: number): string { + if (bt > GB) { + return `${ Math.trunc(bt/GB*1e2)/1e2 }GB`; + } + if (bt > MB) { + return `${ Math.trunc(bt/MB*1e2)/1e2 }MB`; + } + if (bt > KB) { + return `${ Math.trunc(bt/KB*1e2)/1e2 }KB`; + } + return `${ bt }B`; +} + +export function percentOf(part: number, whole: number):number { + return whole > 0 ? (part * 100) / whole : 0; +} + +export function fileType(url) { + return url.split(/[#?]/)[0].split('.').pop().trim() +} + +export function fileName(url) { + if (url) { + var m = url.toString().match(/.*\/(.+?)\./); + if (m && m.length > 1) { + return `${m[1]}.${fileType(url)}`; + } + } + return ""; +} + +export const camelCased = (val) => + val.replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); }) + +export function capitalize(s: string) { + if (s.length === 0) return s; + return s[0].toUpperCase() + s.slice(1); +} + +export const titleize = (str) => { + let upper = true + let newStr = "" + for (let i = 0, l = str.length; i < l; i++) { + // Note that you can also check for all kinds of spaces with + // str[i].match(/\s/) + if (str[i] == " ") { + upper = true + newStr += str[i] + continue + } + if (str[i] == "_") { + upper = true + newStr += ' ' + continue + } + newStr += upper ? str[i].toUpperCase() : str[i].toLowerCase() + upper = false + } + return newStr +} + +/** + * (BigInt('2783377641436327') * BigInt(id) % BigInt('4503599627370496') + BigInt('4503599627370496')).toString() + * Replacing the above line of BigInt with JSBI since the BigInt not supportiing the some of the browser (i.e Safari (< 14), Opera). + */ +export const hashProjectID = (id) => { + if (!!id) { + return JSBI.add( + JSBI.remainder( + JSBI.multiply(JSBI.BigInt('2783377641436327'), JSBI.BigInt(id)), + JSBI.BigInt('4503599627370496') + ), + JSBI.BigInt('4503599627370496') + ).toString() + } + return '' +} + + +export const colorScale = (values, colors) => { + const minValue = Math.min.apply(null, values); + const maxValue = Math.max.apply(null, values); + + return scale.linear() + .domain([minValue,maxValue]) + .range([colors[0], colors[colors.length - 1]]); +} + +export const truncate = (input, max = 10) => input.length > max ? `${input.substring(0, max)}...` : input; \ No newline at end of file diff --git a/frontend/app/validate.js b/frontend/app/validate.js new file mode 100644 index 000000000..687091003 --- /dev/null +++ b/frontend/app/validate.js @@ -0,0 +1,90 @@ +const regexIpAddress = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; +export function validateIP(value) { + return regexIpAddress.test(value); +} + +export function validateURL(value) { + if (typeof value !== 'string') return false; + var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string + '(\\#[-a-z\\d_]*)?$','i'); // fragment locator + return !!pattern.test(value); +} + +function escapeRegexp(s) { + const e = /[-[\]/{}()*+?.\\^$|]/g; // TODO: use [] instead of | + return s.replace(e, '\\$&'); +} + +const defaultOptions = { + empty: true, + spaces: true, + diacritics: true, + numbers: true, + admissibleChars: '-_', +}; +export function validateName(value, options) { + const { + admissibleChars, + empty, + spaces, + diacritics, + numbers, + } = Object.assign({}, defaultOptions, options); + + if (typeof value !== 'string') return false; // throw Error? + if (!empty && value.trim() === '') return false; + + const charsRegex = admissibleChars + ? `|${ admissibleChars.split('').map(escapeRegexp).join('|') }` + : ''; + const spaceRegex = spaces ? '| ' : ''; + + const letters = `[A-Za-z${ numbers ? '0-9' : '' }${ diacritics ? 'À-žØ-öø-ÿ' : '' }]`; + const regExp = `^(${ letters }${ spaceRegex }${ charsRegex })*$`; + return new RegExp(regExp).test(value); +} + +export function notEmptyString(value) { + if (typeof value !== 'string') return false; + if (value.trim() === '') return false; + return true; +} + +// eslint-disable-next-line complexity +export function validateKeyCode(keyCode, key, regex) { + switch (keyCode) { + case 8: // Backspace + case 9: // Tab + case 13: // Enter + case 37: // Left + case 38: // Up + case 39: // Right + case 40: // Down + break; + default: + if (!regex.test(key)) return false; + } + + return true; +} + +export function validateEmail(email) { + const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(String(email).toLowerCase()); +} + +export function validateNumber(str, options = {}) { + const { + min, + max, + } = options; + const n = Number(str); + if (Number.isNaN(n)) return false; + if (min && n < min) return false; + if (max && n > max) return false; + return true; +} diff --git a/frontend/build.sh b/frontend/build.sh new file mode 100644 index 000000000..010b69a34 --- /dev/null +++ b/frontend/build.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Script to build api module +# flags to accept: +# ee: build for enterprise edition. +# Default will be OSS build. + +# Usage: bash build.sh + +git_sha1=$(git rev-parse HEAD) +ee="false" +check_prereq() { + which docker || { + echo "Docker not installed, please install docker." + exit=1 + } + [[ exit -eq 1 ]] && exit 1 +} + +function build(){ + # Copy enterprise code + [[ $1 == "ee" ]] && { + cp ../ee/frontend/* ./ + ee="true" + } + # Run docker as the same user, else we'll run in to permission issues. + docker run --rm -v /etc/passwd:/etc/passwd -u `id -u`:`id -g` -v $(pwd):/home/${USER} -w /home/${USER} --name node_build node:14-stretch-slim /bin/bash -c "npm install && npm run build:oss" +} + +check_prereq +build $1 diff --git a/frontend/env.js b/frontend/env.js new file mode 100644 index 000000000..4c5902987 --- /dev/null +++ b/frontend/env.js @@ -0,0 +1,23 @@ +require('dotenv').config() + +const oss = { + name: 'oss', + PRODUCTION: true, + SENTRY_ENABLED: false, + SENTRY_URL: "", + CAPTCHA_ENABLED: process.env.CAPTCHA_ENABLED, + CAPTCHA_SITE_KEY: process.env.CAPTCHA_SITE_KEY, + ORIGIN: () => 'window.location.origin', + API_EDP: () => 'window.location.origin + "/api"', + ASSETS_HOST: () => 'window.location.origin + "/assets"', + VERSION: '1.0.1', + SOURCEMAP: true, + MINIO_ENDPOINT: process.env.MINIO_ENDPOINT, + MINIO_PORT: process.env.MINIO_PORT, + MINIO_USE_SSL: process.env.MINIO_USE_SSL, + MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, + MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY +} +module.exports = { + oss, +}; \ No newline at end of file diff --git a/frontend/jest.config.js b/frontend/jest.config.js new file mode 100644 index 000000000..729cf29a6 --- /dev/null +++ b/frontend/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + // "preset": "jest-puppeteer" +} \ No newline at end of file diff --git a/frontend/logfile b/frontend/logfile new file mode 100644 index 000000000..3851af727 --- /dev/null +++ b/frontend/logfile @@ -0,0 +1,3819 @@ +2021-01-23 12:42:45.336 IST [37761] LOG: starting PostgreSQL 13.1 on x86_64-apple-darwin20.1.0, compiled by Apple clang version 12.0.0 (clang-1200.0.32.27), 64-bit +2021-01-23 12:42:45.337 IST [37761] LOG: listening on IPv4 address "127.0.0.1", port 5432 +2021-01-23 12:42:45.337 IST [37761] LOG: listening on IPv6 address "::1", port 5432 +2021-01-23 12:42:45.338 IST [37761] LOG: listening on Unix socket "/tmp/.s.PGSQL.5432" +2021-01-23 12:42:45.352 IST [37762] LOG: database system was interrupted; last known up at 2021-01-21 08:13:03 IST +2021-01-23 12:42:45.507 IST [37762] LOG: database system was not properly shut down; automatic recovery in progress +2021-01-23 12:42:45.513 IST [37762] LOG: redo starts at 0/3316BC8 +2021-01-23 12:42:45.513 IST [37762] LOG: invalid record length at 0/3316CB0: wanted 24, got 0 +2021-01-23 12:42:45.513 IST [37762] LOG: redo done at 0/3316C78 +2021-01-23 12:42:45.522 IST [37761] LOG: database system is ready to accept connections +2021-01-23 14:38:53.706 IST [40210] ERROR: bind message supplies 0 parameters, but prepared statement "pdo_stmt_00000003" requires 1 +2021-01-23 14:38:53.706 IST [40210] STATEMENT: select * from "tenants" where "code" = $1 limit 1 +2021-01-23 14:39:00.422 IST [40215] ERROR: bind message supplies 0 parameters, but prepared statement "pdo_stmt_00000003" requires 1 +2021-01-23 14:39:00.422 IST [40215] STATEMENT: select * from "tenants" where "code" = $1 limit 1 +2021-01-23 16:08:04.745 IST [45258] ERROR: relation "sections" does not exist at character 15 +2021-01-23 16:08:04.745 IST [45258] STATEMENT: select * from "sections" where "id" = $1 limit 1 +2021-01-23 16:08:09.391 IST [45262] ERROR: relation "sections" does not exist at character 15 +2021-01-23 16:08:09.391 IST [45262] STATEMENT: select * from "sections" where "id" = $1 limit 1 +2021-01-23 16:09:22.542 IST [45295] ERROR: relation "sections" does not exist at character 15 +2021-01-23 16:09:22.542 IST [45295] STATEMENT: select * from "sections" where "id" = $1 limit 1 +2021-01-24 01:17:39.683 IST [50859] FATAL: role "postgres" does not exist +2021-01-24 01:36:57.415 IST [67292] ERROR: missing FROM-clause entry for table "sections" at character 31 +2021-01-24 01:36:57.415 IST [67292] STATEMENT: select * from "classes" where "sections"."class_id" = "classes"."id" and "academic_year_id" = $1 limit 1 +2021-01-24 01:41:44.028 IST [56873] ERROR: column "academic_year_id" does not exist at character 451 +2021-01-24 01:41:44.028 IST [56873] STATEMENT: select * from "users" where (name ILIKE '%af%' or exists (select * from "students" where "users"."id" = "students"."user_id" and "aadhar_number"::text LIKE $1) or exists (select * from "students" where "users"."id" = "students"."user_id" and "admission_number"::text LIKE $2) and exists (select * from "students" where "users"."id" = "students"."user_id" and exists (select * from "enrolments" where "students"."user_id" = "enrolments"."user_id" and "academic_year_id" = $3))) and "users"."deleted_at" is null limit 5 +2021-01-24 01:43:44.869 IST [66608] ERROR: missing FROM-clause entry for table "student" at character 281 +2021-01-24 01:43:44.869 IST [66608] STATEMENT: select * from "users" where (name ILIKE '%af%' or exists (select * from "students" where "users"."id" = "students"."user_id" and "aadhar_number"::text LIKE $1) or exists (select * from "students" where "users"."id" = "students"."user_id" and "admission_number"::text LIKE $2) and "student"."enrolment" = (select * where "has" = $3)) and "users"."deleted_at" is null limit 5 +2021-01-24 14:36:15.553 IST [61561] ERROR: update or delete on table "payments" violates foreign key constraint "late_fees_payment_id_foreign" on table "late_fees" +2021-01-24 14:36:15.553 IST [61561] DETAIL: Key (id)=(14) is still referenced from table "late_fees". +2021-01-24 14:36:15.553 IST [61561] STATEMENT: DELETE FROM "tnt_cf809103-d949-4562-896e-bcef7c73e8d7"."payments" WHERE "id" = '14' OR "id" = '15' OR "id" = '16' OR "id" = '17' OR "id" = '18' OR "id" = '19' OR "id" = '20' OR "id" = '21' OR "id" = '22' OR "id" = '23' OR "id" = '24' OR "id" = '25' OR "id" = '26' OR "id" = '27' OR "id" = '28' OR "id" = '29' OR "id" = '30' OR "id" = '31' OR "id" = '32' OR "id" = '33' OR "id" = '34'; +2021-01-24 14:52:27.013 IST [54028] ERROR: relation "tnt_c05488f1-1124-4d7f-81ef-3c7e9fb5b6d2.academic_years" does not exist at character 13 +2021-01-24 14:52:27.013 IST [54028] STATEMENT: INSERT INTO "tnt_c05488f1-1124-4d7f-81ef-3c7e9fb5b6d2".academic_years (id, title, start_at, end_at, is_active, created_at, updated_at) VALUES ( $1, $2, $3, $4, $5, $6, $7) +2021-01-24 16:13:57.532 IST [79798] ERROR: column "academic_year_ids" does not exist at character 712 +2021-01-24 16:13:57.532 IST [79798] HINT: Perhaps you meant to reference the column "classes.academic_year_id". +2021-01-24 16:13:57.532 IST [79798] STATEMENT: select * from "enrolments" where exists (select * from "users" where "enrolments"."user_id" = "users"."id" and "name"::text LIKE $1 and "users"."deleted_at" is null) or exists (select * from "users" where "enrolments"."user_id" = "users"."id" and "aadhar_number"::text LIKE $2 and "users"."deleted_at" is null) or exists (select * from "users" where "enrolments"."user_id" = "users"."id" and exists (select * from "students" where "users"."id" = "students"."user_id" and "admission_number"::text LIKE $3) and "users"."deleted_at" is null) and exists (select * from "sections" where "enrolments"."section_id" = "sections"."id" and exists (select * from "classes" where "sections"."class_id" = "classes"."id" and "academic_year_ids" = $4)) limit 5 +2021-01-24 16:16:00.358 IST [61561] ERROR: syntax error at or near "%" at character 716 +2021-01-24 16:16:00.358 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + select + * + from + "enrolments" + where + exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and "name" :: text LIKE % maya % + and "users"."deleted_at" is null + ) + or exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and "aadhar_number" :: text LIKE % maya % + and "users"."deleted_at" is null + ) + or exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and exists ( + select + * + from + "students" + where + "users"."id" = "students"."user_id" + and "admission_number" :: text LIKE % maya % + ) + and "users"."deleted_at" is null + ) + and exists ( + select + * + from + "sections" + where + "enrolments"."section_id" = "sections"."id" + and exists ( + select + * + from + "classes" + where + "sections"."class_id" = "classes"."id" + and "academic_year_id" = 21 + ) + ) + limit + 5 + ) +2021-01-24 16:16:34.283 IST [61561] ERROR: syntax error at or near ")" at character 1647 +2021-01-24 16:16:34.283 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + select + * + from + "enrolments" + where + exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and "name" :: text LIKE '%maya%' + and "users"."deleted_at" is null + ) + or exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and "aadhar_number" :: text LIKE '%maya%' + and "users"."deleted_at" is null + ) + or exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and exists ( + select + * + from + "students" + where + "users"."id" = "students"."user_id" + and "admission_number" :: text LIKE '%maya%' + ) + and "users"."deleted_at" is null + ) + and exists ( + select + * + from + "sections" + where + "enrolments"."section_id" = "sections"."id" + and exists ( + select + * + from + "classes" + where + "sections"."class_id" = "classes"."id" + and "academic_year_id" = 21 + ) + ) + limit + 5 + ) +2021-01-24 16:16:45.440 IST [61561] ERROR: relation "enrolments" does not exist at character 560 +2021-01-24 16:16:45.440 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + select + * + from + "enrolments" + where + exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and "name" :: text LIKE '%maya%' + and "users"."deleted_at" is null + ) + or exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and "aadhar_number" :: text LIKE '%maya%' + and "users"."deleted_at" is null + ) + or exists ( + select + * + from + "users" + where + "enrolments"."user_id" = "users"."id" + and exists ( + select + * + from + "students" + where + "users"."id" = "students"."user_id" + and "admission_number" :: text LIKE '%maya%' + ) + and "users"."deleted_at" is null + ) + and exists ( + select + * + from + "sections" + where + "enrolments"."section_id" = "sections"."id" + and exists ( + select + * + from + "classes" + where + "sections"."class_id" = "classes"."id" + and "academic_year_id" = 21 + ) + ) + limit + 5 +2021-01-24 16:17:32.152 IST [61561] ERROR: relation "students" does not exist at character 1320 +2021-01-24 16:17:32.152 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + select + * + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + where + exists ( + select + * + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + where + "enrolments"."user_id" = "users"."id" + and "name" :: text LIKE '%maya%' + and "users"."deleted_at" is null + ) + or exists ( + select + * + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + where + "enrolments"."user_id" = "users"."id" + and "aadhar_number" :: text LIKE '%maya%' + and "users"."deleted_at" is null + ) + or exists ( + select + * + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + where + "enrolments"."user_id" = "users"."id" + and exists ( + select + * + from + "students" + where + "users"."id" = "students"."user_id" + and "admission_number" :: text LIKE '%maya%' + ) + and "users"."deleted_at" is null + ) + and exists ( + select + * + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + where + "enrolments"."section_id" = "sections"."id" + and exists ( + select + * + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + where + "sections"."class_id" = "classes"."id" + and "academic_year_id" = 21 + ) + ) + limit + 5 +2021-01-24 16:21:47.191 IST [61561] ERROR: table name "s" specified more than once +2021-01-24 16:21:47.191 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + + select + * + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students s on s.user_id = u.id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + and u.name like '%maya%' + or s.admission_number like '%maya%' + or u.aadhar_number like '%maya%' +2021-01-24 17:11:18.471 IST [41136] ERROR: missing FROM-clause entry for table "section_id, enrolments" at character 8 +2021-01-24 17:11:18.471 IST [41136] STATEMENT: select "enrolments"."section_id, enrolments"."id" from "enrolments" inner join "users" on "users"."id" = "enrolments"."user_id" inner join "students" on "students"."user_id" = "users"."id" inner join "sections" on "sections"."id" = "enrolments"."section_id" inner join "classes" on "classes"."id" = "sections"."class_id" where "classes"."academic_year_id" = $1 and "users"."name"::text LIKE $2 or "users"."aadhar_number"::text LIKE $3 or "students"."admission_number"::text LIKE $4 limit 5 +2021-01-24 17:32:01.504 IST [53198] ERROR: column students.admission does not exist at character 166 +2021-01-24 17:32:01.504 IST [53198] STATEMENT: select "enrolments"."id", "enrolments"."section_id", "users"."name", "sections"."name" as "section_name", "classes"."name" as "class_name", "users"."aadhar_number", "students"."admission" from "enrolments" inner join "users" on "users"."id" = "enrolments"."user_id" inner join "students" on "students"."user_id" = "users"."id" inner join "sections" on "sections"."id" = "enrolments"."section_id" inner join "classes" on "classes"."id" = "sections"."class_id" where "classes"."academic_year_id" = $1 and "users"."name"::text LIKE $2 or "users"."aadhar_number"::text LIKE $3 or "students"."admission_number"::text LIKE $4 limit 5 +2021-01-24 17:42:19.170 IST [15965] ERROR: invalid input syntax for type bigint: "undefined" +2021-01-24 17:42:19.170 IST [15965] STATEMENT: select * from "enrolments" where "enrolments"."id" = $1 limit 1 +2021-01-24 17:42:19.170 IST [15967] ERROR: invalid input syntax for type bigint: "undefined" +2021-01-24 17:42:19.170 IST [15967] STATEMENT: select * from "enrolments" where "enrolments"."id" = $1 limit 1 +2021-01-24 17:42:33.397 IST [34326] ERROR: invalid input syntax for type bigint: "undefined" +2021-01-24 17:42:33.397 IST [34326] STATEMENT: select * from "enrolments" where "enrolments"."id" = $1 limit 1 +2021-01-24 17:42:33.397 IST [34328] ERROR: invalid input syntax for type bigint: "undefined" +2021-01-24 17:42:33.397 IST [34328] STATEMENT: select * from "enrolments" where "enrolments"."id" = $1 limit 1 +2021-01-24 17:42:49.746 IST [55543] ERROR: invalid input syntax for type bigint: "undefined" +2021-01-24 17:42:49.746 IST [55543] STATEMENT: select * from "enrolments" where "enrolments"."id" = $1 limit 1 +2021-01-24 17:42:49.746 IST [55544] ERROR: invalid input syntax for type bigint: "undefined" +2021-01-24 17:42:49.746 IST [55544] STATEMENT: select * from "enrolments" where "enrolments"."id" = $1 limit 1 +2021-01-24 18:05:18.709 IST [36131] ERROR: column sections.standard_id does not exist at character 87 +2021-01-24 18:05:18.709 IST [36131] STATEMENT: select count(*) as aggregate from "sections" inner join "classes" on "classes"."id" = "sections"."standard_id" where "classes"."academic_year_id" = $1 +2021-01-24 18:06:14.567 IST [276] ERROR: column sections.standard_id does not exist at character 87 +2021-01-24 18:06:14.567 IST [276] STATEMENT: select count(*) as aggregate from "sections" inner join "classes" on "classes"."id" = "sections"."standard_id" where "classes"."class_id" = $1 +2021-01-24 19:17:35.056 IST [61561] ERROR: syntax error at or near ""tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"" at character 10 +2021-01-24 19:17:35.056 IST [61561] STATEMENT: select * "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where c.academic_year_id = 21 +2021-01-24 19:18:40.073 IST [61561] ERROR: syntax error at or near "select" at character 3383 +2021-01-24 19:18:40.073 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + select amount_paid ( + select + sum(amount_paid) + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + ) +2021-01-24 19:18:47.493 IST [61561] ERROR: syntax error at or near "select" at character 3383 +2021-01-24 19:18:47.493 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + select amount_paid ( + select + sum(amount_paid) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + ) +2021-01-24 19:18:57.121 IST [61561] ERROR: syntax error at or near "select" at character 3383 +2021-01-24 19:18:57.121 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + select amount_paid ( + select + sum(amount_paid) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + ) t +2021-01-24 19:19:01.024 IST [61561] ERROR: syntax error at or near "select" at character 3385 +2021-01-24 19:19:01.024 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + select t.amount_paid ( + select + sum(amount_paid) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + ) t +2021-01-24 19:19:33.948 IST [61561] ERROR: syntax error at or near "(" at character 3371 +2021-01-24 19:19:33.948 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + select * ( + select + sum(amount_paid) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + ) t +2021-01-24 19:19:44.475 IST [61561] ERROR: column "amount_paid" does not exist at character 3376 +2021-01-24 19:19:44.475 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + + select + sum(amount_paid) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + +2021-01-24 19:19:49.689 IST [61561] ERROR: column p.amount_paid does not exist at character 3376 +2021-01-24 19:19:49.689 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + + select + sum(p.amount_paid) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + +2021-01-24 19:19:55.495 IST [61561] ERROR: column p.amount does not exist at character 3376 +2021-01-24 19:19:55.495 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + + select + sum(p.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + where + c.academic_year_id = 21 + +2021-01-24 19:20:43.122 IST [61561] ERROR: column p.amount does not exist at character 3376 +2021-01-24 19:20:43.122 IST [61561] HINT: Perhaps you meant to reference the column "pi.amount". +2021-01-24 19:20:43.122 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + + select + sum(p.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + c.academic_year_id = 21 + +2021-01-24 19:21:15.388 IST [61561] ERROR: syntax error at or near "(" at character 3372 +2021-01-24 19:21:15.388 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + + select * ( + select + sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + c.academic_year_id = 21 + ) t + +2021-01-24 19:21:16.736 IST [61561] ERROR: syntax error at or near "(" at character 3372 +2021-01-24 19:21:16.736 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- OTHER + ------------------------------------------- + + select * ( + select + sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + c.academic_year_id = 21 + ) t + +2021-01-24 19:26:28.793 IST [61561] ERROR: date/time field value out of range: "24-01-2021" at character 3877 +2021-01-24 19:26:28.793 IST [61561] HINT: Perhaps you need a different "datestyle" setting. +2021-01-24 19:26:28.793 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + c.created_at BETWEEN '01-06-2020' and '24-01-2021' + and c.academic_year_id = 21; +2021-01-24 19:31:46.134 IST [61561] ERROR: column fa.section_id does not exist at character 4320 +2021-01-24 19:31:46.134 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + -- select + -- sum(pi.amount) as amount_paid + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + -- where + -- p.created_at BETWEEN '2019-06-01' + -- and '2021-01-24' + -- and c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + + SELECT + * + FROM + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".fee_assignments fa + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s ON s.id = fa.feeable_id + AND fa.feeable_type = 'section' + WHERE fa.academic_year_id = 21 + group by fa.section_id +2021-01-24 19:31:57.880 IST [61561] ERROR: column "fa.id" must appear in the GROUP BY clause or be used in an aggregate function at character 4092 +2021-01-24 19:31:57.880 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + -- select + -- sum(pi.amount) as amount_paid + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + -- where + -- p.created_at BETWEEN '2019-06-01' + -- and '2021-01-24' + -- and c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + + SELECT + * + FROM + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".fee_assignments fa + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s ON s.id = fa.feeable_id + AND fa.feeable_type = 'section' + WHERE fa.academic_year_id = 21 + group by s.id +2021-01-24 19:32:08.697 IST [61561] ERROR: missing FROM-clause entry for table "sa" at character 4096 +2021-01-24 19:32:08.697 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + -- select + -- sum(pi.amount) as amount_paid + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + -- where + -- p.created_at BETWEEN '2019-06-01' + -- and '2021-01-24' + -- and c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + + SELECT + *, + sa.id as section_id + FROM + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".fee_assignments fa + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s ON s.id = fa.feeable_id + AND fa.feeable_type = 'section' + WHERE fa.academic_year_id = 21 + group by s.id +2021-01-24 19:32:26.762 IST [61561] ERROR: column "fa.id" must appear in the GROUP BY clause or be used in an aggregate function at character 4092 +2021-01-24 19:32:26.762 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + -- select + -- sum(pi.amount) as amount_paid + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + -- where + -- p.created_at BETWEEN '2019-06-01' + -- and '2021-01-24' + -- and c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + + SELECT + *, + s.id as section_id + FROM + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".fee_assignments fa + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s ON s.id = fa.feeable_id + AND fa.feeable_type = 'section' + WHERE fa.academic_year_id = 21 + group by s.id +2021-01-24 19:33:03.940 IST [61561] ERROR: syntax error at or near "FROM" at character 4114 +2021-01-24 19:33:03.940 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + -- select + -- sum(pi.amount) as amount_paid + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + -- where + -- p.created_at BETWEEN '2019-06-01' + -- and '2021-01-24' + -- and c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + + SELECT + s.id as section_id, + + FROM + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".fee_assignments fa + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s ON s.id = fa.feeable_id + AND fa.feeable_type = 'section' + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.section_id = s.id + WHERE fa.academic_year_id = 21 + group by s.id +2021-01-24 19:33:32.053 IST [61561] ERROR: column "fa.amount" must appear in the GROUP BY clause or be used in an aggregate function at character 4114 +2021-01-24 19:33:32.053 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + -- select + -- sum(pi.amount) as amount_paid + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + -- where + -- p.created_at BETWEEN '2019-06-01' + -- and '2021-01-24' + -- and c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + SELECT + s.id as section_id, + fa.amount + FROM + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".fee_assignments fa + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s ON s.id = fa.feeable_id + AND fa.feeable_type = 'section' + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.section_id = s.id + WHERE + fa.academic_year_id = 21 + group by + s.id +2021-01-24 19:34:54.376 IST [61561] ERROR: missing FROM-clause entry for table "s" at character 4092 +2021-01-24 19:34:54.376 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + -- select + -- sum(pi.amount) as amount_paid + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + -- where + -- p.created_at BETWEEN '2019-06-01' + -- and '2021-01-24' + -- and c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + SELECT + s.id as section_id, + sum(fa.amount), + count(e.id) as enrolments + FROM + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".fee_assignments fa + + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.section_id = fa.feeable_id + WHERE + fa.academic_year_id = 21 + group by + s.id +2021-01-24 19:34:58.732 IST [61561] ERROR: missing FROM-clause entry for table "s" at character 4370 +2021-01-24 19:34:58.732 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + -- select + -- sum(pi.amount) as amount_paid + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + -- where + -- p.created_at BETWEEN '2019-06-01' + -- and '2021-01-24' + -- and c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + SELECT + -- s.id as section_id, + sum(fa.amount), + count(e.id) as enrolments + FROM + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".fee_assignments fa + + JOIN "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.section_id = fa.feeable_id + WHERE + fa.academic_year_id = 21 + group by + s.id +2021-01-24 19:48:33.759 IST [61561] ERROR: column "e.section_id" must appear in the GROUP BY clause or be used in an aggregate function at character 3402 +2021-01-24 19:48:33.759 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + p.*, + e.section_id, + c.id as class_id, + c.academic_year_id + -- sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + p.created_at BETWEEN '2019-06-01' + and '2021-01-24' + and p.status = 'paid' + and s.id in (4) + and c.academic_year_id = 21 + group by p.id; +2021-01-24 19:48:59.558 IST [61561] ERROR: column "c.id" must appear in the GROUP BY clause or be used in an aggregate function at character 3420 +2021-01-24 19:48:59.558 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + p.*, + -- e.section_id, + c.id as class_id, + c.academic_year_id + -- sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + p.created_at BETWEEN '2019-06-01' + and '2021-01-24' + and p.status = 'paid' + and s.id in (4) + and c.academic_year_id = 21 + group by p.id; +2021-01-24 19:49:05.206 IST [61561] ERROR: syntax error at or near "from" at character 3499 +2021-01-24 19:49:05.206 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + p.*, + -- e.section_id, + -- c.id as class_id, + -- c.academic_year_id + -- sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + p.created_at BETWEEN '2019-06-01' + and '2021-01-24' + and p.status = 'paid' + and s.id in (4) + and c.academic_year_id = 21 + group by p.id; +2021-01-24 19:49:54.422 IST [61561] ERROR: column "pi.amount" must appear in the GROUP BY clause or be used in an aggregate function at character 3439 +2021-01-24 19:49:54.422 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + p.* + -- , sum(pi.amount) as paid_amount + , pi.amount + -- e.section_id, + -- c.id as class_id, + -- c.academic_year_id + -- sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + p.created_at BETWEEN '2019-06-01' + and '2021-01-24' + and p.status = 'paid' + and s.id in (4) + and c.academic_year_id = 21 + group by p.id; +2021-01-24 19:50:10.578 IST [61561] ERROR: syntax error at or near "e" at character 3435 +2021-01-24 19:50:10.578 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + p.* + , sum(pi.amount) as paid_amount + e.section_id, + -- c.id as class_id, + -- c.academic_year_id + -- sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + p.created_at BETWEEN '2019-06-01' + and '2021-01-24' + and p.status = 'paid' + and s.id in (4) + and c.academic_year_id = 21 + group by p.id; +2021-01-24 19:50:16.778 IST [61561] ERROR: syntax error at or near "e" at character 3435 +2021-01-24 19:50:16.778 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + p.* + , sum(pi.amount) as paid_amount + e.section_id, + -- c.id as class_id, + -- c.academic_year_id + -- sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + p.created_at BETWEEN '2019-06-01' + and '2021-01-24' + and p.status = 'paid' + and s.id in (4) + and c.academic_year_id = 21 + group by p.id, e.section_id; +2021-01-24 19:51:33.455 IST [61561] ERROR: syntax error at or near "," at character 3433 +2021-01-24 19:51:33.455 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + p.id + , s.class_id + , e.section_id, + , p.enrolment_id + , sum(pi.amount) as paid_amount + + -- c.id as class_id, + -- c.academic_year_id + -- sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + p.created_at BETWEEN '2019-06-01' + and '2021-01-24' + and p.status = 'paid' + and s.id in (4) + and c.academic_year_id = 21 + group by p.id, s.class_id, e.section_id, p.enrolment_id; +2021-01-24 19:52:33.123 IST [61561] ERROR: column "c.academic_year_id" must appear in the GROUP BY clause or be used in an aggregate function at character 3486 +2021-01-24 19:52:33.123 IST [61561] STATEMENT: -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payment_items pi + -- left join "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".payments p on p.id = pi.payment_id + -- where p.enrolment_id = 1 + -- select * from "tnt_fadab5cd-0384-403b-a152-1e7592084ab4".users where "name" LIKE '%afi%' + -- DROP schema "tnt_788478b3-dcc8-4b5f-b4ee-d51c861333ff" CASCADE; + -- select * from "tnt_cf809103-d949-4562-896e-bcef7c73e8d7".users where phone = '9705664434' + -- select * from "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments where user_id = 1340 + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."enrolments" + -- where + -- exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "name" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and "aadhar_number" :: text LIKE '%maya%' + -- and "users"."deleted_at" is null + -- ) + -- or exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."users" + -- where + -- "enrolments"."user_id" = "users"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."students" + -- where + -- "users"."id" = "students"."user_id" + -- and "admission_number" :: text LIKE '%maya%' + -- ) + -- and "users"."deleted_at" is null + -- ) + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."sections" + -- where + -- "enrolments"."section_id" = "sections"."id" + -- and exists ( + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."classes" + -- where + -- "sections"."class_id" = "classes"."id" + -- and "academic_year_id" = 21 + -- ) + -- ) + -- limit + -- 5 + ------------------------------------------- + -- AUTO COMPLETE + ------------------------------------------- + -- select + -- u.id, s."name" as section_name, u."name" as name, c."name" as class_name, u.aadhar_number, st.admission_number, s.id as section_id, c.id as class_id + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".users u on u.id = e.user_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".students st on st.user_id = u.id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21 + -- and u.name like '%maya%' + -- or st.admission_number like '%maya%' + -- or u.aadhar_number like '%maya%' + ------------------------------------------- + -- SECTIONS + ------------------------------------------- + -- select + -- * + -- from + -- "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s + -- join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + -- where + -- c.academic_year_id = 21; + ------------------------------------------- + -- AMOUNT PAID BY Academic Year ID + ------------------------------------------- + select + p.id + , s.class_id + , e.section_id + , p.enrolment_id + , sum(pi.amount) as paid_amount + , c.academic_year_id + -- c.id as class_id, + -- c.academic_year_id + -- sum(pi.amount) as amount_paid + from + "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payments p + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".enrolments e on e.id = p.enrolment_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".sections s on s.id = e.section_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".classes c on c.id = s.class_id + join "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1".payment_items pi on pi.payment_id = p.id + where + p.created_at BETWEEN '2019-06-01' + and '2021-01-24' + and p.status = 'paid' + and s.id in (4) + and c.academic_year_id = 21 + group by p.id, s.class_id, e.section_id, p.enrolment_id; +2021-01-24 19:56:39.082 IST [61561] ERROR: relation "payments" does not exist at character 225 +2021-01-24 19:56:39.082 IST [61561] STATEMENT: select + p.id as payment_id, + p.type, + p.mode, + p.status, + p.dd_cheque_number, + s.class_id, + e.section_id, + p.enrolment_id, + sum(pi.amount) as paid_amount, + c.academic_year_id, + p.created_at, + p.updated_at + from + payments p + join enrolments e on e.id = p.enrolment_id + join sections s on s.id = e.section_id + join classes c on c.id = s.class_id + join payment_items pi on pi.payment_id = p.id + group by + p.id, + s.class_id, + e.section_id, + p.enrolment_id, + c.academic_year_id; +2021-01-24 19:57:21.731 IST [61561] ERROR: relation "payments" does not exist at character 244 +2021-01-24 19:57:21.731 IST [61561] STATEMENT: CREATE VIEW payments_view AS + SELECT + p.id AS payment_id, + p.type, + p.mode, + p.status, + p.dd_cheque_number, + s.class_id, + e.section_id, + p.enrolment_id, + sum( + pi.amount) AS paid_amount, + c.academic_year_id, + p.created_at, + p.updated_at + FROM + payments p + JOIN enrolments e ON e.id = p.enrolment_id + JOIN sections s ON s.id = e.section_id + JOIN classes c ON c.id = s.class_id + JOIN payment_items pi ON pi.payment_id = p.id + GROUP BY + p.id, + s.class_id, + e.section_id, + p.enrolment_id, + c.academic_year_id; +2021-01-24 19:57:48.605 IST [61561] ERROR: invalid input syntax for type oid: "" at character 1397 +2021-01-24 19:57:48.605 IST [61561] STATEMENT: SELECT c.conname AS constraint_name,(SELECT STRING_AGG(QUOTE_IDENT(a.attname),','ORDER BY t.seq)FROM(SELECT ROW_NUMBER()OVER(ROWS UNBOUNDED PRECEDING)AS seq,attnum FROM UNNEST(c.conkey)AS t(attnum))AS t INNER JOIN pg_attribute AS a ON a.attrelid=c.conrelid AND a.attnum=t.attnum)AS child_column,tt.schema as parent_schema,tt.name AS parent_name,(SELECT STRING_AGG(QUOTE_IDENT(a.attname),','ORDER BY t.seq)FROM(SELECT ROW_NUMBER()OVER(ROWS UNBOUNDED PRECEDING)AS seq,attnum FROM UNNEST(c.confkey)AS t(attnum))AS t INNER JOIN pg_attribute AS a ON a.attrelid=c.confrelid AND a.attnum=t.attnum)AS parent_column,CASE confupdtype WHEN'r'THEN'restrict'WHEN'c'THEN'cascade'WHEN'n'THEN'set null'WHEN'd'THEN'set default'WHEN'a'THEN'no action'ELSE NULL END AS on_update,CASE confdeltype WHEN'r'THEN'restrict'WHEN'c'THEN'cascade'WHEN'n'THEN'set null'WHEN'd'THEN'set default'WHEN'a'THEN'no action'ELSE NULL END AS on_delete FROM pg_catalog.pg_constraint AS c INNER JOIN(SELECT pg_class.oid,QUOTE_IDENT(pg_namespace.nspname)as schema,QUOTE_IDENT(pg_class.relname)AS name FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid)AS tf ON tf.oid=c.conrelid INNER JOIN(SELECT pg_class.oid,QUOTE_IDENT(pg_namespace.nspname)as schema,QUOTE_IDENT(pg_class.relname)AS name FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid)AS tt ON tt.oid=c.confrelid WHERE tf.oid='' AND c.contype='f'; +2021-01-24 19:58:16.168 IST [61561] ERROR: relation "payments" does not exist at character 286 +2021-01-24 19:58:16.168 IST [61561] STATEMENT: CREATE VIEW "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."payments_view" AS SELECT + p.id AS payment_id, + p.type, + p.mode, + p.status, + p.dd_cheque_number, + s.class_id, + e.section_id, + p.enrolment_id, + sum(pi.amount) AS paid_amount, + c.academic_year_id, + p.created_at, + p.updated_at + FROM + payments p + JOIN enrolments e ON e.id = p.enrolment_id + JOIN sections s ON s.id = e.section_id + JOIN classes c ON c.id = s.class_id + JOIN payment_items pi ON pi.payment_id = p.id + GROUP BY + p.id, + s.class_id, + e.section_id, + p.enrolment_id, + c.academic_year_id; +2021-01-25 00:02:22.238 IST [61561] ERROR: duplicate key value violates unique constraint "terms_pkey" +2021-01-25 00:02:22.238 IST [61561] DETAIL: Key (id)=(4) already exists. +2021-01-25 00:02:22.238 IST [61561] STATEMENT: UPDATE "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."terms" SET "id" = '4' WHERE "id" = '11'; +2021-01-25 00:02:51.913 IST [61561] ERROR: duplicate key value violates unique constraint "terms_pkey" +2021-01-25 00:02:51.913 IST [61561] DETAIL: Key (id)=(2) already exists. +2021-01-25 00:02:51.913 IST [61561] STATEMENT: UPDATE "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."terms" SET "id" = '2' WHERE "id" = '9'; +2021-01-25 00:11:59.847 IST [61561] ERROR: null value in column "amount" of relation "fee_assignments" violates not-null constraint +2021-01-25 00:11:59.847 IST [61561] DETAIL: Failing row contains (1, null, null, null, null, null, null, null, null, null, null, null). +2021-01-25 00:11:59.847 IST [61561] STATEMENT: INSERT INTO "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."fee_assignments" VALUES (DEFAULT); +2021-01-25 00:12:14.126 IST [61561] ERROR: insert or update on table "fee_assignments" violates foreign key constraint "fee_assignments_fee_type_id_foreign" +2021-01-25 00:12:14.126 IST [61561] DETAIL: Key (fee_type_id)=(89) is not present in table "fee_types". +2021-01-25 00:12:14.126 IST [61561] STATEMENT: INSERT INTO "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."fee_assignments" ("id", "amount", "amount_new_admission", "fee_type_id", "academic_year_id", "term_id", "feeable_type", "feeable_id", "created_at") VALUES ('8253', '2340', '0', '89', '56', '5', 'section', '50', '2020-06-23 16:02:59.271264'); +2021-01-25 00:14:27.104 IST [61561] ERROR: insert or update on table "fee_assignments" violates foreign key constraint "fee_assignments_term_id_foreign" +2021-01-25 00:14:27.104 IST [61561] DETAIL: Key (term_id)=(5) is not present in table "terms". +2021-01-25 00:14:27.104 IST [61561] STATEMENT: INSERT INTO "tnt_67201e5a-f3b8-48fb-ae8a-f8484ceed5a1"."fee_assignments" ("id", "amount", "amount_new_admission", "fee_type_id", "academic_year_id", "term_id", "feeable_type", "feeable_id", "created_at") VALUES ('8253', '2340', '0', '89', '56', '5', 'section', '50', '2020-06-23 16:02:59.271264'); +2021-04-13 13:56:20.424 IST [39875] LOG: starting PostgreSQL 13.2 on x86_64-apple-darwin20.3.0, compiled by Apple clang version 12.0.0 (clang-1200.0.32.29), 64-bit +2021-04-13 13:56:20.428 IST [39875] LOG: listening on IPv6 address "::1", port 5432 +2021-04-13 13:56:20.428 IST [39875] LOG: listening on IPv4 address "127.0.0.1", port 5432 +2021-04-13 13:56:20.434 IST [39875] LOG: listening on Unix socket "/tmp/.s.PGSQL.5432" +2021-04-13 13:56:20.447 IST [39876] LOG: database system was interrupted; last known up at 2021-04-07 21:56:31 IST +2021-04-13 13:56:20.630 IST [39876] LOG: database system was not properly shut down; automatic recovery in progress +2021-04-13 13:56:20.634 IST [39876] LOG: redo starts at 0/4A1B5D0 +2021-04-13 13:56:20.634 IST [39876] LOG: invalid record length at 0/4A1B6B8: wanted 24, got 0 +2021-04-13 13:56:20.634 IST [39876] LOG: redo done at 0/4A1B680 +2021-04-13 13:56:20.645 IST [39875] LOG: database system is ready to accept connections +2021-04-13 13:57:38.422 IST [39997] ERROR: new row for relation "users" violates check constraint "users_blood_group_check" +2021-04-13 13:57:38.422 IST [39997] DETAIL: Failing row contains (13, Demo Teacher, 1711, null, null, $2y$10$MVlQIOJyYK2gLtDbVP9LNe//4MqnCFwvpNzXvn0c9irwH5ic6gYEK, 1234567890, 123412341239, 1986-10-10, male, null, null, A+, null, t, null, 2021-04-13 08:27:38, 2021-04-13 08:27:38, null). +2021-04-13 13:57:38.422 IST [39997] STATEMENT: insert into "users" ("username", "name", "phone", "gender", "dob", "blood_group", "aadhar_number", "password", "updated_at", "created_at") values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) returning "id" diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 000000000..fa3abbf98 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,63476 @@ +{ + "name": "openreplay", + "version": "1.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "openreplay", + "version": "1.0.1", + "dependencies": { + "@sentry/browser": "^5.21.1", + "classnames": "^2.2.6", + "codemirror": "^5.56.0", + "copy-to-clipboard": "^3.3.1", + "datamaps": "^0.5.9", + "deep-diff": "^1.0.2", + "immutable": "^4.0.0-rc.12", + "jsbi": "^3.1.3", + "jshint": "^2.11.1", + "luxon": "^1.24.1", + "mobx": "^6.0.4", + "mobx-react-lite": "^3.1.6", + "moment": "^2.27.0", + "moment-range": "^4.0.2", + "optimal-select": "^4.0.1", + "rc-time-picker": "^3.7.3", + "react": "^16.13.1", + "react-circular-progressbar": "^2.0.3", + "react-codemirror2": "^5.1.0", + "react-confirm": "^0.1.20", + "react-datepicker": "^2.16.0", + "react-daterange-picker": "^2.0.1", + "react-dnd": "^2.6.0", + "react-dnd-html5-backend": "^2.6.0", + "react-dom": "^16.13.1", + "react-google-recaptcha": "^1.1.0", + "react-highlight": "^0.14.0", + "react-json-tree": "^0.11.2", + "react-json-view": "^1.19.1", + "react-lazyload": "^3.0.0", + "react-redux": "^5.1.2", + "react-router": "^4.3.1", + "react-router-dom": "^4.3.1", + "react-toastify": "^5.5.0", + "react-virtualized": "^9.22.2", + "recharts": "^1.8.5", + "redux": "^4.0.5", + "redux-immutable": "^4.0.0", + "redux-thunk": "^2.3.0", + "semantic-ui-react": "^0.87.3", + "socket.io-client": "^3.0.3", + "source-map": "^0.7.3", + "syncod": "^0.0.1", + "tailwindcss": "^1.5.2" + }, + "devDependencies": { + "@babel/cli": "^7.10.5", + "@babel/core": "^7.12.10", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-decorators": "^7.10.5", + "@babel/plugin-proposal-private-methods": "^7.10.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/preset-env": "^7.10.4", + "@babel/preset-flow": "^7.10.4", + "@babel/preset-react": "^7.10.4", + "@openreplay/sourcemap-uploader": "^3.0.0", + "@storybook/react": "^6.0.20", + "autoprefixer": "^7.2.5", + "babel-loader": "^8.1.0", + "babel-plugin-recharts": "^1.2.1", + "circular-dependency-plugin": "^5.2.0", + "copy-webpack-plugin": "^5.1.1", + "country-data": "0.0.31", + "css-loader": "^3.6.0", + "cssnano": "^4.1.10", + "deasync-promise": "^1.0.1", + "deploy-aws-s3-cloudfront": "^3.2.4", + "dotenv": "^6.2.0", + "eslint-config-airbnb": "^16.1.0", + "eslint-import-resolver-babel-module": "^4.0.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-jsx-a11y": "^6.3.1", + "eslint-plugin-react": "^7.20.6", + "faker": "^5.5.3", + "flow-bin": "^0.115.0", + "html-webpack-plugin": "^3.2.0", + "mini-css-extract-plugin": "^0.7.0", + "minio": "^7.0.18", + "moment-locales-webpack-plugin": "^1.2.0", + "postcss-import": "^12.0.1", + "postcss-inline-svg": "^3.1.1", + "postcss-loader": "^3.0.0", + "postcss-mixins": "^6.2.3", + "postcss-nesting": "^4.2.1", + "postcss-simple-vars": "^4.1.0", + "react-scripts": "^3.4.3", + "style-loader": "^0.23.1", + "svgo": "^1.3.2", + "webpack": "^4.44.0", + "webpack-bundle-analyzer": "^3.8.0", + "webpack-cli": "^3.3.12", + "webpack-dev-server": "^3.11.0" + }, + "engines": { + "node": ">=10.14.1" + } + }, + "node_modules/@babel/cli": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.13.10.tgz", + "integrity": "sha512-lYSBC7B4B9hJ7sv0Ojx1BrGhuzCoOIYfLjd+Xpd4rOzdS+a47yi8voV8vFkfjlZR1N5qZO7ixOCbobUdT304PQ==", + "dev": true, + "dependencies": { + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + }, + "bin": { + "babel": "bin/babel.js", + "babel-external-helpers": "bin/babel-external-helpers.js" + }, + "optionalDependencies": { + "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents", + "chokidar": "^3.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/cli/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz", + "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==", + "dev": true + }, + "node_modules/@babel/core": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.10.tgz", + "integrity": "sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.9", + "@babel/helper-compilation-targets": "^7.13.10", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helpers": "^7.13.10", + "@babel/parser": "^7.13.10", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", + "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.13.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", + "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", + "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz", + "integrity": "sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.13.8", + "@babel/helper-validator-option": "^7.12.17", + "browserslist": "^4.14.5", + "semver": "^6.3.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.13.11", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz", + "integrity": "sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-member-expression-to-functions": "^7.13.0", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-split-export-declaration": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", + "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "regexpu-core": "^4.7.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz", + "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz", + "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.13.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", + "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz", + "integrity": "sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", + "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", + "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.12.tgz", + "integrity": "sha512-7zVQqMO3V+K4JOOj40kxiCrMf6xlQAkewBB0eu2b03OO/Q21ZutOzjpfD79A5gtE/2OWi1nv625MrDlGlkbknQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-replace-supers": "^7.13.12", + "@babel/helper-simple-access": "^7.13.12", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.12.11", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", + "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "dev": true + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz", + "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-wrap-function": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", + "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", + "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.13.12" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", + "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.1" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "dev": true + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz", + "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", + "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", + "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.12.11", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.12.tgz", + "integrity": "sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz", + "integrity": "sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.13.12" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz", + "integrity": "sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-remap-async-to-generator": "^7.13.0", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz", + "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.13.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.13.5.tgz", + "integrity": "sha512-i0GDfVNuoapwiheevUOuSW67mInqJ8qw7uWfpjNVeHMn143kXblEy/bmL9AdZ/0yf/4BMQeWXezK0tQIvNPqag==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-decorators": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz", + "integrity": "sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.12.13.tgz", + "integrity": "sha512-idIsBT+DGXdOHL82U+8bwX4goHm/z10g8sGGrQroh+HCRcm7mDv/luaGdWJQMTuCX2FsdXS7X0Nyyzp4znAPJA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-syntax-export-default-from": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz", + "integrity": "sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz", + "integrity": "sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz", + "integrity": "sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz", + "integrity": "sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz", + "integrity": "sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", + "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.13.8", + "@babel/helper-compilation-targets": "^7.13.8", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz", + "integrity": "sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz", + "integrity": "sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz", + "integrity": "sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz", + "integrity": "sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.12.13.tgz", + "integrity": "sha512-Rw6aIXGuqDLr6/LoBBYE57nKOzQpz/aDkKlMqEwH+Vp0MXbG6H/TfRjaY343LKxzAKAMXIHsQ8JzaZKuDZ9MwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.12.13.tgz", + "integrity": "sha512-gVry0zqoums0hA+EniCYK3gABhjYSLX1dVuwYpPw9DrLNA4/GovXySHVg4FGRsZht09ON/5C2NVx3keq+qqVGQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.13.tgz", + "integrity": "sha512-J/RYxnlSLXZLVR7wTRsozxKT8qbsx1mNKJzXEEjQ0Kjx1ZACcyHgbanNWNCFtc36IzuWhYWPpvJFFoexoOWFmA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz", + "integrity": "sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", + "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.13.tgz", + "integrity": "sha512-cHP3u1JiUiG2LFDKbXnwVad81GvfyIOmCD6HIEId6ojrY0Drfy2q1jw7BwN7dE84+kTnBjLkXoL3IEy/3JPu2w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz", + "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz", + "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-remap-async-to-generator": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz", + "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz", + "integrity": "sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz", + "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-split-export-declaration": "^7.12.13", + "globals": "^11.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz", + "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz", + "integrity": "sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz", + "integrity": "sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz", + "integrity": "sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz", + "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.13.0.tgz", + "integrity": "sha512-EXAGFMJgSX8gxWD7PZtW/P6M+z74jpx3wm/+9pn+c2dOawPpBkUX7BrfyPvo6ZpXbgRIEuwgwDb/MGlKvu2pOg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-flow": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz", + "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz", + "integrity": "sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz", + "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz", + "integrity": "sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz", + "integrity": "sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz", + "integrity": "sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-simple-access": "^7.12.13", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz", + "integrity": "sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.13.0", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-identifier": "^7.12.11", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz", + "integrity": "sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz", + "integrity": "sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz", + "integrity": "sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz", + "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/helper-replace-supers": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz", + "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz", + "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.13.10.tgz", + "integrity": "sha512-E+aCW9j7mLq01tOuGV08YzLBt+vSyr4bOPT75B6WrAlrUfmOYOZ/yWk847EH0dv0xXiCihWLEmlX//O30YhpIw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.13.tgz", + "integrity": "sha512-MprESJzI9O5VnJZrL7gg1MpdqmiFcUv41Jc7SahxYsNP2kDkFqClxxTZq+1Qv4AFCamm+GXMRDQINNn+qrxmiA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.13.12.tgz", + "integrity": "sha512-jcEI2UqIcpCqB5U5DRxIl0tQEProI2gcu+g8VTIqxLO5Iidojb4d77q+fwGseCvd8af/lJ9masp4QWzBXFE2xA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/types": "^7.13.12" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.17.tgz", + "integrity": "sha512-BPjYV86SVuOaudFhsJR1zjgxxOhJDt6JHNoD48DxWEIxUCAMjV1ys6DYw4SDYZh0b1QsS2vfIA9t/ZsQGsDOUQ==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.12.17" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.13.tgz", + "integrity": "sha512-FXYw98TTJ125GVCCkFLZXlZ1qGcsYqNQhVBQcZjyrwf8FEUtVfKIoidnO8S0q+KBQpDYNTmiGo1gn67Vti04lQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.13.tgz", + "integrity": "sha512-O5JJi6fyfih0WfDgIJXksSPhGP/G0fQpfxYy87sDc+1sFmsCS6wr3aAn+whbzkhbjtq4VMqLRaSzR6IsshIC0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz", + "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz", + "integrity": "sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==", + "dev": true, + "dependencies": { + "regenerator-transform": "^0.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz", + "integrity": "sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", + "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz", + "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz", + "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz", + "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz", + "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz", + "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.13.0.tgz", + "integrity": "sha512-elQEwluzaU8R8dbVuW2Q2Y8Nznf7hnjM7+DSCd14Lo5fF63C9qNLbwZYbmZrtV9/ySpSUpkRpQXvJb6xyu4hCQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-typescript": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz", + "integrity": "sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz", + "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.12.tgz", + "integrity": "sha512-JzElc6jk3Ko6zuZgBtjOd01pf9yYDEIH8BcqVuYIuOkzOwDesoa/Nz4gIo4lBG6K861KTV9TvIgmFuT6ytOaAA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.13.12", + "@babel/helper-compilation-targets": "^7.13.10", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-option": "^7.12.17", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.13.12", + "@babel/plugin-proposal-async-generator-functions": "^7.13.8", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-dynamic-import": "^7.13.8", + "@babel/plugin-proposal-export-namespace-from": "^7.12.13", + "@babel/plugin-proposal-json-strings": "^7.13.8", + "@babel/plugin-proposal-logical-assignment-operators": "^7.13.8", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-numeric-separator": "^7.12.13", + "@babel/plugin-proposal-object-rest-spread": "^7.13.8", + "@babel/plugin-proposal-optional-catch-binding": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/plugin-proposal-private-methods": "^7.13.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.13", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.12.13", + "@babel/plugin-transform-arrow-functions": "^7.13.0", + "@babel/plugin-transform-async-to-generator": "^7.13.0", + "@babel/plugin-transform-block-scoped-functions": "^7.12.13", + "@babel/plugin-transform-block-scoping": "^7.12.13", + "@babel/plugin-transform-classes": "^7.13.0", + "@babel/plugin-transform-computed-properties": "^7.13.0", + "@babel/plugin-transform-destructuring": "^7.13.0", + "@babel/plugin-transform-dotall-regex": "^7.12.13", + "@babel/plugin-transform-duplicate-keys": "^7.12.13", + "@babel/plugin-transform-exponentiation-operator": "^7.12.13", + "@babel/plugin-transform-for-of": "^7.13.0", + "@babel/plugin-transform-function-name": "^7.12.13", + "@babel/plugin-transform-literals": "^7.12.13", + "@babel/plugin-transform-member-expression-literals": "^7.12.13", + "@babel/plugin-transform-modules-amd": "^7.13.0", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/plugin-transform-modules-systemjs": "^7.13.8", + "@babel/plugin-transform-modules-umd": "^7.13.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.13", + "@babel/plugin-transform-new-target": "^7.12.13", + "@babel/plugin-transform-object-super": "^7.12.13", + "@babel/plugin-transform-parameters": "^7.13.0", + "@babel/plugin-transform-property-literals": "^7.12.13", + "@babel/plugin-transform-regenerator": "^7.12.13", + "@babel/plugin-transform-reserved-words": "^7.12.13", + "@babel/plugin-transform-shorthand-properties": "^7.12.13", + "@babel/plugin-transform-spread": "^7.13.0", + "@babel/plugin-transform-sticky-regex": "^7.12.13", + "@babel/plugin-transform-template-literals": "^7.13.0", + "@babel/plugin-transform-typeof-symbol": "^7.12.13", + "@babel/plugin-transform-unicode-escapes": "^7.12.13", + "@babel/plugin-transform-unicode-regex": "^7.12.13", + "@babel/preset-modules": "^0.1.4", + "@babel/types": "^7.13.12", + "babel-plugin-polyfill-corejs2": "^0.1.4", + "babel-plugin-polyfill-corejs3": "^0.1.3", + "babel-plugin-polyfill-regenerator": "^0.1.2", + "core-js-compat": "^3.9.0", + "semver": "^6.3.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.12.13.tgz", + "integrity": "sha512-gcEjiwcGHa3bo9idURBp5fmJPcyFPOszPQjztXrOjUE2wWVqc6fIVJPgWPIQksaQ5XZ2HWiRsf2s1fRGVjUtVw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-transform-flow-strip-types": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.13.tgz", + "integrity": "sha512-TYM0V9z6Abb6dj1K7i5NrEhA13oS5ujUYQYDfqIBXYHOc2c2VkFgc+q9kyssIyUfy4/hEwqrgSlJ/Qgv8zJLsA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-transform-react-display-name": "^7.12.13", + "@babel/plugin-transform-react-jsx": "^7.12.13", + "@babel/plugin-transform-react-jsx-development": "^7.12.12", + "@babel/plugin-transform-react-pure-annotations": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.13.0.tgz", + "integrity": "sha512-LXJwxrHy0N3f6gIJlYbLta1D9BDtHpQeqwzM0LIfjDlr6UE/D5Mc7W4iDiQzaE+ks0sTjT26ArcHWnJVt0QiHw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-option": "^7.12.17", + "@babel/plugin-transform-typescript": "^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.13.8.tgz", + "integrity": "sha512-yCVtABcmvQjRsX2elcZFUV5Q5kDDpHdtXKKku22hNDma60lYuhKmtp1ykZ/okRCPLT2bR5S+cA1kvtBdAFlDTQ==", + "dev": true, + "dependencies": { + "find-cache-dir": "^2.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "pirates": "^4.0.0", + "source-map-support": "^0.5.16" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", + "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.13.10.tgz", + "integrity": "sha512-x/XYVQ1h684pp1mJwOV4CyvqZXqbc8CMsMGUnAbuc82ZCdv1U63w5RSUzgDSXQHG5Rps/kiksH6g2D5BuaKyXg==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/@babel/template": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/traverse": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", + "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.0", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.13.0", + "@babel/types": "^7.13.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/types": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz", + "integrity": "sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "dependencies": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" + } + }, + "node_modules/@csstools/convert-colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", + "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@csstools/normalize.css": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", + "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==", + "dev": true + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dev": true, + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "dev": true, + "dependencies": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" + } + }, + "node_modules/@emotion/core": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.1.1.tgz", + "integrity": "sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@emotion/cache": "^10.0.27", + "@emotion/css": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/css": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", + "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", + "dev": true, + "dependencies": { + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3", + "babel-plugin-emotion": "^10.0.27" + } + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "dev": true + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "dev": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "dev": true + }, + "node_modules/@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "dev": true, + "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" + } + }, + "node_modules/@emotion/sheet": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==", + "dev": true + }, + "node_modules/@emotion/styled": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz", + "integrity": "sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==", + "dev": true, + "dependencies": { + "@emotion/styled-base": "^10.0.27", + "babel-plugin-emotion": "^10.0.27" + }, + "peerDependencies": { + "@emotion/core": "^10.0.27", + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/styled-base": { + "version": "10.0.31", + "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.0.31.tgz", + "integrity": "sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@emotion/is-prop-valid": "0.8.8", + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3" + }, + "peerDependencies": { + "@emotion/core": "^10.0.28", + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", + "dev": true + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "dev": true + }, + "node_modules/@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", + "dev": true + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==", + "dev": true + }, + "node_modules/@fullhuman/postcss-purgecss": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.3.0.tgz", + "integrity": "sha512-qnKm5dIOyPGJ70kPZ5jiz0I9foVOic0j+cOzNDoo8KoCf6HjicIZ99UfO2OmE7vCYSKAAepEwJtNzpiiZAh9xw==", + "dependencies": { + "postcss": "7.0.32", + "purgecss": "^2.3.0" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", + "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==", + "deprecated": "Moved to 'npm install @sideway/address'", + "dev": true + }, + "node_modules/@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==", + "deprecated": "This version has been deprecated and is no longer supported or maintained", + "dev": true + }, + "node_modules/@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==", + "deprecated": "This version has been deprecated and is no longer supported or maintained", + "dev": true + }, + "node_modules/@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "deprecated": "Switch to 'npm install joi'", + "dev": true, + "dependencies": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + } + }, + "node_modules/@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", + "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "deprecated": "This version has been deprecated and is no longer supported or maintained", + "dev": true, + "dependencies": { + "@hapi/hoek": "^8.3.0" + } + }, + "node_modules/@hypnosphi/create-react-context": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz", + "integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==", + "dependencies": { + "gud": "^1.0.0", + "warning": "^4.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": ">=0.14.0" + } + }, + "node_modules/@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", + "dev": true, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "dependencies": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "dependencies": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/core/node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@jest/core/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/core/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/core/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/core/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/core/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/core/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "dependencies": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "dependencies": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "dependencies": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@jest/transform/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/transform/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/transform/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/transform/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/transform/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/transform/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "dependencies": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.tgz", + "integrity": "sha512-+nb9vWloHNNMFHjGofEam3wopE3m1yuambrrd/fnPc+lFOMB9ROTqQlche9ByFWNkdNqfSgR/kkQtQ8DzEWt2w==", + "dev": true, + "optional": true, + "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" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@openreplay/sourcemap-uploader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@openreplay/sourcemap-uploader/-/sourcemap-uploader-3.0.0.tgz", + "integrity": "sha512-E1zQkHI9QZ0UYiBtPAweA9o0cuIWwQZfbc/tnUNdY9XF4S0MdIKGVqVh1Tkf4myzLxY4w/4il0ePLMZe1oXhfw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.10", + "glob-promise": "^3.4.0" + }, + "bin": { + "sourcemap-uploader": "cli.js" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz", + "integrity": "sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ==", + "dev": true, + "dependencies": { + "ansi-html": "^0.0.7", + "error-stack-parser": "^2.0.6", + "html-entities": "^1.2.1", + "native-url": "^0.2.6", + "schema-utils": "^2.6.5", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.x" + }, + "peerDependencies": { + "@types/webpack": "4.x", + "react-refresh": ">=0.8.3 <0.10.0", + "sockjs-client": "^1.4.0", + "type-fest": "^0.13.1", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@popperjs/core": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.1.tgz", + "integrity": "sha512-DvJbbn3dUgMxDnJLH+RZQPnXak1h4ZVYQ7CWiFWjQwBFkVajT4rfw2PdpHLTSTwxrYfnoEXkuBiwkDm6tPMQeA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@reach/router": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@reach/router/-/router-1.3.4.tgz", + "integrity": "sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA==", + "dev": true, + "dependencies": { + "create-react-context": "0.3.0", + "invariant": "^2.2.3", + "prop-types": "^15.6.1", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": "15.x || 16.x || 16.4.0-alpha.0911da3", + "react-dom": "15.x || 16.x || 16.4.0-alpha.0911da3" + } + }, + "node_modules/@semantic-ui-react/event-stack": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.2.tgz", + "integrity": "sha512-Yd0Qf7lPCIjzJ9bZYfurlNu2RDXT6KKSyubHfYK3WjRauhxCsq6Fk2LMRI9DEvShoEU+AsLSv3NGkqXAcVp0zg==", + "dependencies": { + "exenv": "^1.2.2", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0", + "react-dom": "^16.0.0 || ^17.0.0" + } + }, + "node_modules/@sentry/browser": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.30.0.tgz", + "integrity": "sha512-rOb58ZNVJWh1VuMuBG1mL9r54nZqKeaIlwSlvzJfc89vyfd7n6tQ1UXMN383QBz/MS5H5z44Hy5eE+7pCrYAfw==", + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/addons": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.1.21.tgz", + "integrity": "sha512-xo5TGu9EZVCqgh3D1veVnfuGzyKDWWsvOMo18phVqRxj21G3/+hScVyfIYwNTv7Ys5/Ahp9JxJUMXL3V3ny+tw==", + "dev": true, + "dependencies": { + "@storybook/api": "6.1.21", + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/router": "6.1.21", + "@storybook/theming": "6.1.21", + "core-js": "^3.0.1", + "global": "^4.3.2", + "regenerator-runtime": "^0.13.7" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/api": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.1.21.tgz", + "integrity": "sha512-QjZk70VSXMw/wPPoWdMp5Bl9VmkfmGhIz8PALrFLLEZHjzptpfZE2qkGEEJHG0NAksFUv6NxGki2/632dzR7Ug==", + "dev": true, + "dependencies": { + "@reach/router": "^1.3.3", + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/csf": "0.0.1", + "@storybook/router": "6.1.21", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.1.21", + "@types/reach__router": "^1.3.7", + "core-js": "^3.0.1", + "fast-deep-equal": "^3.1.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.7.1", + "telejson": "^5.0.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/channel-postmessage": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.1.21.tgz", + "integrity": "sha512-SuI/ffqcPT02VNda32k8V0D4XpLm5bIy8CLIs0OAnQg+zt5KjGBpQBngk3q4EaAiOoAhbMWAQiUzRUXfrgkgXg==", + "dev": true, + "dependencies": { + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/core-events": "6.1.21", + "core-js": "^3.0.1", + "global": "^4.3.2", + "qs": "^6.6.0", + "telejson": "^5.0.2" + } + }, + "node_modules/@storybook/channels": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.1.21.tgz", + "integrity": "sha512-7WoizMjyHqCyvcWncLexSg9FLPIErWAZL4NvluEthwsHSO2sDybn9mh1pzsFHdYMuTP6ml06Zt9ayWMtIveHDg==", + "dev": true, + "dependencies": { + "core-js": "^3.0.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "node_modules/@storybook/client-api": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.1.21.tgz", + "integrity": "sha512-uLFXQ5z1LLWYnw1w+YUJPzIPRVlwCCvM2Si37aHDZn1F3fnbMg+huEhEqIQ1TTTw3wiJoTeGuShYvqyaiNwq/w==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.1.21", + "@storybook/channel-postmessage": "6.1.21", + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/csf": "0.0.1", + "@types/qs": "^6.9.0", + "@types/webpack-env": "^1.15.3", + "core-js": "^3.0.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "memoizerific": "^1.11.3", + "qs": "^6.6.0", + "regenerator-runtime": "^0.13.7", + "stable": "^0.1.8", + "store2": "^2.7.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/client-logger": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.1.21.tgz", + "integrity": "sha512-QJV+gnVM2fQ4M7lSkRLCXkOw/RU+aEtUefo9TAnXxPHK3UGG+DyvLmha6fHGaz9GAcFxyWtgqCyVOhMe03Q35g==", + "dev": true, + "dependencies": { + "core-js": "^3.0.1", + "global": "^4.3.2" + } + }, + "node_modules/@storybook/components": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.1.21.tgz", + "integrity": "sha512-2NjkyS1yeYXlRY7azt88woqd6eqJA00oloIxgMAFLVpRmvFxoHalY61wNrvxl2QSu9cNofp984AbGc8gPbizBA==", + "dev": true, + "dependencies": { + "@popperjs/core": "^2.5.4", + "@storybook/client-logger": "6.1.21", + "@storybook/csf": "0.0.1", + "@storybook/theming": "6.1.21", + "@types/overlayscrollbars": "^1.9.0", + "@types/react-color": "^3.0.1", + "@types/react-syntax-highlighter": "11.0.4", + "core-js": "^3.0.1", + "fast-deep-equal": "^3.1.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "markdown-to-jsx": "^6.11.4", + "memoizerific": "^1.11.3", + "overlayscrollbars": "^1.10.2", + "polished": "^3.4.4", + "react-color": "^2.17.0", + "react-popper-tooltip": "^3.1.1", + "react-syntax-highlighter": "^13.5.0", + "react-textarea-autosize": "^8.1.1", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/core": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-6.1.21.tgz", + "integrity": "sha512-ITqSid3VVL5/fkx7Wwu7QfD2Y5xjl3V6p7yUpLSzP8GpBnCHKDvJ4pFJUdJlGQ0mnGz6ACa0qVnSc+V0hiy1sA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-decorators": "^7.12.1", + "@babel/plugin-proposal-export-default-from": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.1", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.1", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.1", + "@babel/preset-typescript": "^7.12.1", + "@babel/register": "^7.12.1", + "@storybook/addons": "6.1.21", + "@storybook/api": "6.1.21", + "@storybook/channel-postmessage": "6.1.21", + "@storybook/channels": "6.1.21", + "@storybook/client-api": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/components": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/csf": "0.0.1", + "@storybook/node-logger": "6.1.21", + "@storybook/router": "6.1.21", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.1.21", + "@storybook/ui": "6.1.21", + "@types/glob-base": "^0.3.0", + "@types/micromatch": "^4.0.1", + "@types/node-fetch": "^2.5.4", + "airbnb-js-shims": "^2.2.1", + "ansi-to-html": "^0.6.11", + "autoprefixer": "^9.7.2", + "babel-loader": "^8.0.6", + "babel-plugin-emotion": "^10.0.20", + "babel-plugin-macros": "^2.8.0", + "babel-preset-minify": "^0.5.0 || 0.6.0-alpha.5", + "better-opn": "^2.0.0", + "boxen": "^4.1.0", + "case-sensitive-paths-webpack-plugin": "^2.2.0", + "chalk": "^4.0.0", + "cli-table3": "0.6.0", + "commander": "^5.0.0", + "core-js": "^3.0.1", + "cpy": "^8.1.1", + "css-loader": "^3.5.3", + "detect-port": "^1.3.0", + "dotenv-webpack": "^1.7.0", + "ejs": "^3.1.2", + "express": "^4.17.0", + "file-loader": "^6.0.0", + "file-system-cache": "^1.0.5", + "find-up": "^4.1.0", + "fork-ts-checker-webpack-plugin": "^4.1.4", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "glob-base": "^0.3.0", + "glob-promise": "^3.4.0", + "global": "^4.3.2", + "html-webpack-plugin": "^4.2.1", + "inquirer": "^7.0.0", + "interpret": "^2.0.0", + "ip": "^1.1.5", + "json5": "^2.1.1", + "lazy-universal-dotenv": "^3.0.1", + "micromatch": "^4.0.2", + "node-fetch": "^2.6.0", + "pkg-dir": "^4.2.0", + "pnp-webpack-plugin": "1.6.4", + "postcss-flexbugs-fixes": "^4.1.0", + "postcss-loader": "^3.0.0", + "pretty-hrtime": "^1.0.3", + "qs": "^6.6.0", + "raw-loader": "^4.0.1", + "react-dev-utils": "^11.0.3", + "regenerator-runtime": "^0.13.7", + "resolve-from": "^5.0.0", + "serve-favicon": "^2.5.0", + "shelljs": "^0.8.4", + "stable": "^0.1.8", + "style-loader": "^1.2.1", + "telejson": "^5.0.2", + "terser-webpack-plugin": "^3.0.0", + "ts-dedent": "^2.0.0", + "unfetch": "^4.1.0", + "url-loader": "^4.0.0", + "util-deprecate": "^1.0.2", + "webpack": "^4.44.2", + "webpack-dev-middleware": "^3.7.0", + "webpack-filter-warnings-plugin": "^1.2.1", + "webpack-hot-middleware": "^2.25.0", + "webpack-virtual-modules": "^0.2.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/core-events": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.1.21.tgz", + "integrity": "sha512-KWqnh1C7M1pT//WfQb3AD60yTR8jL48AfaeLGto2gO9VK7VVgj/EGsrXZP/GTL90ygyExbbBI5gkr7EBTu/HYw==", + "dev": true, + "dependencies": { + "core-js": "^3.0.1" + } + }, + "node_modules/@storybook/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/core/node_modules/autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "dev": true, + "dependencies": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + }, + "node_modules/@storybook/core/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@storybook/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@storybook/core/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/core/node_modules/html-webpack-plugin": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz", + "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.20", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@storybook/core/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@storybook/core/node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "node_modules/@storybook/core/node_modules/postcss/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@storybook/core/node_modules/postcss/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@storybook/core/node_modules/postcss/node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@storybook/core/node_modules/postcss/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@storybook/core/node_modules/postcss/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/@storybook/core/node_modules/postcss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/core/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@storybook/core/node_modules/style-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", + "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@storybook/core/node_modules/style-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@storybook/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core/node_modules/supports-color/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/csf": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", + "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/@storybook/node-logger": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.1.21.tgz", + "integrity": "sha512-wQZZw4n1PG3kGOsczWCBC6+8RagYkrGYDqsVOpUcs5shGbPg5beCXDuzP4nxz2IlsoP9ZtTSaX741H791OIOjA==", + "dev": true, + "dependencies": { + "@types/npmlog": "^4.1.2", + "chalk": "^4.0.0", + "core-js": "^3.0.1", + "npmlog": "^4.1.2", + "pretty-hrtime": "^1.0.3" + } + }, + "node_modules/@storybook/node-logger/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/node-logger/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/node-logger/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@storybook/node-logger/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@storybook/node-logger/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/node-logger/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/react": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-6.1.21.tgz", + "integrity": "sha512-j3gq/ssWxRCCH5iCHbP3ihXSGS7lVWh1HpmBmGbbhHGHgdmSPsRjwDXiQGE81EmE7bzbC8NECBhU3zHJ6h1TvA==", + "dev": true, + "dependencies": { + "@babel/preset-flow": "^7.12.1", + "@babel/preset-react": "^7.12.1", + "@pmmmwh/react-refresh-webpack-plugin": "^0.4.2", + "@storybook/addons": "6.1.21", + "@storybook/core": "6.1.21", + "@storybook/node-logger": "6.1.21", + "@storybook/semver": "^7.3.2", + "@types/webpack-env": "^1.15.3", + "babel-plugin-add-react-displayname": "^0.0.5", + "babel-plugin-named-asset-import": "^0.3.1", + "babel-plugin-react-docgen": "^4.2.1", + "core-js": "^3.0.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "prop-types": "^15.7.2", + "react-dev-utils": "^11.0.3", + "react-docgen-typescript-plugin": "^0.6.2", + "react-refresh": "^0.8.3", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0", + "webpack": "^4.44.2" + }, + "bin": { + "build-storybook": "bin/build.js", + "start-storybook": "bin/index.js", + "storybook-server": "bin/index.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.5", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/router": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.1.21.tgz", + "integrity": "sha512-m75WvUhoCBWDVekICAdbkidji/w5hCjHo+M8L13UghpwXWEnyr4/QqvkOb/PcSC8aZzxeMqSCpRQ1o6LWULneg==", + "dev": true, + "dependencies": { + "@reach/router": "^1.3.3", + "@types/reach__router": "^1.3.7", + "core-js": "^3.0.1", + "global": "^4.3.2", + "memoizerific": "^1.11.3", + "qs": "^6.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==", + "dev": true, + "dependencies": { + "core-js": "^3.6.5", + "find-up": "^4.1.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/theming": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.1.21.tgz", + "integrity": "sha512-yq7+/mpdljRdSRJYw/In/9tnDGXIUDe//mhyMftFfrB2mq6zi1yAZpowCerWhiDE2ipGkrfzIYx/Sn7bcaXgqg==", + "dev": true, + "dependencies": { + "@emotion/core": "^10.1.1", + "@emotion/is-prop-valid": "^0.8.6", + "@emotion/styled": "^10.0.23", + "@storybook/client-logger": "6.1.21", + "core-js": "^3.0.1", + "deep-object-diff": "^1.1.0", + "emotion-theming": "^10.0.19", + "global": "^4.3.2", + "memoizerific": "^1.11.3", + "polished": "^3.4.4", + "resolve-from": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/ui": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/ui/-/ui-6.1.21.tgz", + "integrity": "sha512-2nRb5egnSBKbosuR7g5PsuM4XnRLXZUf7TBjwT6eRlomnE2wrWM5DtTLpFeUpDob0SI5hPlOV1xCpPz3XmeyyA==", + "dev": true, + "dependencies": { + "@emotion/core": "^10.1.1", + "@storybook/addons": "6.1.21", + "@storybook/api": "6.1.21", + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/components": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/router": "6.1.21", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.1.21", + "@types/markdown-to-jsx": "^6.11.0", + "copy-to-clipboard": "^3.0.8", + "core-js": "^3.0.1", + "core-js-pure": "^3.0.1", + "downshift": "^6.0.6", + "emotion-theming": "^10.0.19", + "fuse.js": "^3.6.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "markdown-to-jsx": "^6.11.4", + "memoizerific": "^1.11.3", + "polished": "^3.4.4", + "qs": "^6.6.0", + "react-draggable": "^4.0.3", + "react-helmet-async": "^1.0.2", + "react-hotkeys": "2.0.0", + "react-sizeme": "^2.6.7", + "regenerator-runtime": "^0.13.7", + "resolve-from": "^5.0.0", + "store2": "^2.7.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz", + "integrity": "sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz", + "integrity": "sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz", + "integrity": "sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz", + "integrity": "sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz", + "integrity": "sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz", + "integrity": "sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.3.tgz", + "integrity": "sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A==", + "dev": true, + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^4.2.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^4.2.0", + "@svgr/babel-plugin-svg-dynamic-title": "^4.3.3", + "@svgr/babel-plugin-svg-em-dimensions": "^4.2.0", + "@svgr/babel-plugin-transform-react-native-svg": "^4.2.0", + "@svgr/babel-plugin-transform-svg-component": "^4.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/core": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-4.3.3.tgz", + "integrity": "sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w==", + "dev": true, + "dependencies": { + "@svgr/plugin-jsx": "^4.3.3", + "camelcase": "^5.3.1", + "cosmiconfig": "^5.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/core/node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/core/node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/core/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/core/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/core/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz", + "integrity": "sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.4.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz", + "integrity": "sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w==", + "dev": true, + "dependencies": { + "@babel/core": "^7.4.5", + "@svgr/babel-preset": "^4.3.3", + "@svgr/hast-util-to-babel-ast": "^4.3.2", + "svg-parser": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz", + "integrity": "sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w==", + "dev": true, + "dependencies": { + "cosmiconfig": "^5.2.1", + "merge-deep": "^3.0.2", + "svgo": "^1.2.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@svgr/webpack": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.3.tgz", + "integrity": "sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.4.5", + "@babel/plugin-transform-react-constant-elements": "^7.0.0", + "@babel/preset-env": "^7.4.5", + "@babel/preset-react": "^7.0.0", + "@svgr/core": "^4.3.3", + "@svgr/plugin-jsx": "^4.3.3", + "@svgr/plugin-svgo": "^4.3.1", + "loader-utils": "^1.2.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", + "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", + "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/braces": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.0.tgz", + "integrity": "sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==", + "dev": true + }, + "node_modules/@types/component-emitter": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", + "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==" + }, + "node_modules/@types/d3": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.38.tgz", + "integrity": "sha1-dvjy6RWa5WKWWy+g5vvuGqZDobw=" + }, + "node_modules/@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@types/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-pYHWiDR+EOUN18F9byiAoQNUMZ0=", + "dev": true + }, + "node_modules/@types/hast": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.1.tgz", + "integrity": "sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==", + "dev": true + }, + "node_modules/@types/is-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.0.tgz", + "integrity": "sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "node_modules/@types/markdown-to-jsx": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz", + "integrity": "sha512-30nFYpceM/ZEvhGiqWjm5quLUxNeld0HCzJEXMZZDpq53FPkS85mTwkWtCXzCqq8s5JYLgM5W392a02xn8Bdaw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/micromatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.1.tgz", + "integrity": "sha512-my6fLBvpY70KattTNzYOK6KU1oR1+UCz9ug/JbcF5UrEmeCt9P7DV2t7L8+t18mMPINqGQCE4O8PLOPbI84gxw==", + "dev": true, + "dependencies": { + "@types/braces": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.14.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz", + "integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==", + "dev": true + }, + "node_modules/@types/node-fetch": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.8.tgz", + "integrity": "sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-4QQmOF5KlwfxJ5IGXFIudkeLCdMABz03RcUXu+LCb24zmln8QW6aDjuGl4d4XPVLf2j+FnjelHTP7dvceAFbhA==", + "dev": true + }, + "node_modules/@types/overlayscrollbars": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@types/overlayscrollbars/-/overlayscrollbars-1.12.0.tgz", + "integrity": "sha512-h/pScHNKi4mb+TrJGDon8Yb06ujFG0mSg12wIO0sWMUF3dQIe2ExRRdNRviaNt9IjxIiOfnRr7FsQAdHwK4sMg==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true + }, + "node_modules/@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", + "dev": true + }, + "node_modules/@types/reach__router": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.3.7.tgz", + "integrity": "sha512-cyBEb8Ef3SJNH5NYEIDGPoMMmYUxROatuxbICusVRQIqZUB85UCt6R2Ok60tKS/TABJsJYaHyNTW3kqbpxlMjg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz", + "integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-color": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.4.tgz", + "integrity": "sha512-EswbYJDF1kkrx93/YU+BbBtb46CCtDMvTiGmcOa/c5PETnwTiSWoseJ1oSWeRl/4rUXkhME9bVURvvPg0W5YQw==", + "dev": true, + "dependencies": { + "@types/react": "*", + "@types/reactcss": "*" + } + }, + "node_modules/@types/react-syntax-highlighter": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz", + "integrity": "sha512-9GfTo3a0PHwQeTVoqs0g5bS28KkSY48pp5659wA+Dp4MqceDEa8EHBqrllJvvtyusszyJhViUEap0FDvlk/9Zg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react/node_modules/csstype": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", + "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==", + "dev": true + }, + "node_modules/@types/reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-d2gQQ0IL6hXLnoRfVYZukQNWHuVsE75DzFTLPUuyyEhJS8G2VvlE+qfQQ91SJjaMqlURRCNIsX7Jcsw6cEuJlA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", + "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==", + "dev": true + }, + "node_modules/@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "node_modules/@types/tapable": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz", + "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", + "dev": true + }, + "node_modules/@types/uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/@types/uglify-js/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/unist": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", + "dev": true + }, + "node_modules/@types/webpack": { + "version": "4.41.26", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz", + "integrity": "sha512-7ZyTfxjCRwexh+EJFwRUM+CDB2XvgHl4vfuqf1ZKrgGvcS5BrNvPQqJh3tsZ0P6h6Aa1qClVHaJZszLPzpqHeA==", + "dev": true, + "dependencies": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + } + }, + "node_modules/@types/webpack-env": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.0.tgz", + "integrity": "sha512-Fx+NpfOO0CpeYX2g9bkvX8O5qh9wrU1sOF4g8sft4Mu7z+qfe387YlyY8w8daDyDsKY5vUxM0yxkAYnbkRbZEw==", + "dev": true + }, + "node_modules/@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + } + }, + "node_modules/@types/webpack/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/yargs": { + "version": "13.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.11.tgz", + "integrity": "sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "dev": true + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", + "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", + "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dev": true, + "dependencies": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "dependencies": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "peer": true, + "dependencies": { + "acorn": "^3.0.4" + } + }, + "node_modules/acorn-jsx/node_modules/acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-node/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-node/node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/add-dom-event-listener": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz", + "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==", + "dependencies": { + "object-assign": "4.x" + } + }, + "node_modules/address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", + "dev": true, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", + "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/airbnb-js-shims": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz", + "integrity": "sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "array.prototype.flatmap": "^1.2.1", + "es5-shim": "^4.5.13", + "es6-shim": "^0.35.5", + "function.prototype.name": "^1.1.0", + "globalthis": "^1.0.0", + "object.entries": "^1.1.0", + "object.fromentries": "^2.0.0 || ^1.0.0", + "object.getownpropertydescriptors": "^2.0.3", + "object.values": "^1.1.0", + "promise.allsettled": "^1.0.0", + "promise.prototype.finally": "^3.1.0", + "string.prototype.matchall": "^4.0.0 || ^3.0.1", + "string.prototype.padend": "^3.0.0", + "string.prototype.padstart": "^3.0.0", + "symbol.prototype.description": "^1.0.0" + } + }, + "node_modules/ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "peer": true, + "dependencies": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true, + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, + "node_modules/ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true, + "peer": true, + "peerDependencies": { + "ajv": "^5.0.0" + } + }, + "node_modules/ajv/node_modules/fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true, + "peer": true + }, + "node_modules/alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "node_modules/ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "dependencies": { + "string-width": "^3.0.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/ansi-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-bgblack": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgblack/-/ansi-bgblack-0.1.1.tgz", + "integrity": "sha1-poulAHiHcBtqr74/oNrf36juPKI=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgblue": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgblue/-/ansi-bgblue-0.1.1.tgz", + "integrity": "sha1-Z73ATtybm1J4lp2hlt6j11yMNhM=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgcyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgcyan/-/ansi-bgcyan-0.1.1.tgz", + "integrity": "sha1-WEiUJWAL3p9VBwaN2Wnr/bUP52g=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bggreen": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bggreen/-/ansi-bggreen-0.1.1.tgz", + "integrity": "sha1-TjGRJIUplD9DIelr8THRwTgWr0k=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgmagenta": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgmagenta/-/ansi-bgmagenta-0.1.1.tgz", + "integrity": "sha1-myhDLAduqpmUGGcqPvvhk5HCx6E=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgred": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgred/-/ansi-bgred-0.1.1.tgz", + "integrity": "sha1-p2+Sg4OCukMpCmwXeEJPmE1vEEE=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgwhite": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgwhite/-/ansi-bgwhite-0.1.1.tgz", + "integrity": "sha1-ZQRlE3elim7OzQMxmU5IAljhG6g=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgyellow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgyellow/-/ansi-bgyellow-0.1.1.tgz", + "integrity": "sha1-w/4usIzUdmSAKeaHTRWgs49h1E8=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-black": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-black/-/ansi-black-0.1.1.tgz", + "integrity": "sha1-9hheiJNgslRaHsUMC/Bj/EMDJFM=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-blue": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-blue/-/ansi-blue-0.1.1.tgz", + "integrity": "sha1-FbgEmQ6S/JyoxUds6PaZd3wh7b8=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bold": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bold/-/ansi-bold-0.1.1.tgz", + "integrity": "sha1-PmOVCvWswq4uZw5vZ96xFdGl9QU=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-colors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-0.2.0.tgz", + "integrity": "sha1-csMd4qDZoszQysMMyYI+6y9kNLU=", + "dev": true, + "dependencies": { + "ansi-bgblack": "^0.1.1", + "ansi-bgblue": "^0.1.1", + "ansi-bgcyan": "^0.1.1", + "ansi-bggreen": "^0.1.1", + "ansi-bgmagenta": "^0.1.1", + "ansi-bgred": "^0.1.1", + "ansi-bgwhite": "^0.1.1", + "ansi-bgyellow": "^0.1.1", + "ansi-black": "^0.1.1", + "ansi-blue": "^0.1.1", + "ansi-bold": "^0.1.1", + "ansi-cyan": "^0.1.1", + "ansi-dim": "^0.1.1", + "ansi-gray": "^0.1.1", + "ansi-green": "^0.1.1", + "ansi-grey": "^0.1.1", + "ansi-hidden": "^0.1.1", + "ansi-inverse": "^0.1.1", + "ansi-italic": "^0.1.1", + "ansi-magenta": "^0.1.1", + "ansi-red": "^0.1.1", + "ansi-reset": "^0.1.1", + "ansi-strikethrough": "^0.1.1", + "ansi-underline": "^0.1.1", + "ansi-white": "^0.1.1", + "ansi-yellow": "^0.1.1", + "lazy-cache": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-dim": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-dim/-/ansi-dim-0.1.1.tgz", + "integrity": "sha1-QN5MYDqoCG2Oeoa4/5mNXDbu/Ww=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "dependencies": { + "type-fest": "^0.11.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-green": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-green/-/ansi-green-0.1.1.tgz", + "integrity": "sha1-il2al55FjVfEDjNYCzc5C44Q0Pc=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-grey": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-grey/-/ansi-grey-0.1.1.tgz", + "integrity": "sha1-WdmLasK6GfilF5jphT+6eDOaM8E=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-hidden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-hidden/-/ansi-hidden-0.1.1.tgz", + "integrity": "sha1-7WpMSY0rt8uyidvyqNHcyFZ/rg8=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-inverse": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-inverse/-/ansi-inverse-0.1.1.tgz", + "integrity": "sha1-tq9Fgm/oJr+1KKbHmIV5Q1XM0mk=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-italic": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-italic/-/ansi-italic-0.1.1.tgz", + "integrity": "sha1-EEdDRj9iXBQqA2c5z4XtpoiYbyM=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-magenta": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-magenta/-/ansi-magenta-0.1.1.tgz", + "integrity": "sha1-BjtboW+z8j4c/aKwfAqJ3hHkMK4=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-reset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-reset/-/ansi-reset-0.1.1.tgz", + "integrity": "sha1-5+cSksPH3c1NYu9KbHwFmAkRw7c=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-strikethrough": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-strikethrough/-/ansi-strikethrough-0.1.1.tgz", + "integrity": "sha1-2Eh3FAss/wfRyT685pkE9oiF5Wg=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-to-html": { + "version": "0.6.14", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.14.tgz", + "integrity": "sha512-7ZslfB1+EnFSDO5Ju+ue5Y6It19DRnZXWv8jrGHgIlPna5Mh4jz7BV5jCbQneXNFurQcKoolaaAjHtgSBfOIuA==", + "dev": true, + "dependencies": { + "entities": "^1.1.2" + }, + "bin": { + "ansi-to-html": "bin/ansi-to-html" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ansi-underline": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-underline/-/ansi-underline-0.1.1.tgz", + "integrity": "sha1-38kg9Ml7WXfqFi34/7mIMIqqcaQ=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-white": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-white/-/ansi-white-0.1.1.tgz", + "integrity": "sha1-nHe3wZPF7pkuYBHTbsTJIbRXiUQ=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-yellow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-yellow/-/ansi-yellow-0.1.1.tgz", + "integrity": "sha1-y5NW8vRscy8OMZnmEClVp32oPB0=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/anymatch/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/app-root-dir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", + "integrity": "sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg=", + "dev": true + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=", + "dev": true + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-swap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arr-swap/-/arr-swap-1.0.1.tgz", + "integrity": "sha1-FHWQ7WX8gVvAf+8Jl8Llgj1kNTQ=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.map": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.3.tgz", + "integrity": "sha512-nNcb30v0wfDyIe26Yif3PcV1JXQp4zEeEfupG7L4SRjnD6HLbO5b2a7eVSba53bOx4YCHYMBHt+Fp4vYstneRA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "node_modules/ast-types/node_modules/tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", + "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", + "dev": true, + "dependencies": { + "browserslist": "^2.11.3", + "caniuse-lite": "^1.0.30000805", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^6.0.17", + "postcss-value-parser": "^3.2.3" + }, + "bin": { + "autoprefixer-info": "bin/autoprefixer-info" + } + }, + "node_modules/autoprefixer/node_modules/browserslist": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", + "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", + "deprecated": "Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30000792", + "electron-to-chromium": "^1.3.30" + }, + "bin": { + "browserslist": "cli.js" + } + }, + "node_modules/aws-sdk": { + "version": "2.870.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.870.0.tgz", + "integrity": "sha512-pbNO+RuEx45aaEZind0Tl9NADxncLJf0mRAwof0szyYMB+FZm165yz7FCxFLumU4R9qw8vOG5YFACBaNoQkJdg==", + "dev": true, + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/axe-core": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.3.tgz", + "integrity": "sha512-vwPpH4Aj4122EW38mxO/fxhGKtwWTMLDIJfZ1He0Edbtjcfna/R3YB67yVhezUMzqc3Jr3+Ii50KRntlENL4xQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "node_modules/babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "node_modules/babel-code-frame/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "node_modules/babel-code-frame/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dev": true, + "peer": true, + "dependencies": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + } + }, + "node_modules/babel-core/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/babel-core/node_modules/json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/babel-core/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "node_modules/babel-core/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-core/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": ">= 4.12.1" + } + }, + "node_modules/babel-extract-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", + "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", + "dev": true, + "dependencies": { + "babylon": "^6.18.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "peer": true, + "dependencies": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + } + }, + "node_modules/babel-generator/node_modules/jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true, + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/babel-generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-helper-evaluate-path": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", + "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", + "dev": true + }, + "node_modules/babel-helper-flip-expressions": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", + "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", + "dev": true + }, + "node_modules/babel-helper-is-nodes-equiv": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", + "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", + "dev": true + }, + "node_modules/babel-helper-is-void-0": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", + "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", + "dev": true + }, + "node_modules/babel-helper-mark-eval-scopes": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", + "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", + "dev": true + }, + "node_modules/babel-helper-remove-or-void": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", + "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", + "dev": true + }, + "node_modules/babel-helper-to-multiple-sequence-expressions": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", + "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==", + "dev": true + }, + "node_modules/babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "peer": true, + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "node_modules/babel-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "dev": true, + "dependencies": { + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-loader": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz", + "integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^1.4.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/babel-loader/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "peer": true, + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-add-react-displayname": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz", + "integrity": "sha1-M51M3be2X9YtHfnbn+BN4TQSK9U=", + "dev": true + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-emotion": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", + "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", + "dev": true, + "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" + } + }, + "node_modules/babel-plugin-emotion/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "dev": true, + "dependencies": { + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "node_modules/babel-plugin-minify-builtins": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", + "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==", + "dev": true + }, + "node_modules/babel-plugin-minify-constant-folding": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", + "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==", + "dev": true, + "dependencies": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "node_modules/babel-plugin-minify-dead-code-elimination": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", + "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", + "dev": true, + "dependencies": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-mark-eval-scopes": "^0.4.3", + "babel-helper-remove-or-void": "^0.4.3", + "lodash": "^4.17.11" + } + }, + "node_modules/babel-plugin-minify-flip-comparisons": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", + "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", + "dev": true, + "dependencies": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "node_modules/babel-plugin-minify-guarded-expressions": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", + "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", + "dev": true, + "dependencies": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3" + } + }, + "node_modules/babel-plugin-minify-infinity": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", + "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", + "dev": true + }, + "node_modules/babel-plugin-minify-mangle-names": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", + "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", + "dev": true, + "dependencies": { + "babel-helper-mark-eval-scopes": "^0.4.3" + } + }, + "node_modules/babel-plugin-minify-numeric-literals": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", + "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", + "dev": true + }, + "node_modules/babel-plugin-minify-replace": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", + "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==", + "dev": true + }, + "node_modules/babel-plugin-minify-simplify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", + "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==", + "dev": true, + "dependencies": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3", + "babel-helper-is-nodes-equiv": "^0.0.1", + "babel-helper-to-multiple-sequence-expressions": "^0.5.0" + } + }, + "node_modules/babel-plugin-minify-type-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", + "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", + "dev": true, + "dependencies": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "node_modules/babel-plugin-module-resolver": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz", + "integrity": "sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA==", + "dev": true, + "peer": true, + "dependencies": { + "find-babel-config": "^1.1.0", + "glob": "^7.1.2", + "pkg-up": "^2.0.0", + "reselect": "^3.0.1", + "resolve": "^1.4.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/babel-plugin-named-asset-import": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz", + "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==", + "dev": true, + "peerDependencies": { + "@babel/core": "^7.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz", + "integrity": "sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.13.0", + "@babel/helper-define-polyfill-provider": "^0.1.5", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz", + "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.1.5", + "core-js-compat": "^3.8.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz", + "integrity": "sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.1.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-react-docgen": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz", + "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.14.2", + "lodash": "^4.17.15", + "react-docgen": "^5.0.0" + } + }, + "node_modules/babel-plugin-recharts": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-recharts/-/babel-plugin-recharts-1.2.1.tgz", + "integrity": "sha512-bIPmjP3TrF2RJk0jDBG+91aTVyLuK48T4Nqekvs/B6MdzPmHXBKB+q+8xXCSRth08Wck+X5ylgSTcr3Ab1egvw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.1.0", + "babylon": "^6.18.0" + } + }, + "node_modules/babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "dev": true + }, + "node_modules/babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "node_modules/babel-plugin-transform-inline-consecutive-adds": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", + "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", + "dev": true + }, + "node_modules/babel-plugin-transform-member-expression-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", + "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", + "dev": true + }, + "node_modules/babel-plugin-transform-merge-sibling-variables": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", + "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", + "dev": true + }, + "node_modules/babel-plugin-transform-minify-booleans": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", + "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", + "dev": true + }, + "node_modules/babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "dev": true, + "dependencies": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "node_modules/babel-plugin-transform-property-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", + "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + } + }, + "node_modules/babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", + "dev": true + }, + "node_modules/babel-plugin-transform-regexp-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", + "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", + "dev": true + }, + "node_modules/babel-plugin-transform-remove-console": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", + "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", + "dev": true + }, + "node_modules/babel-plugin-transform-remove-debugger": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", + "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", + "dev": true + }, + "node_modules/babel-plugin-transform-remove-undefined": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", + "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==", + "dev": true, + "dependencies": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "node_modules/babel-plugin-transform-simplify-comparison-operators": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", + "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", + "dev": true + }, + "node_modules/babel-plugin-transform-undefined-to-void": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", + "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", + "dev": true + }, + "node_modules/babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-minify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", + "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", + "dev": true, + "dependencies": { + "babel-plugin-minify-builtins": "^0.5.0", + "babel-plugin-minify-constant-folding": "^0.5.0", + "babel-plugin-minify-dead-code-elimination": "^0.5.1", + "babel-plugin-minify-flip-comparisons": "^0.4.3", + "babel-plugin-minify-guarded-expressions": "^0.4.4", + "babel-plugin-minify-infinity": "^0.4.3", + "babel-plugin-minify-mangle-names": "^0.5.0", + "babel-plugin-minify-numeric-literals": "^0.4.3", + "babel-plugin-minify-replace": "^0.5.0", + "babel-plugin-minify-simplify": "^0.5.1", + "babel-plugin-minify-type-constructors": "^0.4.3", + "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", + "babel-plugin-transform-member-expression-literals": "^6.9.4", + "babel-plugin-transform-merge-sibling-variables": "^6.9.4", + "babel-plugin-transform-minify-booleans": "^6.9.4", + "babel-plugin-transform-property-literals": "^6.9.4", + "babel-plugin-transform-regexp-constructors": "^0.4.3", + "babel-plugin-transform-remove-console": "^6.9.4", + "babel-plugin-transform-remove-debugger": "^6.9.4", + "babel-plugin-transform-remove-undefined": "^0.5.0", + "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", + "babel-plugin-transform-undefined-to-void": "^6.9.4", + "lodash": "^4.17.11" + } + }, + "node_modules/babel-preset-react-app": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.1.2.tgz", + "integrity": "sha512-k58RtQOKH21NyKtzptoAvtAODuAJJs3ZhqBMl456/GnXEQ/0La92pNmwgWoMn5pBTrsvk3YYXdY7zpY4e3UIxA==", + "dev": true, + "dependencies": { + "@babel/core": "7.9.0", + "@babel/plugin-proposal-class-properties": "7.8.3", + "@babel/plugin-proposal-decorators": "7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3", + "@babel/plugin-proposal-numeric-separator": "7.8.3", + "@babel/plugin-proposal-optional-chaining": "7.9.0", + "@babel/plugin-transform-flow-strip-types": "7.9.0", + "@babel/plugin-transform-react-display-name": "7.8.3", + "@babel/plugin-transform-runtime": "7.9.0", + "@babel/preset-env": "7.9.0", + "@babel/preset-react": "7.9.1", + "@babel/preset-typescript": "7.9.0", + "@babel/runtime": "7.9.0", + "babel-plugin-macros": "2.8.0", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-proposal-decorators": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz", + "integrity": "sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-decorators": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", + "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", + "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz", + "integrity": "sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-flow": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz", + "integrity": "sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/preset-env": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz", + "integrity": "sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.9.0", + "@babel/helper-compilation-targets": "^7.8.7", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.9.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.9.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.9.0", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.9.0", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.9.0", + "@babel/plugin-transform-modules-commonjs": "^7.9.0", + "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-umd": "^7.9.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.7", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.9.0", + "browserslist": "^4.9.1", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/preset-react": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.1.tgz", + "integrity": "sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-react-display-name": "^7.8.3", + "@babel/plugin-transform-react-jsx": "^7.9.1", + "@babel/plugin-transform-react-jsx-development": "^7.9.0", + "@babel/plugin-transform-react-jsx-self": "^7.9.0", + "@babel/plugin-transform-react-jsx-source": "^7.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/preset-typescript": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz", + "integrity": "sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-typescript": "^7.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.0.tgz", + "integrity": "sha512-cTIudHnzuWLS56ik4DnRnqqNf8MkdUzV4iFFI1h7Jo9xvrpQROYaAnaSd2mHLQAzzZAPfATynX5ord6YlNYNMA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/babel-preset-react-app/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/babel-preset-react-app/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "peer": true, + "dependencies": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + } + }, + "node_modules/babel-register/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.", + "dev": true, + "hasInstallScript": true, + "peer": true + }, + "node_modules/babel-register/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-register/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "peer": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/babel-runtime/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.", + "hasInstallScript": true + }, + "node_modules/babel-runtime/node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "node_modules/babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "peer": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "peer": true, + "dependencies": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-traverse/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/babel-traverse/node_modules/globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-traverse/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "node_modules/babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "peer": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "node_modules/babel-types/node_modules/to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true, + "bin": { + "babylon": "bin/babylon.js" + } + }, + "node_modules/backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base16": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", + "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=" + }, + "node_modules/base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "node_modules/batch-processor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz", + "integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/better-opn": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", + "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==", + "dev": true, + "dependencies": { + "open": "^7.0.3" + }, + "engines": { + "node": ">8.0.0" + } + }, + "node_modules/bfj": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", + "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.5", + "check-types": "^8.0.3", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/block-stream2": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.1.0.tgz", + "integrity": "sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.4.0" + } + }, + "node_modules/block-stream2/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "node_modules/bonjour/node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/boxen/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/brfs": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", + "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", + "dependencies": { + "quote-stream": "^1.0.1", + "resolve": "^1.1.5", + "static-module": "^2.2.0", + "through2": "^2.0.0" + }, + "bin": { + "brfs": "bin/cmd.js" + } + }, + "node_modules/brfs/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "dependencies": { + "resolve": "1.1.7" + } + }, + "node_modules/browser-resolve/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "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" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dev": true, + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz", + "integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==", + "dependencies": { + "caniuse-lite": "^1.0.30001181", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.649", + "escalade": "^3.1.1", + "node-releases": "^1.1.70" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "node_modules/buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "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" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cache-base/node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/calendar": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/calendar/-/calendar-0.1.1.tgz", + "integrity": "sha512-CExn+MxSU1pCsjYiS+Cx8d1MtIZqezxRhpIu8odr1oqvYG/0C1m8lvehHxTl1FslgKbOD7Z5QuEcyk8sGgpZLQ==" + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "peer": true, + "dependencies": { + "callsites": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caller-path/node_modules/callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001204", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001204.tgz", + "integrity": "sha512-JUdjWpcxfJ9IPamy2f5JaRDCaqJOxDzOSKtbdx4rH9VivMd1vIzoPumsJa9LoMIi4Fx2BV2KZOxWhNkBjaYivQ==" + }, + "node_modules/capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "dependencies": { + "rsvp": "^4.8.4" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/check-types": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", + "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==", + "dev": true + }, + "node_modules/choices-separator": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/choices-separator/-/choices-separator-2.0.0.tgz", + "integrity": "sha1-kv0XYxgteQM/XFxR0Lo1LlVnxpY=", + "dev": true, + "dependencies": { + "ansi-dim": "^0.1.1", + "debug": "^2.6.6", + "strip-color": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/choices-separator/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/choices-separator/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" + } + }, + "node_modules/chokidar/node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/chokidar/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chokidar/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/chokidar/node_modules/readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/chokidar/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/circular-dependency-plugin": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz", + "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "webpack": ">=4.0.1" + } + }, + "node_modules/circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "deprecated": "CircularJSON is in maintenance only, flatted is its successor.", + "dev": true, + "peer": true + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, + "node_modules/clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dependencies": { + "exit": "0.1.2", + "glob": "^7.1.1" + }, + "engines": { + "node": ">=0.2.5" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", + "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/clipboard": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz", + "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==", + "dev": true, + "optional": true, + "dependencies": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-1.0.0.tgz", + "integrity": "sha512-hmJRX8x1QOJVV+GUjOBzi6iauhPqc9hIF6xitWRBbiPZOBb6vGo/mDRIK9P74RTKSQK7AE8B0DDWY/vpRrPmQw==", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^5.0.0", + "shallow-clone": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone-deep/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/codemirror": { + "version": "5.60.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.60.0.tgz", + "integrity": "sha512-AEL7LhFOlxPlCL8IdTcJDblJm8yrAGib7I+DErJPdZd4l6imx8IMgKK3RblVgBQqz3TZJR4oknQ03bz+uNjBYA==" + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", + "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", + "dependencies": { + "color-convert": "^1.9.1", + "color-string": "^1.5.4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/color-string": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", + "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "dev": true, + "dependencies": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "node_modules/colorspace/node_modules/color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/component-classes": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz", + "integrity": "sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=", + "dependencies": { + "component-indexof": "0.0.3" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/component-indexof": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz", + "integrity": "sha1-EdCRMSI5648yyPJa6csAL/6NPCQ=" + }, + "node_modules/compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", + "dev": true, + "dependencies": { + "arity-n": "^1.0.4" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/compute-scroll-into-view": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", + "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dependencies": { + "date-now": "^0.1.4" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "node_modules/contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "node_modules/copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "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" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz", + "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz", + "integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==", + "dev": true, + "dependencies": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "webpack-log": "^2.0.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/core-js": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.9.1.tgz", + "integrity": "sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.9.1.tgz", + "integrity": "sha512-jXAirMQxrkbiiLsCx9bQPJFA6llDadKMpYrBJQJ3/c4/vsPP/fAf29h24tviRlvwUL6AmY5CHLu2GvjuYviQqA==", + "dev": true, + "dependencies": { + "browserslist": "^4.16.3", + "semver": "7.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-js-pure": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.9.1.tgz", + "integrity": "sha512-laz3Zx0avrw9a4QEIdmIblnVuJz8W51leY9iLThatCsFawWxC3sE4guASC78JbCin+DkwMpCdp1AVAuzL/GN7A==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/country-data": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/country-data/-/country-data-0.0.31.tgz", + "integrity": "sha1-gJZrjh0Uf6bWpYnTKTP4eTd0lW0=", + "dev": true, + "dependencies": { + "currency-symbol-map": "~2", + "underscore": ">1.4.4" + } + }, + "node_modules/cp-file": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz", + "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "nested-error-stacks": "^2.0.0", + "p-event": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cp-file/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-8.1.2.tgz", + "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==", + "dev": true, + "dependencies": { + "arrify": "^2.0.1", + "cp-file": "^7.0.0", + "globby": "^9.2.0", + "has-glob": "^1.0.0", + "junk": "^3.1.0", + "nested-error-stacks": "^2.1.0", + "p-all": "^2.1.0", + "p-filter": "^2.1.0", + "p-map": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy/node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cpy/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpy/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpy/node_modules/fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "dependencies": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/cpy/node_modules/globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cpy/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/cpy/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpy/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpy/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpy/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "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" + } + }, + "node_modules/create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "dependencies": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/create-react-context": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz", + "integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==", + "dev": true, + "dependencies": { + "gud": "^1.0.0", + "warning": "^4.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": "^0.14.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.2.tgz", + "integrity": "sha512-+JhD65rDNqLbGmB3Gzs3HrEKC0aQnD+XA3SY6RjgkF88jV2q5cTc5+CwxlS3sdmLk98gpPt5CF9XRnPdlxZe6w==", + "dependencies": { + "node-fetch": "2.6.1" + } + }, + "node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/cross-spawn/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "peer": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/cross-spawn/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true, + "peer": true + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, + "node_modules/css-animation": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.6.1.tgz", + "integrity": "sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog==", + "dependencies": { + "babel-runtime": "6.x", + "component-classes": "^1.2.5" + } + }, + "node_modules/css-blank-pseudo": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", + "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "dev": true, + "dependencies": { + "postcss": "^7.0.5" + }, + "bin": { + "css-blank-pseudo": "cli.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/css-blank-pseudo/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/css-blank-pseudo/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-blank-pseudo/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + }, + "engines": { + "node": ">4" + } + }, + "node_modules/css-declaration-sorter/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/css-declaration-sorter/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-declaration-sorter/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/css-has-pseudo": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", + "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^5.0.0-rc.4" + }, + "bin": { + "css-has-pseudo": "cli.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/css-has-pseudo/node_modules/cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "dependencies": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-has-pseudo/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-has-pseudo/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/css-loader/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/css-loader/node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "node_modules/css-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-loader/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", + "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.5" + }, + "bin": { + "css-prefers-color-scheme": "cli.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/css-prefers-color-scheme/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/css-prefers-color-scheme/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-prefers-color-scheme/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "dependencies": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" + }, + "node_modules/css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssdb": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", + "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-preset-default/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/cssnano-preset-default/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssnano-preset-default/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-raw-cache/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/cssnano-util-raw-cache/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssnano-util-raw-cache/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano/node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano/node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/cssnano/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssnano/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", + "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/csso/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "dev": true, + "dependencies": { + "cssom": "0.3.x" + } + }, + "node_modules/csstype": { + "version": "2.6.16", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.16.tgz", + "integrity": "sha512-61FBWoDHp/gRtsoDkq/B1nWrCUG/ok1E3tUrcNbZjsE9Cxd9yzUirjS3+nAATB8U4cTtaQmAHbNndoFz5L6C9Q==", + "dev": true + }, + "node_modules/currency-symbol-map": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/currency-symbol-map/-/currency-symbol-map-2.2.0.tgz", + "integrity": "sha1-KzwYcv8aws5ZXYJz5Y4f/wJyrqI=", + "dev": true + }, + "node_modules/cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" + }, + "node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "node_modules/d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + }, + "node_modules/d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + }, + "node_modules/d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" + }, + "node_modules/d3-geo-projection": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-0.2.16.tgz", + "integrity": "sha1-SZTs0QM92xUztsTFUoocgdzClCc=", + "dependencies": { + "brfs": "^1.3.0" + } + }, + "node_modules/d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "dependencies": { + "d3-color": "1" + } + }, + "node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/d3-queue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-2.0.3.tgz", + "integrity": "sha1-B/vaOsrlNYqcUpmq+ICt8JU+0sI=" + }, + "node_modules/d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "dependencies": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" + }, + "node_modules/d3-time-format": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "dependencies": { + "d3-time": "1" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/datamaps": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/datamaps/-/datamaps-0.5.9.tgz", + "integrity": "sha512-GUXpO713URNzaExVUgBtqA5fr2UuxUG/fVitI04zEFHVL2FHSjd672alHq8E16oQqRNzF0m1bmx8WlTnDrGSqQ==", + "dependencies": { + "@types/d3": "3.5.38", + "d3": "^3.5.6", + "topojson": "^1.6.19" + } + }, + "node_modules/date-fns": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.19.0.tgz", + "integrity": "sha512-X3bf2iTPgCAQp9wvjOQytnf5vO5rESYRXlPIVcgSbtT5OTScPcsf9eZU+B/YIkKAtYr5WeCii58BgATrNitlWg==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + }, + "node_modules/deasync": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.21.tgz", + "integrity": "sha512-kUmM8Y+PZpMpQ+B4AuOW9k2Pfx/mSupJtxOsLzmnHY2WqZUYRFccFn2RhzPAqt3Xb+sorK/badW2D4zNzqZz5w==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^1.7.1" + }, + "engines": { + "node": ">=0.11.0" + } + }, + "node_modules/deasync-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deasync-promise/-/deasync-promise-1.0.1.tgz", + "integrity": "sha1-KyfeR4Fnr07zS6mYecUuwM7dYcI=", + "dev": true, + "dependencies": { + "deasync": "^0.1.7" + } + }, + "node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-diff": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz", + "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==" + }, + "node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "node_modules/deep-object-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.0.tgz", + "integrity": "sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==", + "dev": true + }, + "node_modules/default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "dependencies": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "dev": true, + "optional": true + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/deploy-aws-s3-cloudfront": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/deploy-aws-s3-cloudfront/-/deploy-aws-s3-cloudfront-3.3.0.tgz", + "integrity": "sha512-QSV7+sGnMby3iOEdFFRFB4GInjtov8DsJkVhtJKvjiQzuPz/Yd6joBHWlSEoldA1dSeTnP8MUOn5pVLALg+B8Q==", + "dev": true, + "dependencies": { + "aws-sdk": "2", + "fast-glob": "3", + "md5-file": "5", + "micromatch": "4", + "mime-types": "2", + "prompt-confirm": "2", + "winston": "3", + "yargs": "16" + }, + "bin": { + "deploy-aws-s3-cloudfront": "bin/deploy-aws-s3-cloudfront" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "peer": true, + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-node": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.5.tgz", + "integrity": "sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==", + "dev": true + }, + "node_modules/detect-port": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", + "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", + "dev": true, + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dev": true, + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/detect-port/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "dependencies": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "dependencies": { + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/disposables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/disposables/-/disposables-1.0.2.tgz", + "integrity": "sha1-NsamdEdfVaLWkTVnpgFETkh7S24=" + }, + "node_modules/dnd-core": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-2.6.0.tgz", + "integrity": "sha1-ErrWbVh0LG5ffPKUP7aFlED4CcQ=", + "dependencies": { + "asap": "^2.0.6", + "invariant": "^2.0.0", + "lodash": "^4.2.0", + "redux": "^3.7.1" + } + }, + "node_modules/dnd-core/node_modules/redux": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", + "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", + "dependencies": { + "lodash": "^4.2.1", + "lodash-es": "^4.2.1", + "loose-envify": "^1.1.0", + "symbol-observable": "^1.0.3" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "node_modules/dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "dependencies": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "dependencies": { + "buffer-indexof": "^1.0.0" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-align": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.0.tgz", + "integrity": "sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA==" + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", + "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-helpers/node_modules/csstype": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", + "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==" + }, + "node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true, + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "node_modules/domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "dependencies": { + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-case/node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/dot-case/node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-case/node_modules/tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/dotenv-defaults": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-1.1.1.tgz", + "integrity": "sha512-6fPRo9o/3MxKvmRZBD3oNFdxODdhJtIy1zcJeUSCs6HCy4tarUpd+G67UTU9tF6OWXeSPqsm4fPAB+2eY9Rt9Q==", + "dev": true, + "dependencies": { + "dotenv": "^6.2.0" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "node_modules/dotenv-webpack": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-1.8.0.tgz", + "integrity": "sha512-o8pq6NLBehtrqA8Jv8jFQNtG9nhRtVqmoD4yWbgUyoU3+9WBlPe+c2EAiaJok9RB28QvrWvdWLZGeTT5aATDMg==", + "dev": true, + "dependencies": { + "dotenv-defaults": "^1.0.2" + }, + "peerDependencies": { + "webpack": "^1 || ^2 || ^3 || ^4" + } + }, + "node_modules/downshift": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.1.tgz", + "integrity": "sha512-ch8Sh/j7gVqQd7Kcv3A5TkGfldmxmlQrRPZJYWEhzh24+h7WA4vXssuhcGNJrD8YPJlZYQGHcaX8BNhS0IcOvg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "compute-scroll-into-view": "^1.0.17", + "prop-types": "^15.7.2", + "react-is": "^17.0.1" + }, + "peerDependencies": { + "react": ">=16.12.0" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "node_modules/ejs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "dev": true, + "dependencies": { + "jake": "^10.6.1" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.3.698", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.698.tgz", + "integrity": "sha512-VEXDzYblnlT+g8Q3gedwzgKOso1evkeJzV8lih7lV8mL8eAnGVnKyC3KsFT6S+R5PQO4ffdr1PI16/ElibY/kQ==" + }, + "node_modules/element-resize-detector": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.2.tgz", + "integrity": "sha512-+LOXRkCJc4I5WhEJxIDjhmE3raF8jtOMBDqSCgZTMz2TX3oXAX5pE2+MDeopJlGdXzP7KzPbBJaUGfNaP9HG4A==", + "dev": true, + "dependencies": { + "batch-processor": "1.0.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/emotion-theming": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/emotion-theming/-/emotion-theming-10.0.27.tgz", + "integrity": "sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@emotion/weak-memoize": "0.2.5", + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "@emotion/core": "^10.0.27", + "react": ">=16.3.0" + } + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/endent": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.0.1.tgz", + "integrity": "sha512-mADztvcC+vCk4XEZaCz6xIPO2NHQuprv5CAEjuVAu6aZwqAj7nVNlMyl1goPFYqCCpS2OJV9jwpumJLkotZrNw==", + "dev": true, + "dependencies": { + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.4" + } + }, + "node_modules/engine.io-client": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.1.2.tgz", + "integrity": "sha512-1mwvwKYMa0AaCy+sPgvJ/SnKyO5MJZ1HEeXfA3Rm/KHkHGiYD5bQVq8QzvIrkI01FuVtOdZC5lWdRw1BGXB2NQ==", + "dependencies": { + "base64-arraybuffer": "0.1.4", + "component-emitter": "~1.3.0", + "debug": "~4.3.1", + "engine.io-parser": "~4.0.1", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz", + "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==", + "dependencies": { + "base64-arraybuffer": "0.1.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/enhanced-resolve/node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.1.1" + } + }, + "node_modules/error-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/error-symbol/-/error-symbol-0.1.0.tgz", + "integrity": "sha1-Ck2uN9YA0VopukU9jvkg8YRDM/Y=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "node_modules/es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dependencies": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "node_modules/es5-shim": { + "version": "4.5.15", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.15.tgz", + "integrity": "sha512-FYpuxEjMeDvU4rulKqFdukQyZSTpzhg4ScQHrAosrlVpR6GFyaw14f74yn2+4BugniIS0Frpg7TvwZocU4ZMTw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-shim": { + "version": "0.35.6", + "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.6.tgz", + "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==", + "dev": true + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-airbnb": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz", + "integrity": "sha512-zLyOhVWhzB/jwbz7IPSbkUuj7X2ox4PHXTcZkEmDqTvd0baJmJyuxlFPDlZOE/Y5bC+HQRaEkT3FoHo9wIdRiw==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^12.1.0" + }, + "engines": { + "node": ">= 4" + }, + "peerDependencies": { + "eslint": "^4.9.0", + "eslint-plugin-import": "^2.7.0", + "eslint-plugin-jsx-a11y": "^6.0.2", + "eslint-plugin-react": "^7.4.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "dev": true, + "dependencies": { + "eslint-restricted-globals": "^0.1.1" + }, + "engines": { + "node": ">= 4" + }, + "peerDependencies": { + "eslint": "^4.9.0", + "eslint-plugin-import": "^2.7.0" + } + }, + "node_modules/eslint-import-resolver-babel-module": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-babel-module/-/eslint-import-resolver-babel-module-4.0.0.tgz", + "integrity": "sha512-aPj0+pG0H3HCaMD9eRDYEzPdMyKrLE2oNhAzTXd2w86ZBe3s7drSrrPwVTfzO1CBp13FGk8S84oRmZHZvSo0mA==", + "dev": true, + "dependencies": { + "pkg-up": "^2.0.0", + "resolve": "^1.4.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "babel-core": "^6.0.0", + "babel-plugin-module-resolver": "^3.0.0-beta" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", + "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.11.2", + "aria-query": "^4.2.2", + "array-includes": "^3.1.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.0.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.6", + "emoji-regex": "^9.0.0", + "has": "^1.0.3", + "jsx-ast-utils": "^3.1.0", + "language-tags": "^1.0.5" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.23.1.tgz", + "integrity": "sha512-MvFGhZjI8Z4HusajmSw0ougGrq3Gs4vT/0WgwksZgf5RrLrRa2oYAw56okU4tZJl8+j7IYNuTM+2RnFEuTSdRQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.3", + "object.fromentries": "^2.0.4", + "object.values": "^1.1.3", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.4" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz", + "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==", + "dev": true, + "engines": { + "node": ">=7" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true, + "peer": true + }, + "node_modules/eslint/node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "peer": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true, + "peer": true + }, + "node_modules/eslint/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint/node_modules/external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "peer": true, + "dependencies": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/eslint/node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "node_modules/eslint/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true, + "peer": true + }, + "node_modules/eslint/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "peer": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "peer": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "peer": true, + "dependencies": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "dev": true, + "dependencies": { + "original": "^1.0.0" + }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "dev": true + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/execa/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/express/node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", + "dev": true + }, + "node_modules/falafel": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.4.tgz", + "integrity": "sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ==", + "dependencies": { + "acorn": "^7.1.1", + "foreach": "^2.0.5", + "isarray": "^2.0.1", + "object-keys": "^1.0.6" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/falafel/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/falafel/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "node_modules/fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", + "dev": true + }, + "node_modules/fast-xml-parser": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz", + "integrity": "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==", + "dev": true, + "bin": { + "xml2js": "cli.js" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + }, + "node_modules/fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "dev": true, + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", + "dependencies": { + "fbjs": "^3.0.0" + } + }, + "node_modules/fbjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.0.tgz", + "integrity": "sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==", + "dependencies": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, + "node_modules/fecha": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", + "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==", + "dev": true + }, + "node_modules/figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "peer": true, + "dependencies": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/file-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/file-system-cache": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/file-system-cache/-/file-system-cache-1.0.5.tgz", + "integrity": "sha1-hCWbNqK7uNPW6xAh0xMv/mTP/08=", + "dev": true, + "dependencies": { + "bluebird": "^3.3.5", + "fs-extra": "^0.30.0", + "ramda": "^0.21.0" + } + }, + "node_modules/file-system-cache/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/file-system-cache/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true + }, + "node_modules/filelist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/filesize": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", + "integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/find-babel-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", + "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", + "dev": true, + "peer": true, + "dependencies": { + "json5": "^0.5.1", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-babel-config/node_modules/json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/findup-sync/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "peer": true, + "dependencies": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/flatten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", + "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==", + "dev": true + }, + "node_modules/flow-bin": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.115.0.tgz", + "integrity": "sha512-xW+U2SrBaAr0EeLvKmXAmsdnrH6x0Io17P6yRJTNgrrV42G8KXhBAD00s6oGbTTqRyHD0nP47kyuU34zljZpaQ==", + "dev": true, + "bin": { + "flow": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/flux": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.1.tgz", + "integrity": "sha512-emk4RCvJ8RzNP2lNpphKnG7r18q8elDYNAPx7xn+bDeOIo9FFfxEfIQ2y6YbQNmnsGD3nH1noxtLE64Puz1bRQ==", + "dependencies": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.0" + }, + "peerDependencies": { + "react": "^15.0.2 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz", + "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.5.5", + "chalk": "^2.4.1", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "engines": { + "node": ">=6.11.5", + "yarn": ">=1.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.4.tgz", + "integrity": "sha512-iqy1pIotY/RmhdFZygSSlW0wko2yxkSCKqsuv4pr8QESohpYyG/Z7B/XXvPRKTJS//960rgguE5mSRUsDdaJrQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", + "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuse.js": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", + "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "dependencies": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-base/node_modules/glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "dependencies": { + "is-glob": "^2.0.0" + } + }, + "node_modules/glob-base/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-base/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-promise": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-3.4.0.tgz", + "integrity": "sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==", + "dev": true, + "dependencies": { + "@types/glob": "*" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "glob": "*" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "dev": true, + "optional": true, + "dependencies": { + "delegate": "^3.1.2" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "node_modules/growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "node_modules/gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, + "node_modules/gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gzip-size/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/harmony-reflect": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.1.tgz", + "integrity": "sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz", + "integrity": "sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc=", + "dev": true, + "dependencies": { + "is-glob": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-glob/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dev": true, + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "node_modules/highlight.js": { + "version": "10.7.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.1.tgz", + "integrity": "sha512-S6G97tHGqJ/U8DsXcEdnACbirtbx58Bx9CzIVeYli8OuswCfYI/LsXH2EiGcoGio1KAC3x4mmUwulOllJ2ZyRA==", + "engines": { + "node": "*" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "peer": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "node_modules/hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "node_modules/html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "node_modules/html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.1" + } + }, + "node_modules/html-entities": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", + "dev": true + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "dependencies": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "bin": { + "html-minifier": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/html-minifier-terser/node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/html-minifier-terser/node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/html-minifier-terser/node_modules/tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + }, + "node_modules/html-minifier/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + }, + "node_modules/html-tags": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", + "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "deprecated": "3.x is no longer supported", + "dev": true, + "dependencies": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "webpack": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, + "node_modules/html-webpack-plugin/node_modules/big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/html-webpack-plugin/node_modules/emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/html-webpack-plugin/node_modules/json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/html-webpack-plugin/node_modules/loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "dependencies": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + }, + "node_modules/htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dependencies": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" + }, + "node_modules/htmlparser2/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/htmlparser2/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/htmlparser2/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/http-parser-js": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", + "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "dependencies": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/http-proxy-middleware/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/http-proxy-middleware/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/http-proxy-middleware/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/http-proxy-middleware/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/http-proxy-middleware/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/icss-utils/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/icss-utils/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", + "dev": true, + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "node_modules/iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "node_modules/immer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", + "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "4.0.0-rc.12", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.12.tgz", + "integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==" + }, + "node_modules/import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "dependencies": { + "import-from": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "dependencies": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/info-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/info-symbol/-/info-symbol-0.1.0.tgz", + "integrity": "sha1-J4QdcoZ920JCzWEtecEGM4gcang=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "dependencies": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dev": true, + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "dependencies": { + "call-bind": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "dependencies": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "node_modules/is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "dependencies": { + "html-comment-regex": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/iterate-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", + "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", + "dev": true + }, + "node_modules/iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "dev": true, + "dependencies": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jake": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "dev": true, + "dependencies": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "dev": true, + "dependencies": { + "import-local": "^2.0.0", + "jest-cli": "^24.9.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-cli": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "dev": true, + "dependencies": { + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-cli/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/jest-cli/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/jest-cli/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-cli/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-cli/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-cli/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-cli/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-cli/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-cli/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-cli/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "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" + } + }, + "node_modules/jest-cli/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-config/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-config/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-config/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-config/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-config/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, + "dependencies": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "dev": true, + "dependencies": { + "detect-newline": "^2.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "dev": true, + "dependencies": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-environment-jsdom-fourteen": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-1.0.1.tgz", + "integrity": "sha512-DojMX1sY+at5Ep+O9yME34CdidZnO3/zfPh8UW+918C5fIZET5vCjfkegixmsi7AtdYfkr4bPlIzmWnlvQkP7Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^24.3.0", + "@jest/fake-timers": "^24.3.0", + "@jest/types": "^24.3.0", + "jest-mock": "^24.0.0", + "jest-util": "^24.0.0", + "jsdom": "^14.1.0" + } + }, + "node_modules/jest-environment-jsdom-fourteen/node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/jest-environment-jsdom-fourteen/node_modules/jsdom": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.1.0.tgz", + "integrity": "sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng==", + "dev": true, + "dependencies": { + "abab": "^2.0.0", + "acorn": "^6.0.4", + "acorn-globals": "^4.3.0", + "array-equal": "^1.0.0", + "cssom": "^0.3.4", + "cssstyle": "^1.1.1", + "data-urls": "^1.1.0", + "domexception": "^1.0.1", + "escodegen": "^1.11.0", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.1.3", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "saxes": "^3.1.9", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.5.0", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^6.1.2", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom-fourteen/node_modules/parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "dev": true + }, + "node_modules/jest-environment-jsdom-fourteen/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/jest-environment-jsdom-fourteen/node_modules/ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, + "dependencies": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "engines": { + "node": ">= 6" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/jest-haste-map/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-haste-map/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-haste-map/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/jest-haste-map/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-haste-map/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-haste-map/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "dev": true, + "dependencies": { + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, + "dependencies": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-message-util/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-message-util/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-message-util/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-message-util/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-message-util/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-mock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-runner": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", + "dev": true, + "dependencies": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-runtime": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", + "dev": true, + "dependencies": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" + }, + "bin": { + "jest-runtime": "bin/jest-runtime.js" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-runtime/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/jest-runtime/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-runtime/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-runtime/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-runtime/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-runtime/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-runtime/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-runtime/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-runtime/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "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" + } + }, + "node_modules/jest-runtime/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/jest-serializer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-snapshot": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "dev": true, + "dependencies": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-util/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-watch-typeahead": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.4.2.tgz", + "integrity": "sha512-f7VpLebTdaXs81rg/oj4Vg/ObZy2QtGzAmGLNsqUS5G5KtSN68tFcIsbvNODfNyQxU78g7D8x77o3bgfBTR+2Q==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.1", + "jest-regex-util": "^24.9.0", + "jest-watcher": "^24.3.0", + "slash": "^3.0.0", + "string-length": "^3.1.0", + "strip-ansi": "^5.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz", + "integrity": "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==", + "dev": true, + "dependencies": { + "astral-regex": "^1.0.0", + "strip-ansi": "^5.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.9.0", + "string-length": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-watcher/node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "dependencies": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbi": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.4.tgz", + "integrity": "sha512-52QRRFSsi9impURE8ZUbzAMCLjPm4THO7H2fcuIvaaeFTbSysvkodbQQXIVsNgq/ypDbq6dJiuGKL0vZ/i9hUg==" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "node_modules/jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "dependencies": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + } + }, + "node_modules/jsdom/node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jshint": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.12.0.tgz", + "integrity": "sha512-TwuuaUDmra0JMkuqvqy+WGo2xGHSNjv1BA1nTIgtH2K5z1jHuAEeAgp7laaR+hLRmajRjcrM71+vByBDanCyYA==", + "dependencies": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.19", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + }, + "bin": { + "jshint": "bin/jshint" + } + }, + "node_modules/jshint/node_modules/shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/jshint/node_modules/strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "bin": { + "strip-json-comments": "cli.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true, + "peer": true + }, + "node_modules/json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "dependencies": { + "jsonify": "~0.0.0" + } + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-stream/-/json-stream-1.0.0.tgz", + "integrity": "sha1-GjhU4o0rvuqzHMfd9oPS3cVlJwg=", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "node_modules/json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", + "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.2", + "object.assign": "^4.1.2" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/junk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", + "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/keyboard-key": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", + "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==" + }, + "node_modules/killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/koalas": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/koalas/-/koalas-1.0.2.tgz", + "integrity": "sha1-MYQz8HQjXbePrlZhoCqMpT7ilc0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "dev": true + }, + "node_modules/language-subtag-registry": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", + "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", + "dev": true, + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "dev": true, + "dependencies": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "node_modules/lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", + "dev": true, + "dependencies": { + "set-getter": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lazy-universal-dotenv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", + "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.0", + "app-root-dir": "^1.0.2", + "core-js": "^3.0.4", + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=6.0.0", + "yarn": ">=1.0.0" + } + }, + "node_modules/lazy-universal-dotenv/node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "deprecated": "use String.prototype.padStart()", + "dev": true + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "dependencies": { + "leven": "^3.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "node_modules/load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-fs-cache": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", + "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^0.1.1", + "mkdirp": "^0.5.1" + } + }, + "node_modules/loader-fs-cache/node_modules/find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-fs-cache/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-fs-cache/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-fs-cache/node_modules/pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "dependencies": { + "find-up": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "node_modules/lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true + }, + "node_modules/lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, + "node_modules/lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "node_modules/log-ok": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/log-ok/-/log-ok-0.1.1.tgz", + "integrity": "sha1-vqPdNqzQuKckDXhza1uXxlREozQ=", + "dev": true, + "dependencies": { + "ansi-green": "^0.1.1", + "success-symbol": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/log-utils/-/log-utils-0.2.1.tgz", + "integrity": "sha1-pMIXoN2aUFFdm5ICBgkas9TgMc8=", + "dev": true, + "dependencies": { + "ansi-colors": "^0.2.0", + "error-symbol": "^0.1.0", + "info-symbol": "^0.1.0", + "log-ok": "^0.1.1", + "success-symbol": "^0.1.0", + "time-stamp": "^1.0.1", + "warning-symbol": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "dev": true, + "dependencies": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, + "node_modules/loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "dev": true, + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/luxon": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz", + "integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==", + "engines": { + "node": "*" + } + }, + "node_modules/magic-string": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "dependencies": { + "vlq": "^0.2.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "dependencies": { + "tmpl": "1.0.x" + } + }, + "node_modules/mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha1-beJlMXSt+12e3DPGnT6Sobdvrwg=", + "dev": true + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/markdown-to-jsx": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-6.11.4.tgz", + "integrity": "sha512-3lRCD5Sh+tfA52iGgfs/XZiw33f7fFX9Bn55aNnVNUd2GzLDkOWyKYYD8Yju2B1Vn+feiEdgJs8T6Tg0xNokPw==", + "dev": true, + "dependencies": { + "prop-types": "^15.6.2", + "unquote": "^1.1.0" + }, + "engines": { + "node": ">= 4" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==", + "dev": true + }, + "node_modules/math-expression-evaluator": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.3.7.tgz", + "integrity": "sha512-nrbaifCl42w37hYd6oRLvoymFK42tWB+WQTMFtksDGQMi5GvlJwnz/CsS30FFAISFLtX+A0csJ0xLiuuyyec7w==" + }, + "node_modules/md5-file": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-5.0.0.tgz", + "integrity": "sha512-xbEFXCYVWrSx/gEKS1VPlg84h/4L20znVIulKw6kMfmBUAZNAnF00eczz9ICMl+/hjQGo5KSXRxbL/47X3rmMw==", + "dev": true, + "bin": { + "md5-file": "cli.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha1-fIekZGREwy11Q4VwkF8tvRsagFo=", + "dev": true, + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, + "node_modules/memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "node_modules/merge-deep": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", + "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "clone-deep": "^0.2.4", + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-deep/node_modules/clone-deep": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", + "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", + "dev": true, + "dependencies": { + "for-own": "^0.1.3", + "is-plain-object": "^2.0.1", + "kind-of": "^3.0.2", + "lazy-cache": "^1.0.3", + "shallow-clone": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-deep/node_modules/for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-deep/node_modules/lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-deep/node_modules/shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-deep/node_modules/shallow-clone/node_modules/kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "dev": true, + "dependencies": { + "is-buffer": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-deep/node_modules/shallow-clone/node_modules/lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "node_modules/merge-source-map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/merge-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/microevent.ts": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz", + "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/micromatch/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/micromatch/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/micromatch/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/micromatch/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "dev": true, + "dependencies": { + "mime-db": "1.46.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz", + "integrity": "sha512-RQIw6+7utTYn8DBGsf/LpRgZCJMpZt+kuawJ/fju0KiOL6nAaTBNmCJwS7HtwSCXfS47gCkmtBFS7HdsquhdxQ==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.4.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/minio": { + "version": "7.0.18", + "resolved": "https://registry.npmjs.org/minio/-/minio-7.0.18.tgz", + "integrity": "sha512-jVRjkw8A5Spf+ETY5OXQUcQckHriuUA3u2+MAcX36btLT8EytlOVivxIseXvyFf9cNn3dy5w1F1UyjMvHU+nqg==", + "dev": true, + "dependencies": { + "async": "^3.1.0", + "block-stream2": "^2.0.0", + "es6-error": "^4.1.1", + "fast-xml-parser": "^3.17.5", + "json-stream": "^1.0.0", + "lodash": "^4.17.20", + "mime-types": "^2.1.14", + "mkdirp": "^0.5.1", + "querystring": "0.2.0", + "through2": "^3.0.1", + "xml": "^1.0.0", + "xml2js": "^0.4.15" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/minio/node_modules/async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true + }, + "node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "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" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mississippi/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "dependencies": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-object/node_modules/for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mobx": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.1.8.tgz", + "integrity": "sha512-U4yCvUeh6yKXRwFxm2lyJjXPVekOEar/R8ZKWAXem/3fthJqYflViawfjDAUh7lZEvbKqljC3NT/pSaUKpE+gg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react-lite": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.2.0.tgz", + "integrity": "sha512-q5+UHIqYCOpBoFm/PElDuOhbcatvTllgRp3M1s+Hp5j0Z6XNgDbgqxawJ0ZAUEyKM8X1zs70PCuhAIzX1f4Q/g==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-locales-webpack-plugin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/moment-locales-webpack-plugin/-/moment-locales-webpack-plugin-1.2.0.tgz", + "integrity": "sha512-QAi5v0OlPUP7GXviKMtxnpBAo8WmTHrUNN7iciAhNOEAd9evCOvuN0g1N7ThIg3q11GLCkjY1zQ2saRcf/43nQ==", + "dev": true, + "dependencies": { + "lodash.difference": "^4.5.0" + }, + "peerDependencies": { + "moment": "^2.8.0", + "webpack": "^1 || ^2 || ^3 || ^4 || ^5" + } + }, + "node_modules/moment-range": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/moment-range/-/moment-range-4.0.2.tgz", + "integrity": "sha512-n8sceWwSTjmz++nFHzeNEUsYtDqjgXgcOBzsHi+BoXQU2FW+eU92LUaK8gqOiSu5PG57Q9sYj1Fz4LRDj4FtKA==", + "dependencies": { + "es6-symbol": "^3.1.0" + }, + "engines": { + "node": "*" + }, + "peerDependencies": { + "moment": ">= 2" + } + }, + "node_modules/move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "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" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "dependencies": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "dev": true, + "optional": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/native-url": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/native-url/-/native-url-0.2.6.tgz", + "integrity": "sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA==", + "dev": true, + "dependencies": { + "querystring": "^0.2.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", + "dev": true, + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "dependencies": { + "lodash.toarray": "^4.4.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "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" + } + }, + "node_modules/node-libs-browser/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/node-libs-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "node_modules/node-libs-browser/node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/node-libs-browser/node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "node_modules/node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-notifier": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", + "integrity": "sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==", + "dev": true, + "dependencies": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, + "node_modules/node-notifier/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/node-notifier/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-releases": { + "version": "1.1.71", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", + "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==" + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "dependencies": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/normalize-url/node_modules/query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.1.1.tgz", + "integrity": "sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", + "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", + "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.values": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", + "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/objectorarray": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.4.tgz", + "integrity": "sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w==", + "dev": true + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dev": true, + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/opn/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/optimal-select": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/optimal-select/-/optimal-select-4.0.1.tgz", + "integrity": "sha1-R959p6ObsJSf2a9UxvA1cVSPBMk=" + }, + "node_modules/optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "dependencies": { + "wordwrap": "~0.0.2" + } + }, + "node_modules/optimize-css-assets-webpack-plugin": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz", + "integrity": "sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA==", + "dev": true, + "dependencies": { + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "dependencies": { + "url-parse": "^1.4.3" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/overlayscrollbars": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz", + "integrity": "sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ==", + "dev": true + }, + "node_modules/p-all": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz", + "integrity": "sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==", + "dev": true, + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-all/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "dependencies": { + "p-reduce": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "dependencies": { + "p-timeout": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-filter/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "dependencies": { + "retry": "^0.12.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "dependencies": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dev": true, + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "node_modules/parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "node_modules/parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/pascal-case/node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/pascal-case/node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/pascal-case/node_modules/tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "dependencies": { + "node-modules-regexp": "^1.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "node_modules/pnp-webpack-plugin": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", + "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", + "dev": true, + "dependencies": { + "ts-pnp": "^1.1.6" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pointer-symbol": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pointer-symbol/-/pointer-symbol-1.0.0.tgz", + "integrity": "sha1-YPkRAgTqepKbYmRKITFVQ8uz1Ec=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/polished": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-3.7.1.tgz", + "integrity": "sha512-/QgHrNGYwIA4mwxJ/7FSvalUJsm7KNfnXiScVSEG2Xa5qxDeBn4nmdjN2pW00mkM2Tts64ktc47U8F7Ed1BRAA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dependencies": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", + "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^6.0.2" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-browser-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz", + "integrity": "sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig==", + "dev": true, + "dependencies": { + "postcss": "^7" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "browserslist": "^4" + } + }, + "node_modules/postcss-browser-comments/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-browser-comments/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-browser-comments/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/postcss-calc/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-calc/node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "node_modules/postcss-calc/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-calc/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", + "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-color-functional-notation/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-color-functional-notation/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-color-functional-notation/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-color-gray": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", + "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", + "dev": true, + "dependencies": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-color-gray/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-color-gray/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-color-gray/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", + "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.14", + "postcss-values-parser": "^2.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-color-hex-alpha/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-color-hex-alpha/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-color-hex-alpha/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-color-mod-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", + "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", + "dev": true, + "dependencies": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-color-mod-function/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-color-mod-function/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-color-mod-function/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", + "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-color-rebeccapurple/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-color-rebeccapurple/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-color-rebeccapurple/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-colormin/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-colormin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-colormin/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-convert-values/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-convert-values/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-convert-values/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-custom-media": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", + "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-custom-media/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-custom-media/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-custom-media/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-custom-properties": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", + "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.17", + "postcss-values-parser": "^2.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-custom-properties/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-custom-properties/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-custom-properties/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", + "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-custom-selectors/node_modules/cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "dependencies": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-custom-selectors/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", + "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "dependencies": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-comments/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-discard-comments/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-discard-comments/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-duplicates/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-discard-duplicates/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-discard-duplicates/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-empty/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-discard-empty/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-discard-empty/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-overridden/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-discard-overridden/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-discard-overridden/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", + "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-double-position-gradients/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-double-position-gradients/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-double-position-gradients/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-env-function": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", + "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-env-function/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-env-function/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-env-function/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-flexbugs-fixes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz", + "integrity": "sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.26" + } + }, + "node_modules/postcss-flexbugs-fixes/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-flexbugs-fixes/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-flexbugs-fixes/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-focus-visible": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", + "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-focus-visible/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-focus-visible/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-focus-visible/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-focus-within": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", + "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-focus-within/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-focus-within/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-focus-within/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-font-variant": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", + "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + } + }, + "node_modules/postcss-font-variant/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-font-variant/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-font-variant/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-functions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz", + "integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=", + "dependencies": { + "glob": "^7.1.2", + "object-assign": "^4.1.1", + "postcss": "^6.0.9", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", + "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-gap-properties/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-gap-properties/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-gap-properties/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-image-set-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", + "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-image-set-function/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-image-set-function/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-image-set-function/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-import": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz", + "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-import/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-import/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-import/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-initial": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.2.tgz", + "integrity": "sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA==", + "dev": true, + "dependencies": { + "lodash.template": "^4.5.0", + "postcss": "^7.0.2" + } + }, + "node_modules/postcss-initial/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-initial/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-initial/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-inline-svg": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-inline-svg/-/postcss-inline-svg-3.1.1.tgz", + "integrity": "sha512-G2BkarW6gGpGFGAiKzW7aiulUS0/6QuCgq1riZEiX4oMaUTpU1pdW7BU6UFRDrdKkwS0r4icK2pU0bg6sCSOjw==", + "dev": true, + "dependencies": { + "css-select": "^1.2.0", + "dom-serializer": "^0.1.0", + "htmlparser2": "^3.9.0", + "postcss": "^6.0.1", + "postcss-value-parser": "^3.2.3" + } + }, + "node_modules/postcss-inline-svg/node_modules/dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "dependencies": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "node_modules/postcss-inline-svg/node_modules/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "dependencies": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "node_modules/postcss-inline-svg/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz", + "integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==", + "dependencies": { + "camelcase-css": "^2.0.1", + "postcss": "^7.0.18" + } + }, + "node_modules/postcss-js/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-js/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-js/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-lab-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", + "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", + "dev": true, + "dependencies": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-lab-function/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-lab-function/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-lab-function/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", + "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", + "dev": true, + "dependencies": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-load-config/node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-load-config/node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-load-config/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-load-config/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-load-config/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/postcss-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/postcss-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/postcss-loader/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/postcss-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-loader/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-logical": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", + "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-logical/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-logical/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-logical/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-media-minmax": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", + "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-media-minmax/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-media-minmax/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-media-minmax/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "dependencies": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-longhand/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-merge-longhand/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-merge-longhand/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-rules/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-merge-rules/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-merge-rules/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-font-values/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-minify-font-values/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-minify-font-values/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-gradients/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-minify-gradients/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-minify-gradients/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-params/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-minify-params/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-minify-params/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-selectors/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-minify-selectors/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-minify-selectors/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-mixins": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/postcss-mixins/-/postcss-mixins-6.2.3.tgz", + "integrity": "sha512-gfH5d09YilzDn/CLGFA9Lwv7GTezuyHgnAyXC8AfvhUMpl67ZTewhcpNuOgawClCOD+76XePE2IHO1xMgsOlvA==", + "dev": true, + "dependencies": { + "globby": "^8.0.1", + "postcss": "^7.0.21", + "postcss-js": "^2.0.3", + "postcss-simple-vars": "^5.0.2", + "sugarss": "^2.0.0" + } + }, + "node_modules/postcss-mixins/node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-mixins/node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-mixins/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-mixins/node_modules/dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-mixins/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-mixins/node_modules/fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "dependencies": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-mixins/node_modules/globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-mixins/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-mixins/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-mixins/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-mixins/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-mixins/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-mixins/node_modules/postcss-simple-vars": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-5.0.2.tgz", + "integrity": "sha512-xWIufxBoINJv6JiLb7jl5oElgp+6puJwvT5zZHliUSydoLz4DADRB3NDDsYgfKVwojn4TDLiseoC65MuS8oGGg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.14" + } + }, + "node_modules/postcss-mixins/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-mixins/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-mixins/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-extract-imports/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-modules-extract-imports/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-modules-extract-imports/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dev": true, + "dependencies": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "node_modules/postcss-modules-local-by-default/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-modules-scope/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "dependencies": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "node_modules/postcss-modules-values/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-modules-values/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-modules-values/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-nested": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.3.tgz", + "integrity": "sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw==", + "dependencies": { + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2" + } + }, + "node_modules/postcss-nested/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-nested/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-nested/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-nesting": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-4.2.1.tgz", + "integrity": "sha512-IkyWXICwagCnlaviRexi7qOdwPw3+xVVjgFfGsxmztvRVaNxAlrypOIKqDE5mxY+BVxnId1rnUKBRQoNE2VDaA==", + "dev": true, + "dependencies": { + "postcss": "^6.0.11" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-normalize": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-8.0.1.tgz", + "integrity": "sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ==", + "dev": true, + "dependencies": { + "@csstools/normalize.css": "^10.1.0", + "browserslist": "^4.6.2", + "postcss": "^7.0.17", + "postcss-browser-comments": "^3.0.0", + "sanitize.css": "^10.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-charset/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-charset/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-charset/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-display-values/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-display-values/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-display-values/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-positions/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-positions/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-positions/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-repeat-style/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-repeat-style/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-repeat-style/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "dependencies": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-string/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-string/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-string/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-timing-functions/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-timing-functions/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-timing-functions/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-unicode/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-unicode/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-unicode/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "dependencies": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-url/node_modules/normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-url/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-url/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-url/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-whitespace/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize-whitespace/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize-whitespace/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-normalize/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-normalize/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-normalize/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-ordered-values/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-ordered-values/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-ordered-values/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", + "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-overflow-shorthand/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-overflow-shorthand/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-overflow-shorthand/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-page-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", + "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + } + }, + "node_modules/postcss-page-break/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-page-break/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-page-break/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-place": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", + "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-place/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-place/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-place/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-preset-env": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", + "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", + "dev": true, + "dependencies": { + "autoprefixer": "^9.6.1", + "browserslist": "^4.6.4", + "caniuse-lite": "^1.0.30000981", + "css-blank-pseudo": "^0.1.4", + "css-has-pseudo": "^0.10.0", + "css-prefers-color-scheme": "^3.1.1", + "cssdb": "^4.4.0", + "postcss": "^7.0.17", + "postcss-attribute-case-insensitive": "^4.0.1", + "postcss-color-functional-notation": "^2.0.1", + "postcss-color-gray": "^5.0.0", + "postcss-color-hex-alpha": "^5.0.3", + "postcss-color-mod-function": "^3.0.3", + "postcss-color-rebeccapurple": "^4.0.1", + "postcss-custom-media": "^7.0.8", + "postcss-custom-properties": "^8.0.11", + "postcss-custom-selectors": "^5.1.2", + "postcss-dir-pseudo-class": "^5.0.0", + "postcss-double-position-gradients": "^1.0.0", + "postcss-env-function": "^2.0.2", + "postcss-focus-visible": "^4.0.0", + "postcss-focus-within": "^3.0.0", + "postcss-font-variant": "^4.0.0", + "postcss-gap-properties": "^2.0.0", + "postcss-image-set-function": "^3.0.1", + "postcss-initial": "^3.0.0", + "postcss-lab-function": "^2.0.1", + "postcss-logical": "^3.0.0", + "postcss-media-minmax": "^4.0.0", + "postcss-nesting": "^7.0.0", + "postcss-overflow-shorthand": "^2.0.0", + "postcss-page-break": "^2.0.0", + "postcss-place": "^4.0.1", + "postcss-pseudo-class-any-link": "^6.0.0", + "postcss-replace-overflow-wrap": "^3.0.0", + "postcss-selector-matches": "^4.0.0", + "postcss-selector-not": "^4.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-preset-env/node_modules/autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "dev": true, + "dependencies": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + }, + "node_modules/postcss-preset-env/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-preset-env/node_modules/postcss-nesting": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", + "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-preset-env/node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "node_modules/postcss-preset-env/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-preset-env/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", + "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "dependencies": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-reduce-initial/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-reduce-initial/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-reduce-initial/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-reduce-transforms/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-reduce-transforms/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-reduce-transforms/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", + "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + } + }, + "node_modules/postcss-replace-overflow-wrap/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-replace-overflow-wrap/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-replace-overflow-wrap/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-safe-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", + "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-safe-parser/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-safe-parser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-safe-parser/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-selector-matches": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", + "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "node_modules/postcss-selector-matches/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-selector-matches/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-selector-matches/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-selector-not": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz", + "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "node_modules/postcss-selector-not/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-selector-not/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-selector-not/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", + "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", + "dependencies": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-simple-vars": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-4.1.0.tgz", + "integrity": "sha512-J/TRomA8EqXhS4VjQJsPCYTFIa9FYN/dkJK/8oZ0BYeVIPx91goqM8T+ljsP57+4bwSEywFOuB7EZ8n1gjjxZw==", + "dev": true, + "dependencies": { + "postcss": "^6.0.9" + } + }, + "node_modules/postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "dependencies": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-svgo/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-svgo/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-svgo/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-unique-selectors/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-unique-selectors/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-unique-selectors/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/postcss-values-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", + "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", + "dev": true, + "dependencies": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=6.14.4" + } + }, + "node_modules/postcss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "node_modules/pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "dependencies": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/prismjs": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", + "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", + "dev": true, + "optionalDependencies": { + "clipboard": "^2.0.0" + } + }, + "node_modules/private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "node_modules/promise.allsettled": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.4.tgz", + "integrity": "sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag==", + "dev": true, + "dependencies": { + "array.prototype.map": "^1.0.3", + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.0.2", + "iterate-value": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/promise.prototype.finally": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz", + "integrity": "sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.0", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/prompt-actions": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/prompt-actions/-/prompt-actions-3.0.2.tgz", + "integrity": "sha512-dhz2Fl7vK+LPpmnQ/S/eSut4BnH4NZDLyddHKi5uTU/2PDn3grEMGkgsll16V5RpVUh/yxdiam0xsM0RD4xvtg==", + "dev": true, + "dependencies": { + "debug": "^2.6.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prompt-actions/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/prompt-actions/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/prompt-base": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prompt-base/-/prompt-base-4.1.0.tgz", + "integrity": "sha512-svGzgLUKZoqomz9SGMkf1hBG8Wl3K7JGuRCXc/Pv7xw8239hhaTBXrmjt7EXA9P/QZzdyT8uNWt9F/iJTXq75g==", + "dev": true, + "dependencies": { + "component-emitter": "^1.2.1", + "debug": "^3.0.1", + "koalas": "^1.0.2", + "log-utils": "^0.2.1", + "prompt-actions": "^3.0.2", + "prompt-question": "^5.0.1", + "readline-ui": "^2.2.3", + "readline-utils": "^2.2.3", + "static-extend": "^0.1.2" + }, + "engines": { + "node": ">=5.0" + } + }, + "node_modules/prompt-base/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/prompt-choices": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prompt-choices/-/prompt-choices-4.1.0.tgz", + "integrity": "sha512-ZNYLv6rW9z9n0WdwCkEuS+w5nUAGzRgtRt6GQ5aFNFz6MIcU7nHFlHOwZtzy7RQBk80KzUGPSRQphvMiQzB8pg==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "arr-swap": "^1.0.1", + "choices-separator": "^2.0.0", + "clone-deep": "^4.0.0", + "collection-visit": "^1.0.0", + "define-property": "^2.0.2", + "is-number": "^6.0.0", + "kind-of": "^6.0.2", + "koalas": "^1.0.2", + "log-utils": "^0.2.1", + "pointer-symbol": "^1.0.0", + "radio-symbol": "^2.0.0", + "set-value": "^3.0.0", + "strip-color": "^0.1.0", + "terminal-paginator": "^2.0.2", + "toggle-array": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/prompt-choices/node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prompt-choices/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prompt-choices/node_modules/is-number": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-6.0.0.tgz", + "integrity": "sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prompt-choices/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prompt-choices/node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prompt-confirm": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prompt-confirm/-/prompt-confirm-2.0.4.tgz", + "integrity": "sha512-X5lzbC8/kMNHdPOqQPfMKpH4VV2f7v2OTRJoN69ZYBirSwTeQaf9ZhmzPEO9ybMA0YV2Pha5MV27u2/U4ahWfg==", + "dev": true, + "dependencies": { + "ansi-cyan": "^0.1.1", + "prompt-base": "^4.0.1" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/prompt-question": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/prompt-question/-/prompt-question-5.0.2.tgz", + "integrity": "sha512-wreaLbbu8f5+7zXds199uiT11Ojp59Z4iBi6hONlSLtsKGTvL2UY8VglcxQ3t/X4qWIxsNCg6aT4O8keO65v6Q==", + "dev": true, + "dependencies": { + "clone-deep": "^1.0.0", + "debug": "^3.0.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "kind-of": "^5.0.2", + "koalas": "^1.0.2", + "prompt-choices": "^4.0.5" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/prompt-question/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/prompt-question/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prompts": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", + "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dev": true, + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true, + "peer": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "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" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", + "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=" + }, + "node_modules/purgecss": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-2.3.0.tgz", + "integrity": "sha512-BE5CROfVGsx2XIhxGuZAT7rTH9lLeQx/6M0P7DTXQH4IUc3BBzs9JUzt4yzGf3JrH9enkeq6YJBe9CTtkm1WmQ==", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.0.0", + "postcss": "7.0.32", + "postcss-selector-parser": "^6.0.2" + }, + "bin": { + "purgecss": "bin/purgecss" + } + }, + "node_modules/purgecss/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/purgecss/node_modules/postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + }, + "node_modules/purgecss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/purgecss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quote-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", + "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", + "dependencies": { + "buffer-equal": "0.0.1", + "minimist": "^1.1.3", + "through2": "^2.0.0" + }, + "bin": { + "quote-stream": "bin/cmd.js" + } + }, + "node_modules/quote-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/radio-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/radio-symbol/-/radio-symbol-2.0.0.tgz", + "integrity": "sha1-eqm/xQSFY21S3XbWqOYxspB5muE=", + "dev": true, + "dependencies": { + "ansi-gray": "^0.1.1", + "ansi-green": "^0.1.1", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/ramda": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz", + "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=", + "dev": true + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-loader": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", + "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/raw-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/raw-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/raw-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/raw-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/raw-loader/node_modules/schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/rc-align": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-2.4.5.tgz", + "integrity": "sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==", + "dependencies": { + "babel-runtime": "^6.26.0", + "dom-align": "^1.7.0", + "prop-types": "^15.5.8", + "rc-util": "^4.0.4" + } + }, + "node_modules/rc-animate": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.11.1.tgz", + "integrity": "sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ==", + "dependencies": { + "babel-runtime": "6.x", + "classnames": "^2.2.6", + "css-animation": "^1.3.2", + "prop-types": "15.x", + "raf": "^3.4.0", + "rc-util": "^4.15.3", + "react-lifecycles-compat": "^3.0.4" + } + }, + "node_modules/rc-time-picker": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.7.3.tgz", + "integrity": "sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg==", + "dependencies": { + "classnames": "2.x", + "moment": "2.x", + "prop-types": "^15.5.8", + "raf": "^3.4.1", + "rc-trigger": "^2.2.0", + "react-lifecycles-compat": "^3.0.4" + } + }, + "node_modules/rc-trigger": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.6.5.tgz", + "integrity": "sha512-m6Cts9hLeZWsTvWnuMm7oElhf+03GOjOLfTuU0QmdB9ZrW7jR2IpI5rpNM7i9MvAAlMAmTx5Zr7g3uu/aMvZAw==", + "dependencies": { + "babel-runtime": "6.x", + "classnames": "^2.2.6", + "prop-types": "15.x", + "rc-align": "^2.4.0", + "rc-animate": "2.x", + "rc-util": "^4.4.0", + "react-lifecycles-compat": "^3.0.4" + } + }, + "node_modules/rc-util": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz", + "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==", + "dependencies": { + "add-dom-event-listener": "^1.1.0", + "prop-types": "^15.5.10", + "react-is": "^16.12.0", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0" + } + }, + "node_modules/rc-util/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-addons-pure-render-mixin": { + "version": "15.6.3", + "resolved": "https://registry.npmjs.org/react-addons-pure-render-mixin/-/react-addons-pure-render-mixin-15.6.3.tgz", + "integrity": "sha512-e7F2OsLiyYGr9SHWHGlI/FfHRh+kbYx0hNfdN5zivHIf4vzeno7gsRJKXg71E35CpUCnre+JfM6UgWWgsvJBzA==", + "dependencies": { + "object-assign": "^4.1.0" + } + }, + "node_modules/react-app-polyfill": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz", + "integrity": "sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g==", + "dev": true, + "dependencies": { + "core-js": "^3.5.0", + "object-assign": "^4.1.1", + "promise": "^8.0.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.3", + "whatwg-fetch": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-app-polyfill/node_modules/promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "dev": true, + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, + "node_modules/react-base16-styling": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz", + "integrity": "sha1-OFjyTpxN2MvT9wLz901YHKKRcmk=", + "dependencies": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, + "node_modules/react-circular-progressbar": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/react-circular-progressbar/-/react-circular-progressbar-2.0.3.tgz", + "integrity": "sha512-YKN+xAShXA3gYihevbQZbavfiJxo83Dt1cUxqg/cltj4VVsRQpDr7Fg1mvjDG3x1KHGtd9NmYKvJ2mMrPwbKyw==", + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/react-codemirror2": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-5.1.0.tgz", + "integrity": "sha512-Cksbgbviuf2mJfMyrKmcu7ycK6zX/ukuQO8dvRZdFWqATf5joalhjFc6etnBdGCcPA2LbhIwz+OPnQxLN/j1Fw==", + "peerDependencies": { + "codemirror": "5.x", + "react": ">=15.5 <=16.x" + } + }, + "node_modules/react-color": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "dev": true, + "dependencies": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-confirm": { + "version": "0.1.23", + "resolved": "https://registry.npmjs.org/react-confirm/-/react-confirm-0.1.23.tgz", + "integrity": "sha512-G853O0XapIQXF0bx2iFWBLgGIzCu2ZjGJWJp0IFMNoim89yh/cz6i/xcSM/N8zKLWIvrVAWm/Zn/w3d5E7uv3g==", + "peerDependencies": { + "react": "^0.14.7 || 15.x || 16.x || 17.x", + "react-dom": "^0.14.7 || 15.x || 16.x || 17.x" + } + }, + "node_modules/react-datepicker": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-2.16.0.tgz", + "integrity": "sha512-TvcmSY27rn0JKvuJuIXNNS+niGQNdgtuG/CsBttVYhPOA9KmSw7c2PvQBPVEvzkyV+QPNJ8jN/KVJNj9uvopqA==", + "dependencies": { + "classnames": "^2.2.6", + "date-fns": "^2.0.1", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.9.0", + "react-popper": "^1.3.4" + }, + "peerDependencies": { + "react": "^16.9.0", + "react-dom": "^16.9.0" + } + }, + "node_modules/react-daterange-picker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-daterange-picker/-/react-daterange-picker-2.0.1.tgz", + "integrity": "sha512-xPBtMONOfljnausiL6ftlfg6EHHvjdiDcH0j71FblAv35IWUJ9VDH3lXaUX9MZYdIynTN7hW+oqPcRK5xls1Nw==", + "dependencies": { + "calendar": "^0.1.0", + "classnames": "^2.1.1", + "create-react-class": "^15.6.3", + "immutable": "^3.7.2", + "prop-types": "^15.6.0", + "react-addons-pure-render-mixin": "^15.6.2" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "moment": "^2.18.1", + "moment-range": "^3.0.3", + "react": "0.14.x || 15.x.x || 16.x.x", + "react-dom": "0.14.x || 15.x.x || 16.x.x" + } + }, + "node_modules/react-daterange-picker/node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dev-utils": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", + "integrity": "sha512-dx0LvIGHcOPtKbeiSUM4jqpBl3TcY7CDjZdfOIcKeznE7BWr9dg0iPG90G5yfVQ+p/rGNMXdbfStvzQZEVEi4A==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.10.4", + "address": "1.1.2", + "browserslist": "4.14.2", + "chalk": "2.4.2", + "cross-spawn": "7.0.3", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "2.0.0", + "filesize": "6.1.0", + "find-up": "4.1.0", + "fork-ts-checker-webpack-plugin": "4.1.6", + "global-modules": "2.0.0", + "globby": "11.0.1", + "gzip-size": "5.1.1", + "immer": "8.0.1", + "is-root": "2.1.0", + "loader-utils": "2.0.0", + "open": "^7.0.2", + "pkg-up": "3.1.0", + "prompts": "2.4.0", + "react-error-overlay": "^6.0.9", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-dev-utils/node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/react-dev-utils/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/browserslist": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.2.tgz", + "integrity": "sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001125", + "electron-to-chromium": "^1.3.564", + "escalade": "^3.0.2", + "node-releases": "^1.1.61" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + }, + "node_modules/react-dev-utils/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/react-dev-utils/node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-dev-utils/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-dev-utils/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/react-dnd": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-2.6.0.tgz", + "integrity": "sha1-f6JWds+CfViokSk+PBq1naACVFo=", + "dependencies": { + "disposables": "^1.0.1", + "dnd-core": "^2.6.0", + "hoist-non-react-statics": "^2.1.0", + "invariant": "^2.1.0", + "lodash": "^4.2.0", + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-2.6.0.tgz", + "integrity": "sha1-WQzRzKeEQbsnTt1XH+9MCxbdz44=", + "dependencies": { + "lodash": "^4.2.0" + } + }, + "node_modules/react-dnd/node_modules/hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + }, + "node_modules/react-docgen": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.3.1.tgz", + "integrity": "sha512-YG7YujVTwlLslr2Ny8nQiUfbBuEwKsLHJdQTSdEga1eY/nRFh/7LjCWUn6ogYhu2WDKg4z+6W/BJtUi+DPUIlA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@babel/runtime": "^7.7.6", + "ast-types": "^0.14.2", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "neo-async": "^2.6.1", + "node-dir": "^0.1.10", + "strip-indent": "^3.0.0" + }, + "bin": { + "react-docgen": "bin/react-docgen.js" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/react-docgen-typescript": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-1.21.0.tgz", + "integrity": "sha512-E4y/OcXwHukgiVafCGlxwoNHr4BDmM70Ww7oimL/QkMo5dmGALhceewe/xmVjdMxxI7E5syOGOc9/tbHL742rg==", + "dev": true, + "peerDependencies": { + "typescript": ">= 3.x" + } + }, + "node_modules/react-docgen-typescript-plugin": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-0.6.3.tgz", + "integrity": "sha512-av1S/fmWBNFGgNa4qtkidFjjOz23eEi6EdCtwSWo9WNhGzUMyMygbD/DosMWoeFlZpk9R3MXPkRE7PDH6j5GMQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "endent": "^2.0.1", + "micromatch": "^4.0.2", + "react-docgen-typescript": "^1.20.5", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "typescript": ">= 3.x" + } + }, + "node_modules/react-docgen-typescript-plugin/node_modules/tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + }, + "node_modules/react-docgen/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/react-docgen/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + }, + "peerDependencies": { + "react": "^16.14.0" + } + }, + "node_modules/react-draggable": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz", + "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", + "dev": true, + "dependencies": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", + "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==", + "dev": true + }, + "node_modules/react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==", + "dev": true + }, + "node_modules/react-google-recaptcha": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-1.1.0.tgz", + "integrity": "sha512-GMWZEsIKyBVG+iXfVMwtMVKFJATu5c+oguL/5i95H3Jb5d5CG4DY0W9t4QhdSSulgkXbZMgv0VSuGF/GV1ENTA==", + "dependencies": { + "prop-types": "^15.5.0", + "react-async-script": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, + "node_modules/react-helmet-async": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.0.9.tgz", + "integrity": "sha512-N+iUlo9WR3/u9qGMmP4jiYfaD6pe9IvDTapZLFJz2D3xlTlCM1Bzy4Ab3g72Nbajo/0ZyW+W9hdz8Hbe4l97pQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0", + "react-dom": "^16.6.0 || ^17.0.0" + } + }, + "node_modules/react-highlight": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.14.0.tgz", + "integrity": "sha512-kWE+KXOXidS7SABhVopOgMnowbI3RAfeGZbnrduLNlWrYAED8sycL9l/Fvw3w0PFpIIawB7mRDnyhDcM/cIIGA==", + "dependencies": { + "highlight.js": "^10.5.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/react-hotkeys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz", + "integrity": "sha512-3n3OU8vLX/pfcJrR3xJ1zlww6KS1kEJt0Whxc4FiGV+MJrQ1mYSYI3qS/11d2MJDFm8IhOXMTFQirfu6AVOF6Q==", + "dev": true, + "dependencies": { + "prop-types": "^15.6.1" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/react-json-tree": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.11.2.tgz", + "integrity": "sha512-aYhUPj1y5jR3ZQ+G3N7aL8FbTyO03iLwnVvvEikLcNFqNTyabdljo9xDftZndUBFyyyL0aK3qGO9+8EilILHUw==", + "dependencies": { + "babel-runtime": "^6.6.1", + "prop-types": "^15.5.8", + "react-base16-styling": "^0.5.1" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0", + "react-dom": "^15.0.0 || ^16.0.0" + } + }, + "node_modules/react-json-view": { + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", + "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", + "dependencies": { + "flux": "^4.0.1", + "react-base16-styling": "^0.6.0", + "react-lifecycles-compat": "^3.0.4", + "react-textarea-autosize": "^8.3.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^16.3.0 || ^15.5.4", + "react-dom": "^17.0.0 || ^16.3.0 || ^15.5.4" + } + }, + "node_modules/react-json-view/node_modules/react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", + "integrity": "sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=", + "dependencies": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, + "node_modules/react-lazyload": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-lazyload/-/react-lazyload-3.2.0.tgz", + "integrity": "sha512-zJlrG8QyVZz4+xkYZH5v1w3YaP5wEFaYSUWC4CT9UXfK75IfRAIEdnyIUF+dXr3kX2MOtL1lUaZmaQZqrETwgw==", + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", + "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-onclickoutside": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.10.0.tgz", + "integrity": "sha512-7i2L3ef+0ILXpL6P+Hg304eCQswh4jl3ynwR71BSlMU49PE2uk31k8B2GkP6yE9s2D4jTGKnzuSpzWxu4YxfQQ==", + "funding": { + "type": "individual", + "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" + }, + "peerDependencies": { + "react": "^15.5.x || ^16.x || ^17.x", + "react-dom": "^15.5.x || ^16.x || ^17.x" + } + }, + "node_modules/react-popper": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz", + "integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "@hypnosphi/create-react-context": "^0.3.1", + "deep-equal": "^1.1.1", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.7", + "warning": "^4.0.2" + }, + "peerDependencies": { + "react": "0.14.x || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/react-popper-tooltip": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz", + "integrity": "sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@popperjs/core": "^2.5.4", + "react-popper": "^2.2.4" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0", + "react-dom": "^16.6.0 || ^17.0.0" + } + }, + "node_modules/react-popper-tooltip/node_modules/react-popper": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.4.tgz", + "integrity": "sha512-NacOu4zWupdQjVXq02XpTD3yFPSfg5a7fex0wa3uGKVkFK7UN6LvVxgcb+xYr56UCuWiNPMH20tntdVdJRwYew==", + "dev": true, + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17" + } + }, + "node_modules/react-redux": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.2.tgz", + "integrity": "sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "hoist-non-react-statics": "^3.3.0", + "invariant": "^2.2.4", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.1", + "react-is": "^16.6.0", + "react-lifecycles-compat": "^3.0.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0-0 || ^16.0.0-0", + "redux": "^2.0.0 || ^3.0.0 || ^4.0.0-0" + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-refresh": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", + "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-resize-detector": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-2.3.0.tgz", + "integrity": "sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ==", + "dependencies": { + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "prop-types": "^15.6.0", + "resize-observer-polyfill": "^1.5.0" + }, + "peerDependencies": { + "react": "^0.14.7 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/react-router": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", + "integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==", + "dependencies": { + "history": "^4.7.2", + "hoist-non-react-statics": "^2.5.0", + "invariant": "^2.2.4", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.1", + "warning": "^4.0.1" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-dom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz", + "integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==", + "dependencies": { + "history": "^4.7.2", + "invariant": "^2.2.4", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.1", + "react-router": "^4.3.1", + "warning": "^4.0.1" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router/node_modules/hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + }, + "node_modules/react-router/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/react-router/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/react-scripts": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.4.tgz", + "integrity": "sha512-7J7GZyF/QvZkKAZLneiOIhHozvOMHey7hO9cdO9u68jjhGZlI8hDdOm6UyuHofn6Ajc9Uji5I6Psm/nKNuWdyw==", + "dev": true, + "dependencies": { + "@babel/core": "7.9.0", + "@svgr/webpack": "4.3.3", + "@typescript-eslint/eslint-plugin": "^2.10.0", + "@typescript-eslint/parser": "^2.10.0", + "babel-eslint": "10.1.0", + "babel-jest": "^24.9.0", + "babel-loader": "8.1.0", + "babel-plugin-named-asset-import": "^0.3.6", + "babel-preset-react-app": "^9.1.2", + "camelcase": "^5.3.1", + "case-sensitive-paths-webpack-plugin": "2.3.0", + "css-loader": "3.4.2", + "dotenv": "8.2.0", + "dotenv-expand": "5.1.0", + "eslint": "^6.6.0", + "eslint-config-react-app": "^5.2.1", + "eslint-loader": "3.0.3", + "eslint-plugin-flowtype": "4.6.0", + "eslint-plugin-import": "2.20.1", + "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-react": "7.19.0", + "eslint-plugin-react-hooks": "^1.6.1", + "file-loader": "4.3.0", + "fs-extra": "^8.1.0", + "html-webpack-plugin": "4.0.0-beta.11", + "identity-obj-proxy": "3.0.0", + "jest": "24.9.0", + "jest-environment-jsdom-fourteen": "1.0.1", + "jest-resolve": "24.9.0", + "jest-watch-typeahead": "0.4.2", + "mini-css-extract-plugin": "0.9.0", + "optimize-css-assets-webpack-plugin": "5.0.3", + "pnp-webpack-plugin": "1.6.4", + "postcss-flexbugs-fixes": "4.1.0", + "postcss-loader": "3.0.0", + "postcss-normalize": "8.0.1", + "postcss-preset-env": "6.7.0", + "postcss-safe-parser": "4.0.1", + "react-app-polyfill": "^1.0.6", + "react-dev-utils": "^10.2.1", + "resolve": "1.15.0", + "resolve-url-loader": "3.1.2", + "sass-loader": "8.0.2", + "semver": "6.3.0", + "style-loader": "0.23.1", + "terser-webpack-plugin": "2.3.8", + "ts-pnp": "1.1.6", + "url-loader": "2.3.0", + "webpack": "4.42.0", + "webpack-dev-server": "3.11.0", + "webpack-manifest-plugin": "2.2.0", + "workbox-webpack-plugin": "4.3.1" + }, + "bin": { + "react-scripts": "bin/react-scripts.js" + }, + "engines": { + "node": ">=8.10" + }, + "optionalDependencies": { + "fsevents": "2.1.2" + }, + "peerDependencies": { + "typescript": "^3.2.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-scripts/node_modules/@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.8.3" + } + }, + "node_modules/react-scripts/node_modules/@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/react-scripts/node_modules/@babel/core/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/react-scripts/node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-scripts/node_modules/@typescript-eslint/eslint-plugin": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", + "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "2.34.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^2.0.0", + "eslint": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-scripts/node_modules/@typescript-eslint/parser": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", + "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "dev": true, + "dependencies": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/react-scripts/node_modules/@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/react-scripts/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/react-scripts/node_modules/acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/react-scripts/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/react-scripts/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/react-scripts/node_modules/aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "node_modules/react-scripts/node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 6.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/react-scripts/node_modules/browserslist": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.10.0.tgz", + "integrity": "sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001035", + "electron-to-chromium": "^1.3.378", + "node-releases": "^1.1.52", + "pkg-up": "^3.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + }, + "node_modules/react-scripts/node_modules/cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "dev": true, + "dependencies": { + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^7.0.0", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/react-scripts/node_modules/cacache/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/react-scripts/node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", + "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "node_modules/react-scripts/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/react-scripts/node_modules/cliui/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/react-scripts/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/react-scripts/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/react-scripts/node_modules/css-loader": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz", + "integrity": "sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.23", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.1.1", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.0.2", + "schema-utils": "^2.6.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/react-scripts/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/react-scripts/node_modules/emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/react-scripts/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/react-scripts/node_modules/eslint-config-react-app": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz", + "integrity": "sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.9" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "2.x", + "@typescript-eslint/parser": "2.x", + "babel-eslint": "10.x", + "eslint": "6.x", + "eslint-plugin-flowtype": "3.x || 4.x", + "eslint-plugin-import": "2.x", + "eslint-plugin-jsx-a11y": "6.x", + "eslint-plugin-react": "7.x", + "eslint-plugin-react-hooks": "1.x || 2.x" + } + }, + "node_modules/react-scripts/node_modules/eslint-loader": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-3.0.3.tgz", + "integrity": "sha512-+YRqB95PnNvxNp1HEjQmvf9KNvCin5HXYYseOXVC2U0KEcw4IkQ2IQEBG46j7+gW39bMzeu0GsUhVbBY3Votpw==", + "deprecated": "This loader has been deprecated. Please use eslint-webpack-plugin", + "dev": true, + "dependencies": { + "fs-extra": "^8.1.0", + "loader-fs-cache": "^1.0.2", + "loader-utils": "^1.2.3", + "object-hash": "^2.0.1", + "schema-utils": "^2.6.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0", + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/react-scripts/node_modules/eslint-plugin-flowtype": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", + "integrity": "sha512-W5hLjpFfZyZsXfo5anlu7HM970JBDqbEshAJUkeczP6BFCIfJXuiIBQXyberLRtOStT0OGPF8efeTbxlHk4LpQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": ">=6.1.0" + } + }, + "node_modules/react-scripts/node_modules/eslint-plugin-import": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", + "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", + "dev": true, + "dependencies": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "2.x - 6.x" + } + }, + "node_modules/react-scripts/node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/react-scripts/node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/react-scripts/node_modules/eslint-plugin-jsx-a11y": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz", + "integrity": "sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.4.5", + "aria-query": "^3.0.0", + "array-includes": "^3.0.3", + "ast-types-flow": "^0.0.7", + "axobject-query": "^2.0.2", + "damerau-levenshtein": "^1.0.4", + "emoji-regex": "^7.0.2", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6" + } + }, + "node_modules/react-scripts/node_modules/eslint-plugin-react": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", + "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.1", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.3", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.15.1", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/react-scripts/node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/react-scripts/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/react-scripts/node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/eslint/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-scripts/node_modules/eslint/node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/react-scripts/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-scripts/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "dependencies": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/react-scripts/node_modules/fast-glob/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/react-scripts/node_modules/fast-glob/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/file-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz", + "integrity": "sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA==", + "dev": true, + "dependencies": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.5.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/react-scripts/node_modules/filesize": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz", + "integrity": "sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/react-scripts/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/fork-ts-checker-webpack-plugin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz", + "integrity": "sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==", + "dev": true, + "dependencies": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^3.3.0", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "engines": { + "node": ">=6.11.5", + "yarn": ">=1.0.0" + } + }, + "node_modules/react-scripts/node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/react-scripts/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/react-scripts/node_modules/fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/react-scripts/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-scripts/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-scripts/node_modules/globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/globby/node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "node_modules/react-scripts/node_modules/globby/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/html-webpack-plugin": { + "version": "4.0.0-beta.11", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz", + "integrity": "sha512-4Xzepf0qWxf8CGg7/WQM5qBB2Lc/NFI7MhU59eUDTkuQp3skZczH4UA1d6oQyDEIoMDgERVhRyTdtUPZ5s5HBg==", + "deprecated": "please switch to a stable version", + "dev": true, + "dependencies": { + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.15", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/react-scripts/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/react-scripts/node_modules/immer": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", + "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==", + "dev": true + }, + "node_modules/react-scripts/node_modules/inquirer": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", + "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-scripts/node_modules/is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/jest-worker": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", + "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", + "dev": true, + "dependencies": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 8.3" + } + }, + "node_modules/react-scripts/node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/react-scripts/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/react-scripts/node_modules/jsx-ast-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", + "integrity": "sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.1", + "object.assign": "^4.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/react-scripts/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-scripts/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/react-scripts/node_modules/mini-css-extract-plugin": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.4.0" + } + }, + "node_modules/react-scripts/node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/react-scripts/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/react-scripts/node_modules/postcss-flexbugs-fixes": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", + "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + } + }, + "node_modules/react-scripts/node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "node_modules/react-scripts/node_modules/postcss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "node_modules/react-scripts/node_modules/react-dev-utils": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz", + "integrity": "sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.8.3", + "address": "1.1.2", + "browserslist": "4.10.0", + "chalk": "2.4.2", + "cross-spawn": "7.0.1", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "2.0.0", + "filesize": "6.0.1", + "find-up": "4.1.0", + "fork-ts-checker-webpack-plugin": "3.1.1", + "global-modules": "2.0.0", + "globby": "8.0.2", + "gzip-size": "5.1.1", + "immer": "1.10.0", + "inquirer": "7.0.4", + "is-root": "2.1.0", + "loader-utils": "1.2.3", + "open": "^7.0.2", + "pkg-up": "3.1.0", + "react-error-overlay": "^6.0.7", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.0" + }, + "engines": { + "node": ">=8.10" + } + }, + "node_modules/react-scripts/node_modules/react-dev-utils/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/react-dev-utils/node_modules/cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/react-scripts/node_modules/react-dev-utils/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/react-scripts/node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/react-scripts/node_modules/react-dev-utils/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/react-dev-utils/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/react-dev-utils/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/react-dev-utils/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/react-scripts/node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/react-scripts/node_modules/resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/react-scripts/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/react-scripts/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/sockjs": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz", + "integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.10.0", + "uuid": "^3.4.0", + "websocket-driver": "0.6.5" + } + }, + "node_modules/react-scripts/node_modules/sockjs-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", + "dev": true, + "dependencies": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + } + }, + "node_modules/react-scripts/node_modules/sockjs-client/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/react-scripts/node_modules/sockjs/node_modules/faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/react-scripts/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/ssri": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/react-scripts/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-scripts/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-scripts/node_modules/table/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/terser-webpack-plugin": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", + "integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==", + "dev": true, + "dependencies": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.3.1", + "jest-worker": "^25.4.0", + "p-limit": "^2.3.0", + "schema-utils": "^2.6.6", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.6.12", + "webpack-sources": "^1.4.3" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/react-scripts/node_modules/terser-webpack-plugin/node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/react-scripts/node_modules/terser-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/ts-pnp": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz", + "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-scripts/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/react-scripts/node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/react-scripts/node_modules/url-loader": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-2.3.0.tgz", + "integrity": "sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog==", + "dev": true, + "dependencies": { + "loader-utils": "^1.2.3", + "mime": "^2.4.4", + "schema-utils": "^2.5.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/react-scripts/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/react-scripts/node_modules/webpack": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", + "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.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.1", + "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.0", + "webpack-sources": "^1.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/react-scripts/node_modules/webpack-dev-server": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz", + "integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==", + "dev": true, + "dependencies": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.20", + "sockjs-client": "1.4.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 6.11.5" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dev": true, + "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" + } + }, + "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/webpack/node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/react-scripts/node_modules/webpack/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "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" + } + }, + "node_modules/react-scripts/node_modules/webpack/node_modules/eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/react-scripts/node_modules/webpack/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/react-scripts/node_modules/webpack/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-scripts/node_modules/webpack/node_modules/ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/react-scripts/node_modules/webpack/node_modules/terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/react-scripts/node_modules/websocket-driver": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "dev": true, + "dependencies": { + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/react-scripts/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/wrap-ansi/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/react-scripts/node_modules/ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/react-scripts/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "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" + } + }, + "node_modules/react-scripts/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/react-scripts/node_modules/yargs/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-scripts/node_modules/yargs/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-sizeme": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/react-sizeme/-/react-sizeme-2.6.12.tgz", + "integrity": "sha512-tL4sCgfmvapYRZ1FO2VmBmjPVzzqgHA7kI8lSJ6JS6L78jXFNRdOZFpXyK6P1NBZvKPPCZxReNgzZNUajAerZw==", + "dev": true, + "dependencies": { + "element-resize-detector": "^1.2.1", + "invariant": "^2.2.4", + "shallowequal": "^1.1.0", + "throttle-debounce": "^2.1.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0-0 || ^16.0.0", + "react-dom": "^0.14.0 || ^15.0.0-0 || ^16.0.0" + } + }, + "node_modules/react-smooth": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-1.0.6.tgz", + "integrity": "sha512-B2vL4trGpNSMSOzFiAul9kFAsxTukL9Wyy9EXtkQy3GJr6sZqW9e1nShdVOJ3hRYamPZ94O17r3Q0bjSw3UYtg==", + "dependencies": { + "lodash": "~4.17.4", + "prop-types": "^15.6.0", + "raf": "^3.4.0", + "react-transition-group": "^2.5.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0", + "react-dom": "^15.0.0 || ^16.0.0" + } + }, + "node_modules/react-smooth/node_modules/dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "node_modules/react-smooth/node_modules/react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "dependencies": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" + } + }, + "node_modules/react-syntax-highlighter": { + "version": "13.5.3", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz", + "integrity": "sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.1.1", + "lowlight": "^1.14.0", + "prismjs": "^1.21.0", + "refractor": "^3.1.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/react-textarea-autosize": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.2.tgz", + "integrity": "sha512-JrMWVgQSaExQByP3ggI1eA8zF4mF0+ddVuX7acUeK2V7bmrpjVOY72vmLz2IXFJSAXoY3D80nEzrn0GWajWK3Q==", + "dependencies": { + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.0.0", + "use-latest": "^1.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/react-toastify": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-5.5.0.tgz", + "integrity": "sha512-jsVme7jALIFGRyQsri/g4YTsRuaaGI70T6/ikjwZMB4mwTZaCWqj5NqxhGrRStKlJc5npXKKvKeqTiRGQl78LQ==", + "dependencies": { + "@babel/runtime": "^7.4.2", + "classnames": "^2.2.6", + "prop-types": "^15.7.2", + "react-transition-group": "^4" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/react-virtualized": { + "version": "9.22.3", + "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz", + "integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "clsx": "^1.0.4", + "dom-helpers": "^5.1.3", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0-alpha", + "react-dom": "^15.3.0 || ^16.0.0-alpha" + } + }, + "node_modules/reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "dev": true, + "dependencies": { + "lodash": "^4.0.1" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "dependencies": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "dependencies": { + "pify": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "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" + } + }, + "node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/readdirp/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readline-ui": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/readline-ui/-/readline-ui-2.2.3.tgz", + "integrity": "sha512-ix7jz0PxqQqcIuq3yQTHv1TOhlD2IHO74aNO+lSuXsRYm1d+pdyup1yF3zKyLK1wWZrVNGjkzw5tUegO2IDy+A==", + "dev": true, + "dependencies": { + "component-emitter": "^1.2.1", + "debug": "^2.6.8", + "readline-utils": "^2.2.1", + "string-width": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/readline-ui/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/readline-ui/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/readline-ui/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/readline-ui/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/readline-utils": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/readline-utils/-/readline-utils-2.2.3.tgz", + "integrity": "sha1-b4R9a48ZFcORtYHDZ81HhzhiNRo=", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "extend-shallow": "^2.0.1", + "is-buffer": "^1.1.5", + "is-number": "^3.0.0", + "is-windows": "^1.0.1", + "koalas": "^1.0.2", + "mute-stream": "0.0.7", + "strip-color": "^0.1.0", + "window-size": "^1.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/readline-utils/node_modules/mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "node_modules/realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "dependencies": { + "util.promisify": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/recharts": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-1.8.5.tgz", + "integrity": "sha512-tM9mprJbXVEBxjM7zHsIy6Cc41oO/pVYqyAsOHLxlJrbNBuLs0PHB3iys2M+RqCF0//k8nJtZF6X6swSkWY3tg==", + "dependencies": { + "classnames": "^2.2.5", + "core-js": "^2.6.10", + "d3-interpolate": "^1.3.0", + "d3-scale": "^2.1.0", + "d3-shape": "^1.2.0", + "lodash": "^4.17.5", + "prop-types": "^15.6.0", + "react-resize-detector": "^2.3.0", + "react-smooth": "^1.0.5", + "recharts-scale": "^0.4.2", + "reduce-css-calc": "^1.3.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0", + "react-dom": "^15.0.0 || ^16.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.4.tgz", + "integrity": "sha512-e7MCnuD1+gtY9N7TYxzB+QXvi4s30kvNqVbI1p5m4rf47GusEQaEHxi8zvlZkdOOZ90UhpGHcnkYlyYkUJ2JoQ==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.", + "hasInstallScript": true + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dev": true, + "dependencies": { + "minimatch": "3.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "dependencies": { + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + } + }, + "node_modules/reduce-css-calc/node_modules/balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + }, + "node_modules/reduce-function-call": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", + "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "dependencies": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, + "node_modules/redux-immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redux-immutable/-/redux-immutable-4.0.0.tgz", + "integrity": "sha1-Ohoy32Y2ZGK2NpHw4dw15HK7yfM=", + "peerDependencies": { + "immutable": "^3.8.1 || ^4.0.0-rc.1" + } + }, + "node_modules/redux-thunk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", + "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" + }, + "node_modules/refractor": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.3.1.tgz", + "integrity": "sha512-vaN6R56kLMuBszHSWlwTpcZ8KTMG6aUCok4GrxYDT20UIOXxOc5o6oDc8tNTzSlH3m2sI+Eu9Jo2kVdDcUTWYw==", + "dev": true, + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.23.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "node_modules/regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", + "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/renderkid": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", + "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", + "dev": true, + "dependencies": { + "css-select": "^2.0.2", + "dom-converter": "^0.2", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + } + }, + "node_modules/renderkid/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/renderkid/node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "dependencies": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "node_modules/renderkid/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/renderkid/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "peer": true, + "dependencies": { + "is-finite": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.12.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "peer": true, + "dependencies": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-uncached/node_modules/resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/reselect": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", + "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=", + "dev": true, + "peer": true + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/resolve-url-loader": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz", + "integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "3.0.0", + "camelcase": "5.3.1", + "compose-function": "3.0.3", + "convert-source-map": "1.7.0", + "es6-iterator": "2.0.3", + "loader-utils": "1.2.3", + "postcss": "7.0.21", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/resolve-url-loader/node_modules/emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve-url-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/resolve-url-loader/node_modules/postcss": { + "version": "7.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz", + "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-url-loader/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rework": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", + "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", + "dev": true, + "dependencies": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + } + }, + "node_modules/rework-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", + "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=", + "dev": true + }, + "node_modules/rework/node_modules/convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=", + "dev": true + }, + "node_modules/rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "node_modules/rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true, + "engines": { + "node": "6.* || >= 7.*" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "dependencies": { + "aproba": "^1.1.1" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, + "node_modules/rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true, + "peer": true + }, + "node_modules/rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "peer": true, + "dependencies": { + "rx-lite": "*" + } + }, + "node_modules/rxjs": { + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz", + "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "dependencies": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "bin": { + "sane": "src/cli.js" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/sane/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sanitize.css": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz", + "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==", + "dev": true + }, + "node_modules/sass-loader": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz", + "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.6.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0", + "sass": "^1.3.0", + "webpack": "^4.36.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/sass-loader/node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sass-loader/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sass-loader/node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", + "dev": true + }, + "node_modules/saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "dev": true, + "dependencies": { + "xmlchars": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "dev": true, + "optional": true + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "node_modules/selfsigned": { + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", + "dev": true, + "dependencies": { + "node-forge": "^0.10.0" + } + }, + "node_modules/semantic-ui-react": { + "version": "0.87.3", + "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.87.3.tgz", + "integrity": "sha512-YJgFYEheeFBMm/epZpIpWKF9glgSShdLPiY8zoUi+KJ0IKtLtbI8RbMD/ELbZkY+SO/IWbK/f/86pWt3PVvMVA==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "@semantic-ui-react/event-stack": "^3.1.0", + "classnames": "^2.2.6", + "keyboard-key": "^1.0.4", + "lodash": "^4.17.11", + "prop-types": "^15.6.2", + "react-is": "^16.7.0", + "react-popper": "^1.3.3", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.3.0", + "react-dom": "^16.3.0" + } + }, + "node_modules/semantic-ui-react/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=", + "dev": true, + "dependencies": { + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-favicon/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/serve-favicon/node_modules/safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-getter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", + "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", + "dev": true, + "dependencies": { + "to-object-path": "^0.3.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-3.0.2.tgz", + "integrity": "sha512-npjkVoz+ank0zjlV9F47Fdbjfj/PfXyVhZvGALWsyIYU/qrMzpi6avjKW3/7KeSU2Df3I46BrN1xOI1+6vW0hA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shapefile": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/shapefile/-/shapefile-0.3.1.tgz", + "integrity": "sha1-m7mkKb1ghqDPsDli0Uz99CD/uhI=", + "dependencies": { + "d3-queue": "1", + "iconv-lite": "0.2", + "optimist": "0.3" + }, + "bin": { + "dbfcat": "bin/dbfcat", + "shp2json": "bin/shp2json", + "shpcat": "bin/shpcat" + } + }, + "node_modules/shapefile/node_modules/d3-queue": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-1.2.3.tgz", + "integrity": "sha1-FDpwHPpl/gISkvMhwQ0U6Yq9SRs=" + }, + "node_modules/shapefile/node_modules/iconv-lite": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", + "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "node_modules/shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "peer": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/socket.io-client": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-3.1.3.tgz", + "integrity": "sha512-4sIGOGOmCg3AOgGi7EEr6ZkTZRkrXwub70bBB/F0JSkMOUFpA77WsL87o34DffQQ31PkbMUIadGOk+3tx1KGbw==", + "dependencies": { + "@types/component-emitter": "^1.2.10", + "backo2": "~1.0.2", + "component-emitter": "~1.3.0", + "debug": "~4.3.1", + "engine.io-client": "~4.1.0", + "parseuri": "0.0.6", + "socket.io-parser": "~4.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", + "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "dependencies": { + "@types/component-emitter": "^1.2.10", + "component-emitter": "~1.3.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", + "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs-client": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.0.tgz", + "integrity": "sha512-8Dt3BDi4FYNrCFGTL/HtwVzkARrENdwOUf1ZoW/9p3M8lZdFT35jVdrHza+qgxuG9H3/shR4cuX/X9umUrjP8Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.4.7" + } + }, + "node_modules/sockjs-client/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/sockjs/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "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" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.4.tgz", + "integrity": "sha512-IPDJfugEGbfizBwBZRZ3xpccMdRyP5lqsBWXGQWimVjua/ccLCeMOAVjlc1R7LxFjo5sEDhyNIXd8mo/AiDS9w==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", + "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", + "dev": true + }, + "node_modules/static-eval": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz", + "integrity": "sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==", + "dependencies": { + "escodegen": "^1.11.1" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-module": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/static-module/-/static-module-2.2.5.tgz", + "integrity": "sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ==", + "dependencies": { + "concat-stream": "~1.6.0", + "convert-source-map": "^1.5.1", + "duplexer2": "~0.1.4", + "escodegen": "~1.9.0", + "falafel": "^2.1.0", + "has": "^1.0.1", + "magic-string": "^0.22.4", + "merge-source-map": "1.0.4", + "object-inspect": "~1.4.0", + "quote-stream": "~1.0.2", + "readable-stream": "~2.3.3", + "shallow-copy": "~0.0.1", + "static-eval": "^2.0.0", + "through2": "~2.0.3" + } + }, + "node_modules/static-module/node_modules/escodegen": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", + "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", + "dependencies": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/static-module/node_modules/esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/static-module/node_modules/object-inspect": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.4.1.tgz", + "integrity": "sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==" + }, + "node_modules/static-module/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-module/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/store2": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/store2/-/store2-2.12.0.tgz", + "integrity": "sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw==", + "dev": true + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "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" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "dependencies": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", + "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", + "integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.padstart": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.padstart/-/string.prototype.padstart-3.1.2.tgz", + "integrity": "sha512-HDpngIP3pd0DeazrfqzuBrQZa+D2arKWquEHfGt5LzVjd+roLC3cjqVI0X8foaZz5rrrhcu8oJAQamW8on9dqw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-color": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", + "integrity": "sha1-EG9l09PmotlAHKwOsM6LinArT3s=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", + "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", + "dev": true, + "dependencies": { + "babel-extract-comments": "^1.0.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/style-loader": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/style-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/style-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/style-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/style-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/stylehacks/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/stylehacks/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stylehacks/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylehacks/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/success-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/success-symbol/-/success-symbol-0.1.0.tgz", + "integrity": "sha1-JAIuSG878c3KCUKDt2nEctO3KJc=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sugarss": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz", + "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.2" + } + }, + "node_modules/sugarss/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/sugarss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sugarss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "node_modules/svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/svgo/node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/svgo/node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/symbol.prototype.description": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/symbol.prototype.description/-/symbol.prototype.description-1.0.4.tgz", + "integrity": "sha512-fZkHwJ8ZNRVRzF/+/2OtygyyH06CjC0YZAQRHu9jKKw8RXlJpbizEHvGRUu22Qkg182wJk1ugb5Aovcv3UPrww==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.2" + }, + "engines": { + "node": ">= 0.11.15" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/syncod": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/syncod/-/syncod-0.0.1.tgz", + "integrity": "sha512-KHDsGQ4UcP+wSMaqH7wjH4DHxeHKRlmEO5jlSVCS+0x9xA4ZhdKYg/ameGF7RXaFDUcsti6Zj5s5W1Z4/YsbHA==" + }, + "node_modules/table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tailwindcss": { + "version": "1.9.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.9.6.tgz", + "integrity": "sha512-nY8WYM/RLPqGsPEGEV2z63riyQPcHYZUJpAwdyBzVpxQHOHqHE+F/fvbCeXhdF1+TA5l72vSkZrtYCB9hRcwkQ==", + "dependencies": { + "@fullhuman/postcss-purgecss": "^2.1.2", + "autoprefixer": "^9.4.5", + "browserslist": "^4.12.0", + "bytes": "^3.0.0", + "chalk": "^3.0.0 || ^4.0.0", + "color": "^3.1.2", + "detective": "^5.2.0", + "fs-extra": "^8.0.0", + "html-tags": "^3.1.0", + "lodash": "^4.17.20", + "node-emoji": "^1.8.1", + "normalize.css": "^8.0.1", + "object-hash": "^2.0.3", + "postcss": "^7.0.11", + "postcss-functions": "^3.0.0", + "postcss-js": "^2.0.0", + "postcss-nested": "^4.1.1", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^4.1.0", + "pretty-hrtime": "^1.0.3", + "reduce-css-calc": "^2.1.6", + "resolve": "^1.14.2" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/tailwindcss/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/tailwindcss/node_modules/autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "dependencies": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + }, + "node_modules/tailwindcss/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/tailwindcss/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/tailwindcss/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/tailwindcss/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/tailwindcss/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/tailwindcss/node_modules/postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/tailwindcss/node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + }, + "node_modules/tailwindcss/node_modules/postcss/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tailwindcss/node_modules/postcss/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tailwindcss/node_modules/postcss/node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tailwindcss/node_modules/postcss/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/tailwindcss/node_modules/postcss/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/tailwindcss/node_modules/postcss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tailwindcss/node_modules/reduce-css-calc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", + "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", + "dependencies": { + "css-unit-converter": "^1.1.1", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/tailwindcss/node_modules/reduce-css-calc/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/tailwindcss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tailwindcss/node_modules/supports-color/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tailwindcss/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/telejson": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-5.1.0.tgz", + "integrity": "sha512-Yy0N2OV0mosmr1SCZEm3Ezhu/oi5Dbao5RqauZu4+VI5I/XtVBHXajRk0txuqbFYtKdzzWGDZFGSif9ovVLjEA==", + "dev": true, + "dependencies": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.1", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.20", + "memoizerific": "^1.11.3" + } + }, + "node_modules/telejson/node_modules/isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-paginator": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/terminal-paginator/-/terminal-paginator-2.0.2.tgz", + "integrity": "sha512-IZMT5ECF9p4s+sNCV8uvZSW9E1+9zy9Ji9xz2oee8Jfo7hUFpauyjxkhfRcIH6Lu3Wdepv5D1kVRc8Hx74/LfQ==", + "dev": true, + "dependencies": { + "debug": "^2.6.6", + "extend-shallow": "^2.0.1", + "log-utils": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terminal-paginator/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/terminal-paginator/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-3.1.0.tgz", + "integrity": "sha512-cjdZte66fYkZ65rQ2oJfrdCAkkhJA7YLYk5eGOcGCSGlq0ieZupRdjedSQXYknMPo2IveQL+tPdrxUkERENCFA==", + "dev": true, + "dependencies": { + "cacache": "^15.0.5", + "find-cache-dir": "^3.3.1", + "jest-worker": "^26.2.1", + "p-limit": "^3.0.2", + "schema-utils": "^2.6.6", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.8.0", + "webpack-sources": "^1.4.3" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/cacache": { + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz", + "integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==", + "dev": true, + "dependencies": { + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/terser-webpack-plugin/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser-webpack-plugin/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser-webpack-plugin/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/terser-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "dependencies": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/test-exclude/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/test-exclude/node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/test-exclude/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/test-exclude/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/test-exclude/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/test-exclude/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/test-exclude/node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/test-exclude/node_modules/read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "node_modules/throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "dev": true, + "optional": true + }, + "node_modules/tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/toggle-array": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toggle-array/-/toggle-array-1.0.1.tgz", + "integrity": "sha1-y/WEB5K9UJfzMReugkyTKv/ofVg=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/topojson": { + "version": "1.6.27", + "resolved": "https://registry.npmjs.org/topojson/-/topojson-1.6.27.tgz", + "integrity": "sha1-rb4zpn4vFnPTON8SZErSD8ILQu0=", + "deprecated": "Use topojson-client, topojson-server or topojson-simplify directly.", + "dependencies": { + "d3": "3", + "d3-geo-projection": "0.2", + "d3-queue": "2", + "optimist": "0.3", + "rw": "1", + "shapefile": "0.3" + }, + "bin": { + "topojson": "bin/topojson", + "topojson-geojson": "bin/topojson-geojson", + "topojson-group": "bin/topojson-group", + "topojson-merge": "bin/topojson-merge", + "topojson-svg": "bin/topojson-svg" + } + }, + "node_modules/toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", + "dev": true + }, + "node_modules/tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "dev": true + }, + "node_modules/ts-dedent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.1.0.tgz", + "integrity": "sha512-HbmrG+lCgk5W8LQTALxBxQRBDeAhQKRzdqVhHLUkVd5nYT+b6zDzbRMjiA8wqrWDa33X09WdnW4zEsdwQArTaw==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-essentials": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", + "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" + }, + "node_modules/ts-pnp": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", + "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/typescript": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", + "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.25", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.25.tgz", + "integrity": "sha512-8NFExdfI24Ny8R3Vc6+uUytP/I7dpqk3JERlvxPWlrtx5YboqCgxAXYKPAifbPLV2zKbgmmPL53ufW7mUC/VOQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "dependencies": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uglify-js/node_modules/commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz", + "integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.0", + "has-symbols": "^1.0.0", + "which-boxed-primitive": "^1.0.1" + } + }, + "node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "dev": true + }, + "node_modules/unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value/node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" + }, + "node_modules/uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/url-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/url-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/url-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/url-parse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/use-composed-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz", + "integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==", + "dependencies": { + "ts-essentials": "^2.0.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", + "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz", + "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==", + "dependencies": { + "use-isomorphic-layout-effect": "^1.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "dev": true, + "dependencies": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, + "node_modules/walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "dependencies": { + "makeerror": "1.0.x" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/warning-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/warning-symbol/-/warning-symbol-0.1.0.tgz", + "integrity": "sha1-uzHdEbeg+dZ6su2V9Fe2WCW7rSE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "optionalDependencies": { + "chokidar": "^3.4.1", + "watchpack-chokidar2": "^2.0.1" + } + }, + "node_modules/watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "dev": true, + "optional": true, + "dependencies": { + "chokidar": "^2.1.8" + } + }, + "node_modules/watchpack-chokidar2/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dev": true, + "optional": true, + "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" + } + }, + "node_modules/watchpack-chokidar2/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "node_modules/webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "dev": true, + "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.5.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.7.4", + "webpack-sources": "^1.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + }, + "webpack-command": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz", + "integrity": "sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.19", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 6.14.4" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/webpack-bundle-analyzer/node_modules/ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "dev": true, + "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" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "peerDependencies": { + "webpack": "4.x.x" + } + }, + "node_modules/webpack-cli/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/webpack-cli/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/webpack-cli/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/webpack-cli/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/webpack-cli/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack-cli/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/webpack-cli/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "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" + } + }, + "node_modules/webpack-cli/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", + "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", + "dev": true, + "dependencies": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack-dev-server": { + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz", + "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", + "dev": true, + "dependencies": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 6.11.5" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack-dev-server/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dev": true, + "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" + } + }, + "node_modules/webpack-dev-server/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/webpack-dev-server/node_modules/cliui/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/cliui/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/webpack-dev-server/node_modules/is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-dev-server/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/webpack-dev-server/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/string-width/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/string-width/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/webpack-dev-server/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "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" + } + }, + "node_modules/webpack-dev-server/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/webpack-filter-warnings-plugin": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/webpack-filter-warnings-plugin/-/webpack-filter-warnings-plugin-1.2.1.tgz", + "integrity": "sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg==", + "dev": true, + "engines": { + "node": ">= 4.3 < 5.0.0 || >= 5.10" + }, + "peerDependencies": { + "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, + "node_modules/webpack-hot-middleware": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.25.0.tgz", + "integrity": "sha512-xs5dPOrGPCzuRXNi8F6rwhawWvQQkeli5Ro48PRuQh8pYPCPmNnltP9itiUPT4xI8oW+y0m59lyyeQk54s5VgA==", + "dev": true, + "dependencies": { + "ansi-html": "0.0.7", + "html-entities": "^1.2.0", + "querystring": "^0.2.0", + "strip-ansi": "^3.0.0" + } + }, + "node_modules/webpack-hot-middleware/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-hot-middleware/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "dependencies": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-log/node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-manifest-plugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz", + "integrity": "sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ==", + "dev": true, + "dependencies": { + "fs-extra": "^7.0.0", + "lodash": ">=3.5 <5", + "object.entries": "^1.1.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.11.5" + }, + "peerDependencies": { + "webpack": "2 || 3 || 4" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/webpack-sources/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.2.2.tgz", + "integrity": "sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==", + "dev": true, + "dependencies": { + "debug": "^3.0.0" + } + }, + "node_modules/webpack-virtual-modules/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/webpack/node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/webpack/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==", + "dev": true + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/window-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-1.1.1.tgz", + "integrity": "sha512-5D/9vujkmVQ7pSmc0SCBmHXbkv6eaHwXEx65MywhmUMsI8sGqJ972APq1lotfcwMKPFLuCFfL8xGHLIp7jaBmA==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "is-number": "^3.0.0" + }, + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "dev": true, + "dependencies": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston/node_modules/async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true + }, + "node_modules/winston/node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/workbox-background-sync": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz", + "integrity": "sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz", + "integrity": "sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-build": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-4.3.1.tgz", + "integrity": "sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.3.4", + "@hapi/joi": "^15.0.0", + "common-tags": "^1.8.0", + "fs-extra": "^4.0.2", + "glob": "^7.1.3", + "lodash.template": "^4.4.0", + "pretty-bytes": "^5.1.0", + "stringify-object": "^3.3.0", + "strip-comments": "^1.0.2", + "workbox-background-sync": "^4.3.1", + "workbox-broadcast-update": "^4.3.1", + "workbox-cacheable-response": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-expiration": "^4.3.1", + "workbox-google-analytics": "^4.3.1", + "workbox-navigation-preload": "^4.3.1", + "workbox-precaching": "^4.3.1", + "workbox-range-requests": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1", + "workbox-streams": "^4.3.1", + "workbox-sw": "^4.3.1", + "workbox-window": "^4.3.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/workbox-build/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/workbox-build/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/workbox-build/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz", + "integrity": "sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-core": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-4.3.1.tgz", + "integrity": "sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg==", + "dev": true + }, + "node_modules/workbox-expiration": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-4.3.1.tgz", + "integrity": "sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-google-analytics": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz", + "integrity": "sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg==", + "dev": true, + "dependencies": { + "workbox-background-sync": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz", + "integrity": "sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-precaching": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-4.3.1.tgz", + "integrity": "sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-range-requests": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz", + "integrity": "sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-routing": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-4.3.1.tgz", + "integrity": "sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-strategies": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-4.3.1.tgz", + "integrity": "sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-streams": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-4.3.1.tgz", + "integrity": "sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/workbox-sw": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-4.3.1.tgz", + "integrity": "sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w==", + "dev": true + }, + "node_modules/workbox-webpack-plugin": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz", + "integrity": "sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.0.0", + "json-stable-stringify": "^1.0.1", + "workbox-build": "^4.3.1" + }, + "engines": { + "node": ">=4.0.0" + }, + "peerDependencies": { + "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, + "node_modules/workbox-window": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-4.3.1.tgz", + "integrity": "sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg==", + "dev": true, + "dependencies": { + "workbox-core": "^4.3.1" + } + }, + "node_modules/worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "dependencies": { + "errno": "~0.1.7" + } + }, + "node_modules/worker-rpc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz", + "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", + "dev": true, + "dependencies": { + "microevent.ts": "~0.1.1" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "peer": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", + "dev": true + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xregexp": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz", + "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", + "dev": true, + "dependencies": { + "@babel/runtime-corejs3": "^7.12.1" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/cli": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.13.10.tgz", + "integrity": "sha512-lYSBC7B4B9hJ7sv0Ojx1BrGhuzCoOIYfLjd+Xpd4rOzdS+a47yi8voV8vFkfjlZR1N5qZO7ixOCbobUdT304PQ==", + "dev": true, + "requires": { + "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents", + "chokidar": "^3.4.0", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + }, + "@babel/compat-data": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz", + "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==", + "dev": true + }, + "@babel/core": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.10.tgz", + "integrity": "sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.9", + "@babel/helper-compilation-targets": "^7.13.10", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helpers": "^7.13.10", + "@babel/parser": "^7.13.10", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", + "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "dev": true, + "requires": { + "@babel/types": "^7.13.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", + "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", + "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz", + "integrity": "sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.8", + "@babel/helper-validator-option": "^7.12.17", + "browserslist": "^4.14.5", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.13.11", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz", + "integrity": "sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-member-expression-to-functions": "^7.13.0", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-split-export-declaration": "^7.12.13" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", + "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "regexpu-core": "^4.7.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz", + "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz", + "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==", + "dev": true, + "requires": { + "@babel/types": "^7.13.0" + } + }, + "@babel/helper-function-name": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", + "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz", + "integrity": "sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==", + "dev": true, + "requires": { + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", + "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-module-imports": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", + "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-module-transforms": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.12.tgz", + "integrity": "sha512-7zVQqMO3V+K4JOOj40kxiCrMf6xlQAkewBB0eu2b03OO/Q21ZutOzjpfD79A5gtE/2OWi1nv625MrDlGlkbknQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-replace-supers": "^7.13.12", + "@babel/helper-simple-access": "^7.13.12", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.12.11", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", + "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz", + "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-wrap-function": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", + "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-simple-access": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", + "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "dev": true, + "requires": { + "@babel/types": "^7.13.12" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", + "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz", + "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "@babel/helpers": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", + "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", + "dev": true, + "requires": { + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" + } + }, + "@babel/highlight": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", + "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.12.tgz", + "integrity": "sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==", + "dev": true + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz", + "integrity": "sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.13.12" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz", + "integrity": "sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-remap-async-to-generator": "^7.13.0", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz", + "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.13.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.13.5.tgz", + "integrity": "sha512-i0GDfVNuoapwiheevUOuSW67mInqJ8qw7uWfpjNVeHMn143kXblEy/bmL9AdZ/0yf/4BMQeWXezK0tQIvNPqag==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-decorators": "^7.12.13" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz", + "integrity": "sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-default-from": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.12.13.tgz", + "integrity": "sha512-idIsBT+DGXdOHL82U+8bwX4goHm/z10g8sGGrQroh+HCRcm7mDv/luaGdWJQMTuCX2FsdXS7X0Nyyzp4znAPJA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-syntax-export-default-from": "^7.12.13" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz", + "integrity": "sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz", + "integrity": "sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz", + "integrity": "sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz", + "integrity": "sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz", + "integrity": "sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", + "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.8", + "@babel/helper-compilation-targets": "^7.13.8", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.13.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz", + "integrity": "sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz", + "integrity": "sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz", + "integrity": "sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz", + "integrity": "sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.12.13.tgz", + "integrity": "sha512-Rw6aIXGuqDLr6/LoBBYE57nKOzQpz/aDkKlMqEwH+Vp0MXbG6H/TfRjaY343LKxzAKAMXIHsQ8JzaZKuDZ9MwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-default-from": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.12.13.tgz", + "integrity": "sha512-gVry0zqoums0hA+EniCYK3gABhjYSLX1dVuwYpPw9DrLNA4/GovXySHVg4FGRsZht09ON/5C2NVx3keq+qqVGQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.13.tgz", + "integrity": "sha512-J/RYxnlSLXZLVR7wTRsozxKT8qbsx1mNKJzXEEjQ0Kjx1ZACcyHgbanNWNCFtc36IzuWhYWPpvJFFoexoOWFmA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz", + "integrity": "sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", + "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.13.tgz", + "integrity": "sha512-cHP3u1JiUiG2LFDKbXnwVad81GvfyIOmCD6HIEId6ojrY0Drfy2q1jw7BwN7dE84+kTnBjLkXoL3IEy/3JPu2w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz", + "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz", + "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-remap-async-to-generator": "^7.13.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz", + "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz", + "integrity": "sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz", + "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-split-export-declaration": "^7.12.13", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz", + "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz", + "integrity": "sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz", + "integrity": "sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz", + "integrity": "sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz", + "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.13.0.tgz", + "integrity": "sha512-EXAGFMJgSX8gxWD7PZtW/P6M+z74jpx3wm/+9pn+c2dOawPpBkUX7BrfyPvo6ZpXbgRIEuwgwDb/MGlKvu2pOg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-flow": "^7.12.13" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz", + "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz", + "integrity": "sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz", + "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz", + "integrity": "sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz", + "integrity": "sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz", + "integrity": "sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-simple-access": "^7.12.13", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz", + "integrity": "sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.13.0", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-identifier": "^7.12.11", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz", + "integrity": "sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz", + "integrity": "sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz", + "integrity": "sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz", + "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/helper-replace-supers": "^7.12.13" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz", + "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz", + "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.13.10.tgz", + "integrity": "sha512-E+aCW9j7mLq01tOuGV08YzLBt+vSyr4bOPT75B6WrAlrUfmOYOZ/yWk847EH0dv0xXiCihWLEmlX//O30YhpIw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.13.tgz", + "integrity": "sha512-MprESJzI9O5VnJZrL7gg1MpdqmiFcUv41Jc7SahxYsNP2kDkFqClxxTZq+1Qv4AFCamm+GXMRDQINNn+qrxmiA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.13.12.tgz", + "integrity": "sha512-jcEI2UqIcpCqB5U5DRxIl0tQEProI2gcu+g8VTIqxLO5Iidojb4d77q+fwGseCvd8af/lJ9masp4QWzBXFE2xA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/types": "^7.13.12" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.17.tgz", + "integrity": "sha512-BPjYV86SVuOaudFhsJR1zjgxxOhJDt6JHNoD48DxWEIxUCAMjV1ys6DYw4SDYZh0b1QsS2vfIA9t/ZsQGsDOUQ==", + "dev": true, + "requires": { + "@babel/plugin-transform-react-jsx": "^7.12.17" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.13.tgz", + "integrity": "sha512-FXYw98TTJ125GVCCkFLZXlZ1qGcsYqNQhVBQcZjyrwf8FEUtVfKIoidnO8S0q+KBQpDYNTmiGo1gn67Vti04lQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.13.tgz", + "integrity": "sha512-O5JJi6fyfih0WfDgIJXksSPhGP/G0fQpfxYy87sDc+1sFmsCS6wr3aAn+whbzkhbjtq4VMqLRaSzR6IsshIC0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz", + "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz", + "integrity": "sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz", + "integrity": "sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", + "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz", + "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz", + "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz", + "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz", + "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz", + "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.13.0.tgz", + "integrity": "sha512-elQEwluzaU8R8dbVuW2Q2Y8Nznf7hnjM7+DSCd14Lo5fF63C9qNLbwZYbmZrtV9/ySpSUpkRpQXvJb6xyu4hCQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-typescript": "^7.12.13" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz", + "integrity": "sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz", + "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/preset-env": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.12.tgz", + "integrity": "sha512-JzElc6jk3Ko6zuZgBtjOd01pf9yYDEIH8BcqVuYIuOkzOwDesoa/Nz4gIo4lBG6K861KTV9TvIgmFuT6ytOaAA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.12", + "@babel/helper-compilation-targets": "^7.13.10", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-option": "^7.12.17", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.13.12", + "@babel/plugin-proposal-async-generator-functions": "^7.13.8", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-dynamic-import": "^7.13.8", + "@babel/plugin-proposal-export-namespace-from": "^7.12.13", + "@babel/plugin-proposal-json-strings": "^7.13.8", + "@babel/plugin-proposal-logical-assignment-operators": "^7.13.8", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-numeric-separator": "^7.12.13", + "@babel/plugin-proposal-object-rest-spread": "^7.13.8", + "@babel/plugin-proposal-optional-catch-binding": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/plugin-proposal-private-methods": "^7.13.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.13", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.12.13", + "@babel/plugin-transform-arrow-functions": "^7.13.0", + "@babel/plugin-transform-async-to-generator": "^7.13.0", + "@babel/plugin-transform-block-scoped-functions": "^7.12.13", + "@babel/plugin-transform-block-scoping": "^7.12.13", + "@babel/plugin-transform-classes": "^7.13.0", + "@babel/plugin-transform-computed-properties": "^7.13.0", + "@babel/plugin-transform-destructuring": "^7.13.0", + "@babel/plugin-transform-dotall-regex": "^7.12.13", + "@babel/plugin-transform-duplicate-keys": "^7.12.13", + "@babel/plugin-transform-exponentiation-operator": "^7.12.13", + "@babel/plugin-transform-for-of": "^7.13.0", + "@babel/plugin-transform-function-name": "^7.12.13", + "@babel/plugin-transform-literals": "^7.12.13", + "@babel/plugin-transform-member-expression-literals": "^7.12.13", + "@babel/plugin-transform-modules-amd": "^7.13.0", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/plugin-transform-modules-systemjs": "^7.13.8", + "@babel/plugin-transform-modules-umd": "^7.13.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.13", + "@babel/plugin-transform-new-target": "^7.12.13", + "@babel/plugin-transform-object-super": "^7.12.13", + "@babel/plugin-transform-parameters": "^7.13.0", + "@babel/plugin-transform-property-literals": "^7.12.13", + "@babel/plugin-transform-regenerator": "^7.12.13", + "@babel/plugin-transform-reserved-words": "^7.12.13", + "@babel/plugin-transform-shorthand-properties": "^7.12.13", + "@babel/plugin-transform-spread": "^7.13.0", + "@babel/plugin-transform-sticky-regex": "^7.12.13", + "@babel/plugin-transform-template-literals": "^7.13.0", + "@babel/plugin-transform-typeof-symbol": "^7.12.13", + "@babel/plugin-transform-unicode-escapes": "^7.12.13", + "@babel/plugin-transform-unicode-regex": "^7.12.13", + "@babel/preset-modules": "^0.1.4", + "@babel/types": "^7.13.12", + "babel-plugin-polyfill-corejs2": "^0.1.4", + "babel-plugin-polyfill-corejs3": "^0.1.3", + "babel-plugin-polyfill-regenerator": "^0.1.2", + "core-js-compat": "^3.9.0", + "semver": "^6.3.0" + } + }, + "@babel/preset-flow": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.12.13.tgz", + "integrity": "sha512-gcEjiwcGHa3bo9idURBp5fmJPcyFPOszPQjztXrOjUE2wWVqc6fIVJPgWPIQksaQ5XZ2HWiRsf2s1fRGVjUtVw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-transform-flow-strip-types": "^7.12.13" + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.13.tgz", + "integrity": "sha512-TYM0V9z6Abb6dj1K7i5NrEhA13oS5ujUYQYDfqIBXYHOc2c2VkFgc+q9kyssIyUfy4/hEwqrgSlJ/Qgv8zJLsA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-transform-react-display-name": "^7.12.13", + "@babel/plugin-transform-react-jsx": "^7.12.13", + "@babel/plugin-transform-react-jsx-development": "^7.12.12", + "@babel/plugin-transform-react-pure-annotations": "^7.12.1" + } + }, + "@babel/preset-typescript": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.13.0.tgz", + "integrity": "sha512-LXJwxrHy0N3f6gIJlYbLta1D9BDtHpQeqwzM0LIfjDlr6UE/D5Mc7W4iDiQzaE+ks0sTjT26ArcHWnJVt0QiHw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-option": "^7.12.17", + "@babel/plugin-transform-typescript": "^7.13.0" + } + }, + "@babel/register": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.13.8.tgz", + "integrity": "sha512-yCVtABcmvQjRsX2elcZFUV5Q5kDDpHdtXKKku22hNDma60lYuhKmtp1ykZ/okRCPLT2bR5S+cA1kvtBdAFlDTQ==", + "dev": true, + "requires": { + "find-cache-dir": "^2.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "pirates": "^4.0.0", + "source-map-support": "^0.5.16" + } + }, + "@babel/runtime": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", + "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.13.10.tgz", + "integrity": "sha512-x/XYVQ1h684pp1mJwOV4CyvqZXqbc8CMsMGUnAbuc82ZCdv1U63w5RSUzgDSXQHG5Rps/kiksH6g2D5BuaKyXg==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "@babel/traverse": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", + "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.0", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.13.0", + "@babel/types": "^7.13.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz", + "integrity": "sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@csstools/convert-colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", + "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==", + "dev": true + }, + "@csstools/normalize.css": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", + "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==", + "dev": true + }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dev": true, + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "dev": true, + "requires": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" + } + }, + "@emotion/core": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.1.1.tgz", + "integrity": "sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@emotion/cache": "^10.0.27", + "@emotion/css": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" + } + }, + "@emotion/css": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", + "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", + "dev": true, + "requires": { + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3", + "babel-plugin-emotion": "^10.0.27" + } + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "dev": true + }, + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "dev": true, + "requires": { + "@emotion/memoize": "0.7.4" + } + }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "dev": true + }, + "@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "dev": true, + "requires": { + "@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": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==", + "dev": true + }, + "@emotion/styled": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz", + "integrity": "sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==", + "dev": true, + "requires": { + "@emotion/styled-base": "^10.0.27", + "babel-plugin-emotion": "^10.0.27" + } + }, + "@emotion/styled-base": { + "version": "10.0.31", + "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.0.31.tgz", + "integrity": "sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@emotion/is-prop-valid": "0.8.8", + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3" + } + }, + "@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", + "dev": true + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "dev": true + }, + "@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", + "dev": true + }, + "@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==", + "dev": true + }, + "@fullhuman/postcss-purgecss": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.3.0.tgz", + "integrity": "sha512-qnKm5dIOyPGJ70kPZ5jiz0I9foVOic0j+cOzNDoo8KoCf6HjicIZ99UfO2OmE7vCYSKAAepEwJtNzpiiZAh9xw==", + "requires": { + "postcss": "7.0.32", + "purgecss": "^2.3.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", + "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==", + "dev": true + }, + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==", + "dev": true + }, + "@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==", + "dev": true + }, + "@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "dev": true, + "requires": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + } + }, + "@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", + "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "dev": true, + "requires": { + "@hapi/hoek": "^8.3.0" + } + }, + "@hypnosphi/create-react-context": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz", + "integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==", + "requires": { + "gud": "^1.0.0", + "warning": "^4.0.3" + } + }, + "@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", + "dev": true, + "requires": {} + }, + "@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.tgz", + "integrity": "sha512-+nb9vWloHNNMFHjGofEam3wopE3m1yuambrrd/fnPc+lFOMB9ROTqQlche9ByFWNkdNqfSgR/kkQtQ8DzEWt2w==", + "dev": true, + "optional": true, + "requires": { + "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" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "@openreplay/sourcemap-uploader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@openreplay/sourcemap-uploader/-/sourcemap-uploader-3.0.0.tgz", + "integrity": "sha512-E1zQkHI9QZ0UYiBtPAweA9o0cuIWwQZfbc/tnUNdY9XF4S0MdIKGVqVh1Tkf4myzLxY4w/4il0ePLMZe1oXhfw==", + "dev": true, + "requires": { + "argparse": "^1.0.10", + "glob-promise": "^3.4.0" + } + }, + "@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz", + "integrity": "sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ==", + "dev": true, + "requires": { + "ansi-html": "^0.0.7", + "error-stack-parser": "^2.0.6", + "html-entities": "^1.2.1", + "native-url": "^0.2.6", + "schema-utils": "^2.6.5", + "source-map": "^0.7.3" + } + }, + "@popperjs/core": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.1.tgz", + "integrity": "sha512-DvJbbn3dUgMxDnJLH+RZQPnXak1h4ZVYQ7CWiFWjQwBFkVajT4rfw2PdpHLTSTwxrYfnoEXkuBiwkDm6tPMQeA==", + "dev": true + }, + "@reach/router": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@reach/router/-/router-1.3.4.tgz", + "integrity": "sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA==", + "dev": true, + "requires": { + "create-react-context": "0.3.0", + "invariant": "^2.2.3", + "prop-types": "^15.6.1", + "react-lifecycles-compat": "^3.0.4" + } + }, + "@semantic-ui-react/event-stack": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.2.tgz", + "integrity": "sha512-Yd0Qf7lPCIjzJ9bZYfurlNu2RDXT6KKSyubHfYK3WjRauhxCsq6Fk2LMRI9DEvShoEU+AsLSv3NGkqXAcVp0zg==", + "requires": { + "exenv": "^1.2.2", + "prop-types": "^15.6.2" + } + }, + "@sentry/browser": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.30.0.tgz", + "integrity": "sha512-rOb58ZNVJWh1VuMuBG1mL9r54nZqKeaIlwSlvzJfc89vyfd7n6tQ1UXMN383QBz/MS5H5z44Hy5eE+7pCrYAfw==", + "requires": { + "@sentry/core": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "requires": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==" + }, + "@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "requires": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@storybook/addons": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.1.21.tgz", + "integrity": "sha512-xo5TGu9EZVCqgh3D1veVnfuGzyKDWWsvOMo18phVqRxj21G3/+hScVyfIYwNTv7Ys5/Ahp9JxJUMXL3V3ny+tw==", + "dev": true, + "requires": { + "@storybook/api": "6.1.21", + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/router": "6.1.21", + "@storybook/theming": "6.1.21", + "core-js": "^3.0.1", + "global": "^4.3.2", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/api": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.1.21.tgz", + "integrity": "sha512-QjZk70VSXMw/wPPoWdMp5Bl9VmkfmGhIz8PALrFLLEZHjzptpfZE2qkGEEJHG0NAksFUv6NxGki2/632dzR7Ug==", + "dev": true, + "requires": { + "@reach/router": "^1.3.3", + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/csf": "0.0.1", + "@storybook/router": "6.1.21", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.1.21", + "@types/reach__router": "^1.3.7", + "core-js": "^3.0.1", + "fast-deep-equal": "^3.1.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.7.1", + "telejson": "^5.0.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/channel-postmessage": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.1.21.tgz", + "integrity": "sha512-SuI/ffqcPT02VNda32k8V0D4XpLm5bIy8CLIs0OAnQg+zt5KjGBpQBngk3q4EaAiOoAhbMWAQiUzRUXfrgkgXg==", + "dev": true, + "requires": { + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/core-events": "6.1.21", + "core-js": "^3.0.1", + "global": "^4.3.2", + "qs": "^6.6.0", + "telejson": "^5.0.2" + } + }, + "@storybook/channels": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.1.21.tgz", + "integrity": "sha512-7WoizMjyHqCyvcWncLexSg9FLPIErWAZL4NvluEthwsHSO2sDybn9mh1pzsFHdYMuTP6ml06Zt9ayWMtIveHDg==", + "dev": true, + "requires": { + "core-js": "^3.0.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/client-api": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.1.21.tgz", + "integrity": "sha512-uLFXQ5z1LLWYnw1w+YUJPzIPRVlwCCvM2Si37aHDZn1F3fnbMg+huEhEqIQ1TTTw3wiJoTeGuShYvqyaiNwq/w==", + "dev": true, + "requires": { + "@storybook/addons": "6.1.21", + "@storybook/channel-postmessage": "6.1.21", + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/csf": "0.0.1", + "@types/qs": "^6.9.0", + "@types/webpack-env": "^1.15.3", + "core-js": "^3.0.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "memoizerific": "^1.11.3", + "qs": "^6.6.0", + "regenerator-runtime": "^0.13.7", + "stable": "^0.1.8", + "store2": "^2.7.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/client-logger": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.1.21.tgz", + "integrity": "sha512-QJV+gnVM2fQ4M7lSkRLCXkOw/RU+aEtUefo9TAnXxPHK3UGG+DyvLmha6fHGaz9GAcFxyWtgqCyVOhMe03Q35g==", + "dev": true, + "requires": { + "core-js": "^3.0.1", + "global": "^4.3.2" + } + }, + "@storybook/components": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.1.21.tgz", + "integrity": "sha512-2NjkyS1yeYXlRY7azt88woqd6eqJA00oloIxgMAFLVpRmvFxoHalY61wNrvxl2QSu9cNofp984AbGc8gPbizBA==", + "dev": true, + "requires": { + "@popperjs/core": "^2.5.4", + "@storybook/client-logger": "6.1.21", + "@storybook/csf": "0.0.1", + "@storybook/theming": "6.1.21", + "@types/overlayscrollbars": "^1.9.0", + "@types/react-color": "^3.0.1", + "@types/react-syntax-highlighter": "11.0.4", + "core-js": "^3.0.1", + "fast-deep-equal": "^3.1.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "markdown-to-jsx": "^6.11.4", + "memoizerific": "^1.11.3", + "overlayscrollbars": "^1.10.2", + "polished": "^3.4.4", + "react-color": "^2.17.0", + "react-popper-tooltip": "^3.1.1", + "react-syntax-highlighter": "^13.5.0", + "react-textarea-autosize": "^8.1.1", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/core": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-6.1.21.tgz", + "integrity": "sha512-ITqSid3VVL5/fkx7Wwu7QfD2Y5xjl3V6p7yUpLSzP8GpBnCHKDvJ4pFJUdJlGQ0mnGz6ACa0qVnSc+V0hiy1sA==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-decorators": "^7.12.1", + "@babel/plugin-proposal-export-default-from": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.1", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.1", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.1", + "@babel/preset-typescript": "^7.12.1", + "@babel/register": "^7.12.1", + "@storybook/addons": "6.1.21", + "@storybook/api": "6.1.21", + "@storybook/channel-postmessage": "6.1.21", + "@storybook/channels": "6.1.21", + "@storybook/client-api": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/components": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/csf": "0.0.1", + "@storybook/node-logger": "6.1.21", + "@storybook/router": "6.1.21", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.1.21", + "@storybook/ui": "6.1.21", + "@types/glob-base": "^0.3.0", + "@types/micromatch": "^4.0.1", + "@types/node-fetch": "^2.5.4", + "airbnb-js-shims": "^2.2.1", + "ansi-to-html": "^0.6.11", + "autoprefixer": "^9.7.2", + "babel-loader": "^8.0.6", + "babel-plugin-emotion": "^10.0.20", + "babel-plugin-macros": "^2.8.0", + "babel-preset-minify": "^0.5.0 || 0.6.0-alpha.5", + "better-opn": "^2.0.0", + "boxen": "^4.1.0", + "case-sensitive-paths-webpack-plugin": "^2.2.0", + "chalk": "^4.0.0", + "cli-table3": "0.6.0", + "commander": "^5.0.0", + "core-js": "^3.0.1", + "cpy": "^8.1.1", + "css-loader": "^3.5.3", + "detect-port": "^1.3.0", + "dotenv-webpack": "^1.7.0", + "ejs": "^3.1.2", + "express": "^4.17.0", + "file-loader": "^6.0.0", + "file-system-cache": "^1.0.5", + "find-up": "^4.1.0", + "fork-ts-checker-webpack-plugin": "^4.1.4", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "glob-base": "^0.3.0", + "glob-promise": "^3.4.0", + "global": "^4.3.2", + "html-webpack-plugin": "^4.2.1", + "inquirer": "^7.0.0", + "interpret": "^2.0.0", + "ip": "^1.1.5", + "json5": "^2.1.1", + "lazy-universal-dotenv": "^3.0.1", + "micromatch": "^4.0.2", + "node-fetch": "^2.6.0", + "pkg-dir": "^4.2.0", + "pnp-webpack-plugin": "1.6.4", + "postcss-flexbugs-fixes": "^4.1.0", + "postcss-loader": "^3.0.0", + "pretty-hrtime": "^1.0.3", + "qs": "^6.6.0", + "raw-loader": "^4.0.1", + "react-dev-utils": "^11.0.3", + "regenerator-runtime": "^0.13.7", + "resolve-from": "^5.0.0", + "serve-favicon": "^2.5.0", + "shelljs": "^0.8.4", + "stable": "^0.1.8", + "style-loader": "^1.2.1", + "telejson": "^5.0.2", + "terser-webpack-plugin": "^3.0.0", + "ts-dedent": "^2.0.0", + "unfetch": "^4.1.0", + "url-loader": "^4.0.0", + "util-deprecate": "^1.0.2", + "webpack": "^4.44.2", + "webpack-dev-middleware": "^3.7.0", + "webpack-filter-warnings-plugin": "^1.2.1", + "webpack-hot-middleware": "^2.25.0", + "webpack-virtual-modules": "^0.2.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true + }, + "html-webpack-plugin": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz", + "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.20", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + } + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "style-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", + "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + } + } + } + } + }, + "@storybook/core-events": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.1.21.tgz", + "integrity": "sha512-KWqnh1C7M1pT//WfQb3AD60yTR8jL48AfaeLGto2gO9VK7VVgj/EGsrXZP/GTL90ygyExbbBI5gkr7EBTu/HYw==", + "dev": true, + "requires": { + "core-js": "^3.0.1" + } + }, + "@storybook/csf": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", + "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "@storybook/node-logger": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.1.21.tgz", + "integrity": "sha512-wQZZw4n1PG3kGOsczWCBC6+8RagYkrGYDqsVOpUcs5shGbPg5beCXDuzP4nxz2IlsoP9ZtTSaX741H791OIOjA==", + "dev": true, + "requires": { + "@types/npmlog": "^4.1.2", + "chalk": "^4.0.0", + "core-js": "^3.0.1", + "npmlog": "^4.1.2", + "pretty-hrtime": "^1.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@storybook/react": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-6.1.21.tgz", + "integrity": "sha512-j3gq/ssWxRCCH5iCHbP3ihXSGS7lVWh1HpmBmGbbhHGHgdmSPsRjwDXiQGE81EmE7bzbC8NECBhU3zHJ6h1TvA==", + "dev": true, + "requires": { + "@babel/preset-flow": "^7.12.1", + "@babel/preset-react": "^7.12.1", + "@pmmmwh/react-refresh-webpack-plugin": "^0.4.2", + "@storybook/addons": "6.1.21", + "@storybook/core": "6.1.21", + "@storybook/node-logger": "6.1.21", + "@storybook/semver": "^7.3.2", + "@types/webpack-env": "^1.15.3", + "babel-plugin-add-react-displayname": "^0.0.5", + "babel-plugin-named-asset-import": "^0.3.1", + "babel-plugin-react-docgen": "^4.2.1", + "core-js": "^3.0.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "prop-types": "^15.7.2", + "react-dev-utils": "^11.0.3", + "react-docgen-typescript-plugin": "^0.6.2", + "react-refresh": "^0.8.3", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0", + "webpack": "^4.44.2" + } + }, + "@storybook/router": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.1.21.tgz", + "integrity": "sha512-m75WvUhoCBWDVekICAdbkidji/w5hCjHo+M8L13UghpwXWEnyr4/QqvkOb/PcSC8aZzxeMqSCpRQ1o6LWULneg==", + "dev": true, + "requires": { + "@reach/router": "^1.3.3", + "@types/reach__router": "^1.3.7", + "core-js": "^3.0.1", + "global": "^4.3.2", + "memoizerific": "^1.11.3", + "qs": "^6.6.0" + } + }, + "@storybook/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==", + "dev": true, + "requires": { + "core-js": "^3.6.5", + "find-up": "^4.1.0" + } + }, + "@storybook/theming": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.1.21.tgz", + "integrity": "sha512-yq7+/mpdljRdSRJYw/In/9tnDGXIUDe//mhyMftFfrB2mq6zi1yAZpowCerWhiDE2ipGkrfzIYx/Sn7bcaXgqg==", + "dev": true, + "requires": { + "@emotion/core": "^10.1.1", + "@emotion/is-prop-valid": "^0.8.6", + "@emotion/styled": "^10.0.23", + "@storybook/client-logger": "6.1.21", + "core-js": "^3.0.1", + "deep-object-diff": "^1.1.0", + "emotion-theming": "^10.0.19", + "global": "^4.3.2", + "memoizerific": "^1.11.3", + "polished": "^3.4.4", + "resolve-from": "^5.0.0", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/ui": { + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@storybook/ui/-/ui-6.1.21.tgz", + "integrity": "sha512-2nRb5egnSBKbosuR7g5PsuM4XnRLXZUf7TBjwT6eRlomnE2wrWM5DtTLpFeUpDob0SI5hPlOV1xCpPz3XmeyyA==", + "dev": true, + "requires": { + "@emotion/core": "^10.1.1", + "@storybook/addons": "6.1.21", + "@storybook/api": "6.1.21", + "@storybook/channels": "6.1.21", + "@storybook/client-logger": "6.1.21", + "@storybook/components": "6.1.21", + "@storybook/core-events": "6.1.21", + "@storybook/router": "6.1.21", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.1.21", + "@types/markdown-to-jsx": "^6.11.0", + "copy-to-clipboard": "^3.0.8", + "core-js": "^3.0.1", + "core-js-pure": "^3.0.1", + "downshift": "^6.0.6", + "emotion-theming": "^10.0.19", + "fuse.js": "^3.6.1", + "global": "^4.3.2", + "lodash": "^4.17.15", + "markdown-to-jsx": "^6.11.4", + "memoizerific": "^1.11.3", + "polished": "^3.4.4", + "qs": "^6.6.0", + "react-draggable": "^4.0.3", + "react-helmet-async": "^1.0.2", + "react-hotkeys": "2.0.0", + "react-sizeme": "^2.6.7", + "regenerator-runtime": "^0.13.7", + "resolve-from": "^5.0.0", + "store2": "^2.7.1" + } + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig==", + "dev": true + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ==", + "dev": true + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz", + "integrity": "sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w==", + "dev": true + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz", + "integrity": "sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w==", + "dev": true + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz", + "integrity": "sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w==", + "dev": true + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz", + "integrity": "sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w==", + "dev": true + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz", + "integrity": "sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw==", + "dev": true + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz", + "integrity": "sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw==", + "dev": true + }, + "@svgr/babel-preset": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.3.tgz", + "integrity": "sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A==", + "dev": true, + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^4.2.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^4.2.0", + "@svgr/babel-plugin-svg-dynamic-title": "^4.3.3", + "@svgr/babel-plugin-svg-em-dimensions": "^4.2.0", + "@svgr/babel-plugin-transform-react-native-svg": "^4.2.0", + "@svgr/babel-plugin-transform-svg-component": "^4.2.0" + } + }, + "@svgr/core": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-4.3.3.tgz", + "integrity": "sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w==", + "dev": true, + "requires": { + "@svgr/plugin-jsx": "^4.3.3", + "camelcase": "^5.3.1", + "cosmiconfig": "^5.2.1" + }, + "dependencies": { + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz", + "integrity": "sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@svgr/plugin-jsx": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz", + "integrity": "sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w==", + "dev": true, + "requires": { + "@babel/core": "^7.4.5", + "@svgr/babel-preset": "^4.3.3", + "@svgr/hast-util-to-babel-ast": "^4.3.2", + "svg-parser": "^2.0.0" + } + }, + "@svgr/plugin-svgo": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz", + "integrity": "sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w==", + "dev": true, + "requires": { + "cosmiconfig": "^5.2.1", + "merge-deep": "^3.0.2", + "svgo": "^1.2.2" + }, + "dependencies": { + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "@svgr/webpack": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.3.tgz", + "integrity": "sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg==", + "dev": true, + "requires": { + "@babel/core": "^7.4.5", + "@babel/plugin-transform-react-constant-elements": "^7.0.0", + "@babel/preset-env": "^7.4.5", + "@babel/preset-react": "^7.0.0", + "@svgr/core": "^4.3.3", + "@svgr/plugin-jsx": "^4.3.3", + "@svgr/plugin-svgo": "^4.3.1", + "loader-utils": "^1.2.3" + } + }, + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", + "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", + "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/braces": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.0.tgz", + "integrity": "sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==", + "dev": true + }, + "@types/component-emitter": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", + "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==" + }, + "@types/d3": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.38.tgz", + "integrity": "sha1-dvjy6RWa5WKWWy+g5vvuGqZDobw=" + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@types/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-pYHWiDR+EOUN18F9byiAoQNUMZ0=", + "dev": true + }, + "@types/hast": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.1.tgz", + "integrity": "sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==", + "dev": true, + "requires": { + "@types/unist": "*" + } + }, + "@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==", + "dev": true + }, + "@types/is-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.0.tgz", + "integrity": "sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/markdown-to-jsx": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz", + "integrity": "sha512-30nFYpceM/ZEvhGiqWjm5quLUxNeld0HCzJEXMZZDpq53FPkS85mTwkWtCXzCqq8s5JYLgM5W392a02xn8Bdaw==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/micromatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.1.tgz", + "integrity": "sha512-my6fLBvpY70KattTNzYOK6KU1oR1+UCz9ug/JbcF5UrEmeCt9P7DV2t7L8+t18mMPINqGQCE4O8PLOPbI84gxw==", + "dev": true, + "requires": { + "@types/braces": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "14.14.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz", + "integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==", + "dev": true + }, + "@types/node-fetch": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.8.tgz", + "integrity": "sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "@types/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-4QQmOF5KlwfxJ5IGXFIudkeLCdMABz03RcUXu+LCb24zmln8QW6aDjuGl4d4XPVLf2j+FnjelHTP7dvceAFbhA==", + "dev": true + }, + "@types/overlayscrollbars": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@types/overlayscrollbars/-/overlayscrollbars-1.12.0.tgz", + "integrity": "sha512-h/pScHNKi4mb+TrJGDon8Yb06ujFG0mSg12wIO0sWMUF3dQIe2ExRRdNRviaNt9IjxIiOfnRr7FsQAdHwK4sMg==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "dev": true + }, + "@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", + "dev": true + }, + "@types/reach__router": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.3.7.tgz", + "integrity": "sha512-cyBEb8Ef3SJNH5NYEIDGPoMMmYUxROatuxbICusVRQIqZUB85UCt6R2Ok60tKS/TABJsJYaHyNTW3kqbpxlMjg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz", + "integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", + "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==", + "dev": true + } + } + }, + "@types/react-color": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.4.tgz", + "integrity": "sha512-EswbYJDF1kkrx93/YU+BbBtb46CCtDMvTiGmcOa/c5PETnwTiSWoseJ1oSWeRl/4rUXkhME9bVURvvPg0W5YQw==", + "dev": true, + "requires": { + "@types/react": "*", + "@types/reactcss": "*" + } + }, + "@types/react-syntax-highlighter": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz", + "integrity": "sha512-9GfTo3a0PHwQeTVoqs0g5bS28KkSY48pp5659wA+Dp4MqceDEa8EHBqrllJvvtyusszyJhViUEap0FDvlk/9Zg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-d2gQQ0IL6hXLnoRfVYZukQNWHuVsE75DzFTLPUuyyEhJS8G2VvlE+qfQQ91SJjaMqlURRCNIsX7Jcsw6cEuJlA==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", + "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==", + "dev": true + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/tapable": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz", + "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/unist": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", + "dev": true + }, + "@types/webpack": { + "version": "4.41.26", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz", + "integrity": "sha512-7ZyTfxjCRwexh+EJFwRUM+CDB2XvgHl4vfuqf1ZKrgGvcS5BrNvPQqJh3tsZ0P6h6Aa1qClVHaJZszLPzpqHeA==", + "dev": true, + "requires": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/webpack-env": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.0.tgz", + "integrity": "sha512-Fx+NpfOO0CpeYX2g9bkvX8O5qh9wrU1sOF4g8sft4Mu7z+qfe387YlyY8w8daDyDsKY5vUxM0yxkAYnbkRbZEw==", + "dev": true + }, + "@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + } + }, + "@types/yargs": { + "version": "13.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.11.tgz", + "integrity": "sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "dev": true + }, + "@typescript-eslint/experimental-utils": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", + "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + } + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", + "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "requires": { + "@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": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dev": true, + "requires": { + "@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": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dev": true, + "requires": { + "@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": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dev": true, + "requires": { + "@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": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dev": true, + "requires": { + "@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": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dev": true, + "requires": { + "@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": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dev": true, + "requires": { + "@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": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + } + } + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "peer": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true, + "peer": true + } + } + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + } + } + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, + "add-dom-event-listener": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz", + "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==", + "requires": { + "object-assign": "4.x" + } + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", + "dev": true + }, + "adjust-sourcemap-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", + "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "airbnb-js-shims": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz", + "integrity": "sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "array.prototype.flatmap": "^1.2.1", + "es5-shim": "^4.5.13", + "es6-shim": "^0.35.5", + "function.prototype.name": "^1.1.0", + "globalthis": "^1.0.0", + "object.entries": "^1.1.0", + "object.fromentries": "^2.0.0 || ^1.0.0", + "object.getownpropertydescriptors": "^2.0.3", + "object.values": "^1.1.0", + "promise.allsettled": "^1.0.0", + "promise.prototype.finally": "^3.1.0", + "string.prototype.matchall": "^4.0.0 || ^3.0.1", + "string.prototype.padend": "^3.0.0", + "string.prototype.padstart": "^3.0.0", + "symbol.prototype.description": "^1.0.0" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "peer": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + }, + "dependencies": { + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true, + "peer": true + } + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true, + "requires": {} + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true, + "peer": true, + "requires": {} + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ansi-bgblack": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgblack/-/ansi-bgblack-0.1.1.tgz", + "integrity": "sha1-poulAHiHcBtqr74/oNrf36juPKI=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgblue": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgblue/-/ansi-bgblue-0.1.1.tgz", + "integrity": "sha1-Z73ATtybm1J4lp2hlt6j11yMNhM=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgcyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgcyan/-/ansi-bgcyan-0.1.1.tgz", + "integrity": "sha1-WEiUJWAL3p9VBwaN2Wnr/bUP52g=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bggreen": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bggreen/-/ansi-bggreen-0.1.1.tgz", + "integrity": "sha1-TjGRJIUplD9DIelr8THRwTgWr0k=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgmagenta": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgmagenta/-/ansi-bgmagenta-0.1.1.tgz", + "integrity": "sha1-myhDLAduqpmUGGcqPvvhk5HCx6E=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgred": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgred/-/ansi-bgred-0.1.1.tgz", + "integrity": "sha1-p2+Sg4OCukMpCmwXeEJPmE1vEEE=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgwhite": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgwhite/-/ansi-bgwhite-0.1.1.tgz", + "integrity": "sha1-ZQRlE3elim7OzQMxmU5IAljhG6g=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgyellow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgyellow/-/ansi-bgyellow-0.1.1.tgz", + "integrity": "sha1-w/4usIzUdmSAKeaHTRWgs49h1E8=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-black": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-black/-/ansi-black-0.1.1.tgz", + "integrity": "sha1-9hheiJNgslRaHsUMC/Bj/EMDJFM=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-blue": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-blue/-/ansi-blue-0.1.1.tgz", + "integrity": "sha1-FbgEmQ6S/JyoxUds6PaZd3wh7b8=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bold": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bold/-/ansi-bold-0.1.1.tgz", + "integrity": "sha1-PmOVCvWswq4uZw5vZ96xFdGl9QU=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-colors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-0.2.0.tgz", + "integrity": "sha1-csMd4qDZoszQysMMyYI+6y9kNLU=", + "dev": true, + "requires": { + "ansi-bgblack": "^0.1.1", + "ansi-bgblue": "^0.1.1", + "ansi-bgcyan": "^0.1.1", + "ansi-bggreen": "^0.1.1", + "ansi-bgmagenta": "^0.1.1", + "ansi-bgred": "^0.1.1", + "ansi-bgwhite": "^0.1.1", + "ansi-bgyellow": "^0.1.1", + "ansi-black": "^0.1.1", + "ansi-blue": "^0.1.1", + "ansi-bold": "^0.1.1", + "ansi-cyan": "^0.1.1", + "ansi-dim": "^0.1.1", + "ansi-gray": "^0.1.1", + "ansi-green": "^0.1.1", + "ansi-grey": "^0.1.1", + "ansi-hidden": "^0.1.1", + "ansi-inverse": "^0.1.1", + "ansi-italic": "^0.1.1", + "ansi-magenta": "^0.1.1", + "ansi-red": "^0.1.1", + "ansi-reset": "^0.1.1", + "ansi-strikethrough": "^0.1.1", + "ansi-underline": "^0.1.1", + "ansi-white": "^0.1.1", + "ansi-yellow": "^0.1.1", + "lazy-cache": "^2.0.1" + } + }, + "ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-dim": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-dim/-/ansi-dim-0.1.1.tgz", + "integrity": "sha1-QN5MYDqoCG2Oeoa4/5mNXDbu/Ww=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-green": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-green/-/ansi-green-0.1.1.tgz", + "integrity": "sha1-il2al55FjVfEDjNYCzc5C44Q0Pc=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-grey": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-grey/-/ansi-grey-0.1.1.tgz", + "integrity": "sha1-WdmLasK6GfilF5jphT+6eDOaM8E=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-hidden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-hidden/-/ansi-hidden-0.1.1.tgz", + "integrity": "sha1-7WpMSY0rt8uyidvyqNHcyFZ/rg8=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-inverse": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-inverse/-/ansi-inverse-0.1.1.tgz", + "integrity": "sha1-tq9Fgm/oJr+1KKbHmIV5Q1XM0mk=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-italic": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-italic/-/ansi-italic-0.1.1.tgz", + "integrity": "sha1-EEdDRj9iXBQqA2c5z4XtpoiYbyM=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-magenta": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-magenta/-/ansi-magenta-0.1.1.tgz", + "integrity": "sha1-BjtboW+z8j4c/aKwfAqJ3hHkMK4=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-reset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-reset/-/ansi-reset-0.1.1.tgz", + "integrity": "sha1-5+cSksPH3c1NYu9KbHwFmAkRw7c=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-strikethrough": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-strikethrough/-/ansi-strikethrough-0.1.1.tgz", + "integrity": "sha1-2Eh3FAss/wfRyT685pkE9oiF5Wg=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansi-to-html": { + "version": "0.6.14", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.14.tgz", + "integrity": "sha512-7ZslfB1+EnFSDO5Ju+ue5Y6It19DRnZXWv8jrGHgIlPna5Mh4jz7BV5jCbQneXNFurQcKoolaaAjHtgSBfOIuA==", + "dev": true, + "requires": { + "entities": "^1.1.2" + } + }, + "ansi-underline": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-underline/-/ansi-underline-0.1.1.tgz", + "integrity": "sha1-38kg9Ml7WXfqFi34/7mIMIqqcaQ=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-white": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-white/-/ansi-white-0.1.1.tgz", + "integrity": "sha1-nHe3wZPF7pkuYBHTbsTJIbRXiUQ=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "ansi-yellow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-yellow/-/ansi-yellow-0.1.1.tgz", + "integrity": "sha1-y5NW8vRscy8OMZnmEClVp32oPB0=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "app-root-dir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", + "integrity": "sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg=", + "dev": true + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-swap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arr-swap/-/arr-swap-1.0.1.tgz", + "integrity": "sha1-FHWQ7WX8gVvAf+8Jl8Llgj1kNTQ=", + "dev": true, + "requires": { + "is-number": "^3.0.0" + } + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + } + }, + "array.prototype.map": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.3.tgz", + "integrity": "sha512-nNcb30v0wfDyIe26Yif3PcV1JXQp4zEeEfupG7L4SRjnD6HLbO5b2a7eVSba53bOx4YCHYMBHt+Fp4vYstneRA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.5" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", + "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", + "dev": true, + "requires": { + "browserslist": "^2.11.3", + "caniuse-lite": "^1.0.30000805", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^6.0.17", + "postcss-value-parser": "^3.2.3" + }, + "dependencies": { + "browserslist": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", + "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000792", + "electron-to-chromium": "^1.3.30" + } + } + } + }, + "aws-sdk": { + "version": "2.870.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.870.0.tgz", + "integrity": "sha512-pbNO+RuEx45aaEZind0Tl9NADxncLJf0mRAwof0szyYMB+FZm165yz7FCxFLumU4R9qw8vOG5YFACBaNoQkJdg==", + "dev": true, + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "axe-core": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.3.tgz", + "integrity": "sha512-vwPpH4Aj4122EW38mxO/fxhGKtwWTMLDIJfZ1He0Edbtjcfna/R3YB67yVhezUMzqc3Jr3+Ii50KRntlENL4xQ==", + "dev": true + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dev": true, + "peer": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.0.0" + } + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true, + "peer": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true, + "peer": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "peer": true + } + } + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + } + }, + "babel-extract-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", + "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", + "dev": true, + "requires": { + "babylon": "^6.18.0" + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "peer": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true, + "peer": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "peer": true + } + } + }, + "babel-helper-evaluate-path": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", + "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", + "dev": true + }, + "babel-helper-flip-expressions": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", + "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", + "dev": true + }, + "babel-helper-is-nodes-equiv": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", + "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", + "dev": true + }, + "babel-helper-is-void-0": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", + "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", + "dev": true + }, + "babel-helper-mark-eval-scopes": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", + "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", + "dev": true + }, + "babel-helper-remove-or-void": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", + "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", + "dev": true + }, + "babel-helper-to-multiple-sequence-expressions": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", + "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==", + "dev": true + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "peer": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "dev": true, + "requires": { + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + } + }, + "babel-loader": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz", + "integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^1.4.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + } + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "peer": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-add-react-displayname": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz", + "integrity": "sha1-M51M3be2X9YtHfnbn+BN4TQSK9U=", + "dev": true + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-emotion": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", + "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", + "dev": true, + "requires": { + "@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" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + } + } + }, + "babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "dev": true, + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "babel-plugin-minify-builtins": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", + "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==", + "dev": true + }, + "babel-plugin-minify-constant-folding": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", + "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "babel-plugin-minify-dead-code-elimination": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", + "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-mark-eval-scopes": "^0.4.3", + "babel-helper-remove-or-void": "^0.4.3", + "lodash": "^4.17.11" + } + }, + "babel-plugin-minify-flip-comparisons": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", + "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", + "dev": true, + "requires": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "babel-plugin-minify-guarded-expressions": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", + "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3" + } + }, + "babel-plugin-minify-infinity": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", + "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", + "dev": true + }, + "babel-plugin-minify-mangle-names": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", + "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", + "dev": true, + "requires": { + "babel-helper-mark-eval-scopes": "^0.4.3" + } + }, + "babel-plugin-minify-numeric-literals": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", + "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", + "dev": true + }, + "babel-plugin-minify-replace": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", + "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==", + "dev": true + }, + "babel-plugin-minify-simplify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", + "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3", + "babel-helper-is-nodes-equiv": "^0.0.1", + "babel-helper-to-multiple-sequence-expressions": "^0.5.0" + } + }, + "babel-plugin-minify-type-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", + "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", + "dev": true, + "requires": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "babel-plugin-module-resolver": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz", + "integrity": "sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA==", + "dev": true, + "peer": true, + "requires": { + "find-babel-config": "^1.1.0", + "glob": "^7.1.2", + "pkg-up": "^2.0.0", + "reselect": "^3.0.1", + "resolve": "^1.4.0" + } + }, + "babel-plugin-named-asset-import": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz", + "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==", + "dev": true, + "requires": {} + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz", + "integrity": "sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.0", + "@babel/helper-define-polyfill-provider": "^0.1.5", + "semver": "^6.1.1" + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz", + "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.1.5", + "core-js-compat": "^3.8.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz", + "integrity": "sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.1.5" + } + }, + "babel-plugin-react-docgen": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz", + "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==", + "dev": true, + "requires": { + "ast-types": "^0.14.2", + "lodash": "^4.17.15", + "react-docgen": "^5.0.0" + } + }, + "babel-plugin-recharts": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-recharts/-/babel-plugin-recharts-1.2.1.tgz", + "integrity": "sha512-bIPmjP3TrF2RJk0jDBG+91aTVyLuK48T4Nqekvs/B6MdzPmHXBKB+q+8xXCSRth08Wck+X5ylgSTcr3Ab1egvw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.1.0", + "babylon": "^6.18.0" + } + }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "dev": true + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-transform-inline-consecutive-adds": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", + "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", + "dev": true + }, + "babel-plugin-transform-member-expression-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", + "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", + "dev": true + }, + "babel-plugin-transform-merge-sibling-variables": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", + "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", + "dev": true + }, + "babel-plugin-transform-minify-booleans": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", + "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", + "dev": true + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-plugin-transform-property-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", + "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", + "dev": true + }, + "babel-plugin-transform-regexp-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", + "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", + "dev": true + }, + "babel-plugin-transform-remove-console": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", + "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", + "dev": true + }, + "babel-plugin-transform-remove-debugger": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", + "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", + "dev": true + }, + "babel-plugin-transform-remove-undefined": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", + "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "babel-plugin-transform-simplify-comparison-operators": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", + "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", + "dev": true + }, + "babel-plugin-transform-undefined-to-void": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", + "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", + "dev": true + }, + "babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + } + }, + "babel-preset-minify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", + "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", + "dev": true, + "requires": { + "babel-plugin-minify-builtins": "^0.5.0", + "babel-plugin-minify-constant-folding": "^0.5.0", + "babel-plugin-minify-dead-code-elimination": "^0.5.1", + "babel-plugin-minify-flip-comparisons": "^0.4.3", + "babel-plugin-minify-guarded-expressions": "^0.4.4", + "babel-plugin-minify-infinity": "^0.4.3", + "babel-plugin-minify-mangle-names": "^0.5.0", + "babel-plugin-minify-numeric-literals": "^0.4.3", + "babel-plugin-minify-replace": "^0.5.0", + "babel-plugin-minify-simplify": "^0.5.1", + "babel-plugin-minify-type-constructors": "^0.4.3", + "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", + "babel-plugin-transform-member-expression-literals": "^6.9.4", + "babel-plugin-transform-merge-sibling-variables": "^6.9.4", + "babel-plugin-transform-minify-booleans": "^6.9.4", + "babel-plugin-transform-property-literals": "^6.9.4", + "babel-plugin-transform-regexp-constructors": "^0.4.3", + "babel-plugin-transform-remove-console": "^6.9.4", + "babel-plugin-transform-remove-debugger": "^6.9.4", + "babel-plugin-transform-remove-undefined": "^0.5.0", + "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", + "babel-plugin-transform-undefined-to-void": "^6.9.4", + "lodash": "^4.17.11" + } + }, + "babel-preset-react-app": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.1.2.tgz", + "integrity": "sha512-k58RtQOKH21NyKtzptoAvtAODuAJJs3ZhqBMl456/GnXEQ/0La92pNmwgWoMn5pBTrsvk3YYXdY7zpY4e3UIxA==", + "dev": true, + "requires": { + "@babel/core": "7.9.0", + "@babel/plugin-proposal-class-properties": "7.8.3", + "@babel/plugin-proposal-decorators": "7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3", + "@babel/plugin-proposal-numeric-separator": "7.8.3", + "@babel/plugin-proposal-optional-chaining": "7.9.0", + "@babel/plugin-transform-flow-strip-types": "7.9.0", + "@babel/plugin-transform-react-display-name": "7.8.3", + "@babel/plugin-transform-runtime": "7.9.0", + "@babel/preset-env": "7.9.0", + "@babel/preset-react": "7.9.1", + "@babel/preset-typescript": "7.9.0", + "@babel/runtime": "7.9.0", + "babel-plugin-macros": "2.8.0", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz", + "integrity": "sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-decorators": "^7.8.3" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", + "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", + "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz", + "integrity": "sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-flow": "^7.8.3" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz", + "integrity": "sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/preset-env": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz", + "integrity": "sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.9.0", + "@babel/helper-compilation-targets": "^7.8.7", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.9.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.9.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.9.0", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.9.0", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.9.0", + "@babel/plugin-transform-modules-commonjs": "^7.9.0", + "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-umd": "^7.9.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.7", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.9.0", + "browserslist": "^4.9.1", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/preset-react": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.1.tgz", + "integrity": "sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-react-display-name": "^7.8.3", + "@babel/plugin-transform-react-jsx": "^7.9.1", + "@babel/plugin-transform-react-jsx-development": "^7.9.0", + "@babel/plugin-transform-react-jsx-self": "^7.9.0", + "@babel/plugin-transform-react-jsx-source": "^7.9.0" + } + }, + "@babel/preset-typescript": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz", + "integrity": "sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-typescript": "^7.9.0" + } + }, + "@babel/runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.0.tgz", + "integrity": "sha512-cTIudHnzuWLS56ik4DnRnqqNf8MkdUzV4iFFI1h7Jo9xvrpQROYaAnaSd2mHLQAzzZAPfATynX5ord6YlNYNMA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "peer": true, + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "dev": true, + "peer": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "peer": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "peer": true, + "requires": { + "source-map": "^0.5.6" + } + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "peer": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "peer": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true, + "peer": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "peer": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + }, + "dependencies": { + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true, + "peer": true + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + } + }, + "base16": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", + "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=" + }, + "base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "batch-processor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz", + "integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "better-opn": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", + "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==", + "dev": true, + "requires": { + "open": "^7.0.3" + } + }, + "bfj": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", + "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "check-types": "^8.0.3", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "block-stream2": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.1.0.tgz", + "integrity": "sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==", + "dev": true, + "requires": { + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + }, + "dependencies": { + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "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" + } + }, + "brfs": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", + "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", + "requires": { + "quote-stream": "^1.0.1", + "resolve": "^1.1.5", + "static-module": "^2.2.0", + "through2": "^2.0.0" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz", + "integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==", + "requires": { + "caniuse-lite": "^1.0.30001181", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.649", + "escalade": "^3.1.1", + "node-releases": "^1.1.70" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + } + } + }, + "calendar": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/calendar/-/calendar-0.1.1.tgz", + "integrity": "sha512-CExn+MxSU1pCsjYiS+Cx8d1MtIZqezxRhpIu8odr1oqvYG/0C1m8lvehHxTl1FslgKbOD7Z5QuEcyk8sGgpZLQ==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "peer": true, + "requires": { + "callsites": "^0.2.0" + }, + "dependencies": { + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true, + "peer": true + } + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001204", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001204.tgz", + "integrity": "sha512-JUdjWpcxfJ9IPamy2f5JaRDCaqJOxDzOSKtbdx4rH9VivMd1vIzoPumsJa9LoMIi4Fx2BV2KZOxWhNkBjaYivQ==" + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "dev": true + }, + "character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "dev": true + }, + "character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "check-types": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", + "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==", + "dev": true + }, + "choices-separator": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/choices-separator/-/choices-separator-2.0.0.tgz", + "integrity": "sha1-kv0XYxgteQM/XFxR0Lo1LlVnxpY=", + "dev": true, + "requires": { + "ansi-dim": "^0.1.1", + "debug": "^2.6.6", + "strip-color": "^0.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "dependencies": { + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-dependency-plugin": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz", + "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", + "dev": true, + "requires": {} + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true, + "peer": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + } + } + }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "requires": { + "exit": "0.1.2", + "glob": "^7.1.1" + } + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-table3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", + "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^4.2.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "clipboard": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz", + "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==", + "dev": true, + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "clone-deep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-1.0.0.tgz", + "integrity": "sha512-hmJRX8x1QOJVV+GUjOBzi6iauhPqc9hIF6xitWRBbiPZOBb6vGo/mDRIK9P74RTKSQK7AE8B0DDWY/vpRrPmQw==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^5.0.0", + "shallow-clone": "^1.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "codemirror": { + "version": "5.60.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.60.0.tgz", + "integrity": "sha512-AEL7LhFOlxPlCL8IdTcJDblJm8yrAGib7I+DErJPdZd4l6imx8IMgKK3RblVgBQqz3TZJR4oknQ03bz+uNjBYA==" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", + "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.4" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", + "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "dev": true, + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + }, + "dependencies": { + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + } + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "dev": true + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-classes": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz", + "integrity": "sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=", + "requires": { + "component-indexof": "0.0.3" + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "component-indexof": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz", + "integrity": "sha1-EdCRMSI5648yyPJa6csAL/6NPCQ=" + }, + "compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", + "dev": true, + "requires": { + "arity-n": "^1.0.4" + } + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "compute-scroll-into-view": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz", + "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "confusing-browser-globals": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", + "dev": true + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "requires": { + "date-now": "^0.1.4" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "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": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-to-clipboard": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz", + "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==", + "requires": { + "toggle-selection": "^1.0.6" + } + }, + "copy-webpack-plugin": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz", + "integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==", + "dev": true, + "requires": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "core-js": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.9.1.tgz", + "integrity": "sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg==", + "dev": true + }, + "core-js-compat": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.9.1.tgz", + "integrity": "sha512-jXAirMQxrkbiiLsCx9bQPJFA6llDadKMpYrBJQJ3/c4/vsPP/fAf29h24tviRlvwUL6AmY5CHLu2GvjuYviQqA==", + "dev": true, + "requires": { + "browserslist": "^4.16.3", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-js-pure": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.9.1.tgz", + "integrity": "sha512-laz3Zx0avrw9a4QEIdmIblnVuJz8W51leY9iLThatCsFawWxC3sE4guASC78JbCin+DkwMpCdp1AVAuzL/GN7A==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@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" + } + }, + "country-data": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/country-data/-/country-data-0.0.31.tgz", + "integrity": "sha1-gJZrjh0Uf6bWpYnTKTP4eTd0lW0=", + "dev": true, + "requires": { + "currency-symbol-map": "~2", + "underscore": ">1.4.4" + } + }, + "cp-file": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz", + "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "nested-error-stacks": "^2.0.0", + "p-event": "^4.1.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + } + } + }, + "cpy": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-8.1.2.tgz", + "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==", + "dev": true, + "requires": { + "arrify": "^2.0.1", + "cp-file": "^7.0.0", + "globby": "^9.2.0", + "has-glob": "^1.0.0", + "junk": "^3.1.0", + "nested-error-stacks": "^2.1.0", + "p-all": "^2.1.0", + "p-filter": "^2.1.0", + "p-map": "^3.0.0" + }, + "dependencies": { + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "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": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "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" + } + }, + "create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, + "create-react-context": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz", + "integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==", + "dev": true, + "requires": { + "gud": "^1.0.0", + "warning": "^4.0.3" + } + }, + "cross-fetch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.2.tgz", + "integrity": "sha512-+JhD65rDNqLbGmB3Gzs3HrEKC0aQnD+XA3SY6RjgkF88jV2q5cTc5+CwxlS3sdmLk98gpPt5CF9XRnPdlxZe6w==", + "requires": { + "node-fetch": "2.6.1" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "peer": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true, + "peer": true + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "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" + } + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-animation": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.6.1.tgz", + "integrity": "sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog==", + "requires": { + "babel-runtime": "6.x", + "component-classes": "^1.2.5" + } + }, + "css-blank-pseudo": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", + "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "css-has-pseudo": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", + "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^5.0.0-rc.4" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "css-prefers-color-scheme": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", + "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true + }, + "cssdb": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", + "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + }, + "dependencies": { + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", + "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "csstype": { + "version": "2.6.16", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.16.tgz", + "integrity": "sha512-61FBWoDHp/gRtsoDkq/B1nWrCUG/ok1E3tUrcNbZjsE9Cxd9yzUirjS3+nAATB8U4cTtaQmAHbNndoFz5L6C9Q==", + "dev": true + }, + "currency-symbol-map": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/currency-symbol-map/-/currency-symbol-map-2.2.0.tgz", + "integrity": "sha1-KzwYcv8aws5ZXYJz5Y4f/wJyrqI=", + "dev": true + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" + }, + "d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + }, + "d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + }, + "d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" + }, + "d3-geo-projection": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-0.2.16.tgz", + "integrity": "sha1-SZTs0QM92xUztsTFUoocgdzClCc=", + "requires": { + "brfs": "^1.3.0" + } + }, + "d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "d3-queue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-2.0.3.tgz", + "integrity": "sha1-B/vaOsrlNYqcUpmq+ICt8JU+0sI=" + }, + "d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "requires": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "requires": { + "d3-path": "1" + } + }, + "d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" + }, + "d3-time-format": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "requires": { + "d3-time": "1" + } + }, + "damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "datamaps": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/datamaps/-/datamaps-0.5.9.tgz", + "integrity": "sha512-GUXpO713URNzaExVUgBtqA5fr2UuxUG/fVitI04zEFHVL2FHSjd672alHq8E16oQqRNzF0m1bmx8WlTnDrGSqQ==", + "requires": { + "@types/d3": "3.5.38", + "d3": "^3.5.6", + "topojson": "^1.6.19" + } + }, + "date-fns": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.19.0.tgz", + "integrity": "sha512-X3bf2iTPgCAQp9wvjOQytnf5vO5rESYRXlPIVcgSbtT5OTScPcsf9eZU+B/YIkKAtYr5WeCii58BgATrNitlWg==" + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + }, + "deasync": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.21.tgz", + "integrity": "sha512-kUmM8Y+PZpMpQ+B4AuOW9k2Pfx/mSupJtxOsLzmnHY2WqZUYRFccFn2RhzPAqt3Xb+sorK/badW2D4zNzqZz5w==", + "dev": true, + "requires": { + "bindings": "^1.5.0", + "node-addon-api": "^1.7.1" + } + }, + "deasync-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deasync-promise/-/deasync-promise-1.0.1.tgz", + "integrity": "sha1-KyfeR4Fnr07zS6mYecUuwM7dYcI=", + "dev": true, + "requires": { + "deasync": "^0.1.7" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-diff": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz", + "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==" + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "deep-object-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.0.tgz", + "integrity": "sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==", + "dev": true + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "deploy-aws-s3-cloudfront": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/deploy-aws-s3-cloudfront/-/deploy-aws-s3-cloudfront-3.3.0.tgz", + "integrity": "sha512-QSV7+sGnMby3iOEdFFRFB4GInjtov8DsJkVhtJKvjiQzuPz/Yd6joBHWlSEoldA1dSeTnP8MUOn5pVLALg+B8Q==", + "dev": true, + "requires": { + "aws-sdk": "2", + "fast-glob": "3", + "md5-file": "5", + "micromatch": "4", + "mime-types": "2", + "prompt-confirm": "2", + "winston": "3", + "yargs": "16" + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "peer": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "detect-node": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.5.tgz", + "integrity": "sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==", + "dev": true + }, + "detect-port": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", + "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", + "dev": true, + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dev": true, + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + } + } + }, + "disposables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/disposables/-/disposables-1.0.2.tgz", + "integrity": "sha1-NsamdEdfVaLWkTVnpgFETkh7S24=" + }, + "dnd-core": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-2.6.0.tgz", + "integrity": "sha1-ErrWbVh0LG5ffPKUP7aFlED4CcQ=", + "requires": { + "asap": "^2.0.6", + "invariant": "^2.0.0", + "lodash": "^4.2.0", + "redux": "^3.7.1" + }, + "dependencies": { + "redux": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", + "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", + "requires": { + "lodash": "^4.2.1", + "lodash-es": "^4.2.1", + "loose-envify": "^1.1.0", + "symbol-observable": "^1.0.3" + } + } + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-align": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.0.tgz", + "integrity": "sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA==" + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-helpers": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", + "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", + "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==" + } + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + }, + "dependencies": { + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + } + } + }, + "dotenv": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", + "dev": true + }, + "dotenv-defaults": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-1.1.1.tgz", + "integrity": "sha512-6fPRo9o/3MxKvmRZBD3oNFdxODdhJtIy1zcJeUSCs6HCy4tarUpd+G67UTU9tF6OWXeSPqsm4fPAB+2eY9Rt9Q==", + "dev": true, + "requires": { + "dotenv": "^6.2.0" + } + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "dotenv-webpack": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-1.8.0.tgz", + "integrity": "sha512-o8pq6NLBehtrqA8Jv8jFQNtG9nhRtVqmoD4yWbgUyoU3+9WBlPe+c2EAiaJok9RB28QvrWvdWLZGeTT5aATDMg==", + "dev": true, + "requires": { + "dotenv-defaults": "^1.0.2" + } + }, + "downshift": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.1.tgz", + "integrity": "sha512-ch8Sh/j7gVqQd7Kcv3A5TkGfldmxmlQrRPZJYWEhzh24+h7WA4vXssuhcGNJrD8YPJlZYQGHcaX8BNhS0IcOvg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "compute-scroll-into-view": "^1.0.17", + "prop-types": "^15.7.2", + "react-is": "^17.0.1" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "^2.0.2" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "dev": true, + "requires": { + "jake": "^10.6.1" + } + }, + "electron-to-chromium": { + "version": "1.3.698", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.698.tgz", + "integrity": "sha512-VEXDzYblnlT+g8Q3gedwzgKOso1evkeJzV8lih7lV8mL8eAnGVnKyC3KsFT6S+R5PQO4ffdr1PI16/ElibY/kQ==" + }, + "element-resize-detector": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.2.tgz", + "integrity": "sha512-+LOXRkCJc4I5WhEJxIDjhmE3raF8jtOMBDqSCgZTMz2TX3oXAX5pE2+MDeopJlGdXzP7KzPbBJaUGfNaP9HG4A==", + "dev": true, + "requires": { + "batch-processor": "1.0.0" + } + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "emotion-theming": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/emotion-theming/-/emotion-theming-10.0.27.tgz", + "integrity": "sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@emotion/weak-memoize": "0.2.5", + "hoist-non-react-statics": "^3.3.0" + } + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "endent": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.0.1.tgz", + "integrity": "sha512-mADztvcC+vCk4XEZaCz6xIPO2NHQuprv5CAEjuVAu6aZwqAj7nVNlMyl1goPFYqCCpS2OJV9jwpumJLkotZrNw==", + "dev": true, + "requires": { + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.4" + } + }, + "engine.io-client": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.1.2.tgz", + "integrity": "sha512-1mwvwKYMa0AaCy+sPgvJ/SnKyO5MJZ1HEeXfA3Rm/KHkHGiYD5bQVq8QzvIrkI01FuVtOdZC5lWdRw1BGXB2NQ==", + "requires": { + "base64-arraybuffer": "0.1.4", + "component-emitter": "~1.3.0", + "debug": "~4.3.1", + "engine.io-parser": "~4.0.1", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz", + "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==", + "requires": { + "base64-arraybuffer": "0.1.4" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "dev": true, + "requires": { + "stackframe": "^1.1.1" + } + }, + "error-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/error-symbol/-/error-symbol-0.1.0.tgz", + "integrity": "sha1-Ck2uN9YA0VopukU9jvkg8YRDM/Y=", + "dev": true + }, + "es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es5-shim": { + "version": "4.5.15", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.15.tgz", + "integrity": "sha512-FYpuxEjMeDvU4rulKqFdukQyZSTpzhg4ScQHrAosrlVpR6GFyaw14f74yn2+4BugniIS0Frpg7TvwZocU4ZMTw==", + "dev": true + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-shim": { + "version": "0.35.6", + "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.6.tgz", + "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==", + "dev": true + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "peer": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "peer": true + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true, + "peer": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "peer": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true, + "peer": true + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "^2.1.1" + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "peer": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "peer": true + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "peer": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true, + "peer": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "peer": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "peer": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + } + } + }, + "eslint-config-airbnb": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz", + "integrity": "sha512-zLyOhVWhzB/jwbz7IPSbkUuj7X2ox4PHXTcZkEmDqTvd0baJmJyuxlFPDlZOE/Y5bC+HQRaEkT3FoHo9wIdRiw==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^12.1.0" + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "dev": true, + "requires": { + "eslint-restricted-globals": "^0.1.1" + } + }, + "eslint-import-resolver-babel-module": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-babel-module/-/eslint-import-resolver-babel-module-4.0.0.tgz", + "integrity": "sha512-aPj0+pG0H3HCaMD9eRDYEzPdMyKrLE2oNhAzTXd2w86ZBe3s7drSrrPwVTfzO1CBp13FGk8S84oRmZHZvSo0mA==", + "dev": true, + "requires": { + "pkg-up": "^2.0.0", + "resolve": "^1.4.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", + "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.11.2", + "aria-query": "^4.2.2", + "array-includes": "^3.1.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.0.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.6", + "emoji-regex": "^9.0.0", + "has": "^1.0.3", + "jsx-ast-utils": "^3.1.0", + "language-tags": "^1.0.5" + } + }, + "eslint-plugin-react": { + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.23.1.tgz", + "integrity": "sha512-MvFGhZjI8Z4HusajmSw0ougGrq3Gs4vT/0WgwksZgf5RrLrRa2oYAw56okU4tZJl8+j7IYNuTM+2RnFEuTSdRQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.3", + "object.fromentries": "^2.0.4", + "object.values": "^1.1.3", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.4" + }, + "dependencies": { + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz", + "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==", + "dev": true, + "requires": {} + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dev": true, + "peer": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "peer": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.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" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", + "dev": true + }, + "falafel": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.4.tgz", + "integrity": "sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ==", + "requires": { + "acorn": "^7.1.1", + "foreach": "^2.0.5", + "isarray": "^2.0.1", + "object-keys": "^1.0.6" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", + "dev": true + }, + "fast-xml-parser": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz", + "integrity": "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==", + "dev": true + }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "dev": true, + "requires": { + "format": "^0.2.0" + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", + "requires": { + "fbjs": "^3.0.0" + } + }, + "fbjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.0.tgz", + "integrity": "sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==", + "requires": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, + "fecha": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", + "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "peer": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "file-system-cache": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/file-system-cache/-/file-system-cache-1.0.5.tgz", + "integrity": "sha1-hCWbNqK7uNPW6xAh0xMv/mTP/08=", + "dev": true, + "requires": { + "bluebird": "^3.3.5", + "fs-extra": "^0.30.0", + "ramda": "^0.21.0" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true + }, + "filelist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "filesize": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", + "integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-babel-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", + "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", + "dev": true, + "peer": true, + "requires": { + "json5": "^0.5.1", + "path-exists": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true, + "peer": true + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "dependencies": { + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "peer": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "peer": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "flatten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", + "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==", + "dev": true + }, + "flow-bin": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.115.0.tgz", + "integrity": "sha512-xW+U2SrBaAr0EeLvKmXAmsdnrH6x0Io17P6yRJTNgrrV42G8KXhBAD00s6oGbTTqRyHD0nP47kyuU34zljZpaQ==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "flux": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.1.tgz", + "integrity": "sha512-emk4RCvJ8RzNP2lNpphKnG7r18q8elDYNAPx7xn+bDeOIo9FFfxEfIQ2y6YbQNmnsGD3nH1noxtLE64Puz1bRQ==", + "requires": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.0" + } + }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "dev": true + }, + "follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "fork-ts-checker-webpack-plugin": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz", + "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "chalk": "^2.4.1", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=", + "dev": true + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.4.tgz", + "integrity": "sha512-iqy1pIotY/RmhdFZygSSlW0wko2yxkSCKqsuv4pr8QESohpYyG/Z7B/XXvPRKTJS//960rgguE5mSRUsDdaJrQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "functions-have-names": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", + "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==", + "dev": true + }, + "fuse.js": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", + "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "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" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-promise": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-3.4.0.tgz", + "integrity": "sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==", + "dev": true, + "requires": { + "@types/glob": "*" + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globalthis": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + } + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "dev": true, + "optional": true, + "requires": { + "delegate": "^3.1.2" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "harmony-reflect": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.1.tgz", + "integrity": "sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz", + "integrity": "sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc=", + "dev": true, + "requires": { + "is-glob": "^3.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "dev": true + }, + "hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dev": true, + "requires": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "highlight.js": { + "version": "10.7.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.1.tgz", + "integrity": "sha512-S6G97tHGqJ/U8DsXcEdnACbirtbx58Bx9CzIVeYli8OuswCfYI/LsXH2EiGcoGio1KAC3x4mmUwulOllJ2ZyRA==" + }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "peer": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "html-entities": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + } + } + }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + }, + "dependencies": { + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, + "html-tags": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", + "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==" + }, + "html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "dev": true, + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "requires": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + }, + "dependencies": { + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", + "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", + "dev": true, + "requires": { + "harmony-reflect": "^1.4.6" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "immer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", + "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==", + "dev": true + }, + "immutable": { + "version": "4.0.0-rc.12", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.12.tgz", + "integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==" + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "info-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/info-symbol/-/info-symbol-0.1.0.tgz", + "integrity": "sha1-J4QdcoZ920JCzWEtecEGM4gcang=", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "dev": true + }, + "is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, + "is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "dev": true + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-docker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true, + "peer": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "dev": true + }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "dev": true + }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0" + } + }, + "iterate-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", + "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", + "dev": true + }, + "iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "dev": true, + "requires": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + } + }, + "jake": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "dev": true, + "requires": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + } + }, + "jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.9.0" + } + }, + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-cli": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "dev": true, + "requires": { + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" + }, + "dependencies": { + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-jsdom-fourteen": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-1.0.1.tgz", + "integrity": "sha512-DojMX1sY+at5Ep+O9yME34CdidZnO3/zfPh8UW+918C5fIZET5vCjfkegixmsi7AtdYfkr4bPlIzmWnlvQkP7Q==", + "dev": true, + "requires": { + "@jest/environment": "^24.3.0", + "@jest/fake-timers": "^24.3.0", + "@jest/types": "^24.3.0", + "jest-mock": "^24.0.0", + "jest-util": "^24.0.0", + "jsdom": "^14.1.0" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "jsdom": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.1.0.tgz", + "integrity": "sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^6.0.4", + "acorn-globals": "^4.3.0", + "array-equal": "^1.0.0", + "cssom": "^0.3.4", + "cssstyle": "^1.1.1", + "data-urls": "^1.1.0", + "domexception": "^1.0.1", + "escodegen": "^1.11.0", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.1.3", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "saxes": "^3.1.9", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.5.0", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^6.1.2", + "xml-name-validator": "^3.0.0" + } + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "dev": true + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" + } + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "jest-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + } + }, + "jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "dev": true, + "requires": { + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "jest-mock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, + "jest-resolve-dependencies": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" + } + }, + "jest-runner": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + } + }, + "jest-runtime": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" + }, + "dependencies": { + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-serializer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", + "dev": true + }, + "jest-snapshot": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" + } + }, + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + } + }, + "jest-watch-typeahead": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.4.2.tgz", + "integrity": "sha512-f7VpLebTdaXs81rg/oj4Vg/ObZy2QtGzAmGLNsqUS5G5KtSN68tFcIsbvNODfNyQxU78g7D8x77o3bgfBTR+2Q==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.1", + "jest-regex-util": "^24.9.0", + "jest-watcher": "^24.3.0", + "slash": "^3.0.0", + "string-length": "^3.1.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "string-length": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz", + "integrity": "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.9.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + } + } + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbi": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.4.tgz", + "integrity": "sha512-52QRRFSsi9impURE8ZUbzAMCLjPm4THO7H2fcuIvaaeFTbSysvkodbQQXIVsNgq/ypDbq6dJiuGKL0vZ/i9hUg==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "jshint": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.12.0.tgz", + "integrity": "sha512-TwuuaUDmra0JMkuqvqy+WGo2xGHSNjv1BA1nTIgtH2K5z1jHuAEeAgp7laaR+hLRmajRjcrM71+vByBDanCyYA==", + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.19", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + }, + "dependencies": { + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=" + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=" + } + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true, + "peer": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-stream/-/json-stream-1.0.0.tgz", + "integrity": "sha1-GjhU4o0rvuqzHMfd9oPS3cVlJwg=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jsx-ast-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", + "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", + "dev": true, + "requires": { + "array-includes": "^3.1.2", + "object.assign": "^4.1.2" + } + }, + "junk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", + "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", + "dev": true + }, + "keyboard-key": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", + "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==" + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "koalas": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/koalas/-/koalas-1.0.2.tgz", + "integrity": "sha1-MYQz8HQjXbePrlZhoCqMpT7ilc0=", + "dev": true + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "dev": true + }, + "language-subtag-registry": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", + "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", + "dev": true + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", + "dev": true, + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "dev": true, + "requires": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", + "dev": true, + "requires": { + "set-getter": "^0.1.0" + } + }, + "lazy-universal-dotenv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", + "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.0", + "app-root-dir": "^1.0.2", + "core-js": "^3.0.4", + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0" + }, + "dependencies": { + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + } + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "loader-fs-cache": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", + "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==", + "dev": true, + "requires": { + "find-cache-dir": "^0.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true + }, + "lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-ok": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/log-ok/-/log-ok-0.1.1.tgz", + "integrity": "sha1-vqPdNqzQuKckDXhza1uXxlREozQ=", + "dev": true, + "requires": { + "ansi-green": "^0.1.1", + "success-symbol": "^0.1.0" + } + }, + "log-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/log-utils/-/log-utils-0.2.1.tgz", + "integrity": "sha1-pMIXoN2aUFFdm5ICBgkas9TgMc8=", + "dev": true, + "requires": { + "ansi-colors": "^0.2.0", + "error-symbol": "^0.1.0", + "info-symbol": "^0.1.0", + "log-ok": "^0.1.1", + "success-symbol": "^0.1.0", + "time-stamp": "^1.0.1", + "warning-symbol": "^0.1.0" + } + }, + "logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "dev": true, + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, + "loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "dev": true, + "requires": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "luxon": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz", + "integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==" + }, + "magic-string": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "requires": { + "vlq": "^0.2.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha1-beJlMXSt+12e3DPGnT6Sobdvrwg=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "markdown-to-jsx": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-6.11.4.tgz", + "integrity": "sha512-3lRCD5Sh+tfA52iGgfs/XZiw33f7fFX9Bn55aNnVNUd2GzLDkOWyKYYD8Yju2B1Vn+feiEdgJs8T6Tg0xNokPw==", + "dev": true, + "requires": { + "prop-types": "^15.6.2", + "unquote": "^1.1.0" + } + }, + "material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==", + "dev": true + }, + "math-expression-evaluator": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.3.7.tgz", + "integrity": "sha512-nrbaifCl42w37hYd6oRLvoymFK42tWB+WQTMFtksDGQMi5GvlJwnz/CsS30FFAISFLtX+A0csJ0xLiuuyyec7w==" + }, + "md5-file": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-5.0.0.tgz", + "integrity": "sha512-xbEFXCYVWrSx/gEKS1VPlg84h/4L20znVIulKw6kMfmBUAZNAnF00eczz9ICMl+/hjQGo5KSXRxbL/47X3rmMw==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha1-fIekZGREwy11Q4VwkF8tvRsagFo=", + "dev": true, + "requires": { + "map-or-similar": "^1.5.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-deep": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", + "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "clone-deep": "^0.2.4", + "kind-of": "^3.0.2" + }, + "dependencies": { + "clone-deep": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", + "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", + "dev": true, + "requires": { + "for-own": "^0.1.3", + "is-plain-object": "^2.0.1", + "kind-of": "^3.0.2", + "lazy-cache": "^1.0.3", + "shallow-clone": "^0.1.2" + } + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "dev": true, + "requires": { + "is-buffer": "^1.0.2" + } + }, + "lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", + "dev": true + } + } + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-source-map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", + "requires": { + "source-map": "^0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "microevent.ts": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz", + "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "dev": true, + "requires": { + "mime-db": "1.46.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz", + "integrity": "sha512-RQIw6+7utTYn8DBGsf/LpRgZCJMpZt+kuawJ/fju0KiOL6nAaTBNmCJwS7HtwSCXfS47gCkmtBFS7HdsquhdxQ==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minio": { + "version": "7.0.18", + "resolved": "https://registry.npmjs.org/minio/-/minio-7.0.18.tgz", + "integrity": "sha512-jVRjkw8A5Spf+ETY5OXQUcQckHriuUA3u2+MAcX36btLT8EytlOVivxIseXvyFf9cNn3dy5w1F1UyjMvHU+nqg==", + "dev": true, + "requires": { + "async": "^3.1.0", + "block-stream2": "^2.0.0", + "es6-error": "^4.1.1", + "fast-xml-parser": "^3.17.5", + "json-stream": "^1.0.0", + "lodash": "^4.17.20", + "mime-types": "^2.1.14", + "mkdirp": "^0.5.1", + "querystring": "0.2.0", + "through2": "^3.0.1", + "xml": "^1.0.0", + "xml2js": "^0.4.15" + }, + "dependencies": { + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true + } + } + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mobx": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.1.8.tgz", + "integrity": "sha512-U4yCvUeh6yKXRwFxm2lyJjXPVekOEar/R8ZKWAXem/3fthJqYflViawfjDAUh7lZEvbKqljC3NT/pSaUKpE+gg==" + }, + "mobx-react-lite": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.2.0.tgz", + "integrity": "sha512-q5+UHIqYCOpBoFm/PElDuOhbcatvTllgRp3M1s+Hp5j0Z6XNgDbgqxawJ0ZAUEyKM8X1zs70PCuhAIzX1f4Q/g==", + "requires": {} + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "moment-locales-webpack-plugin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/moment-locales-webpack-plugin/-/moment-locales-webpack-plugin-1.2.0.tgz", + "integrity": "sha512-QAi5v0OlPUP7GXviKMtxnpBAo8WmTHrUNN7iciAhNOEAd9evCOvuN0g1N7ThIg3q11GLCkjY1zQ2saRcf/43nQ==", + "dev": true, + "requires": { + "lodash.difference": "^4.5.0" + } + }, + "moment-range": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/moment-range/-/moment-range-4.0.2.tgz", + "integrity": "sha512-n8sceWwSTjmz++nFHzeNEUsYtDqjgXgcOBzsHi+BoXQU2FW+eU92LUaK8gqOiSu5PG57Q9sYj1Fz4LRDj4FtKA==", + "requires": { + "es6-symbol": "^3.1.0" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "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": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-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" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "native-url": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/native-url/-/native-url-0.2.6.tgz", + "integrity": "sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA==", + "dev": true, + "requires": { + "querystring": "^0.2.0" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true + }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", + "dev": true, + "requires": { + "minimatch": "^3.0.2" + } + }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "requires": { + "lodash.toarray": "^4.4.0" + } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + } + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", + "integrity": "sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.71", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", + "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + }, + "dependencies": { + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + } + } + }, + "normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + } + } + }, + "object-hash": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.1.1.tgz", + "integrity": "sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ==" + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", + "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", + "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has": "^1.0.3" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", + "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has": "^1.0.3" + } + }, + "objectorarray": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.4.tgz", + "integrity": "sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w==", + "dev": true + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dev": true, + "requires": { + "fn.name": "1.x.x" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + } + } + }, + "optimal-select": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/optimal-select/-/optimal-select-4.0.1.tgz", + "integrity": "sha1-R959p6ObsJSf2a9UxvA1cVSPBMk=" + }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "requires": { + "wordwrap": "~0.0.2" + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz", + "integrity": "sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA==", + "dev": true, + "requires": { + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "peer": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "overlayscrollbars": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz", + "integrity": "sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ==", + "dev": true + }, + "p-all": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz", + "integrity": "sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==", + "dev": true, + "requires": { + "p-map": "^2.0.0" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } + } + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "requires": { + "p-timeout": "^3.1.0" + } + }, + "p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "requires": { + "p-map": "^2.0.0" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dev": true, + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@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": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true, + "peer": true + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "pnp-webpack-plugin": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", + "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", + "dev": true, + "requires": { + "ts-pnp": "^1.1.6" + } + }, + "pointer-symbol": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pointer-symbol/-/pointer-symbol-1.0.0.tgz", + "integrity": "sha1-YPkRAgTqepKbYmRKITFVQ8uz1Ec=", + "dev": true + }, + "polished": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-3.7.1.tgz", + "integrity": "sha512-/QgHrNGYwIA4mwxJ/7FSvalUJsm7KNfnXiScVSEG2Xa5qxDeBn4nmdjN2pW00mkM2Tts64ktc47U8F7Ed1BRAA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5" + } + }, + "popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "postcss-attribute-case-insensitive": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", + "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^6.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-browser-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz", + "integrity": "sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig==", + "dev": true, + "requires": { + "postcss": "^7" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "dev": true, + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-color-functional-notation": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", + "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-color-gray": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", + "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", + "dev": true, + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-color-hex-alpha": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", + "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", + "dev": true, + "requires": { + "postcss": "^7.0.14", + "postcss-values-parser": "^2.0.1" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-color-mod-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", + "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", + "dev": true, + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-color-rebeccapurple": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", + "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-custom-media": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", + "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-custom-properties": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", + "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", + "dev": true, + "requires": { + "postcss": "^7.0.17", + "postcss-values-parser": "^2.0.1" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-custom-selectors": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", + "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-dir-pseudo-class": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", + "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-double-position-gradients": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", + "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", + "dev": true, + "requires": { + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-env-function": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", + "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-flexbugs-fixes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz", + "integrity": "sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==", + "dev": true, + "requires": { + "postcss": "^7.0.26" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-focus-visible": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", + "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-focus-within": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", + "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-font-variant": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", + "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-functions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz", + "integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=", + "requires": { + "glob": "^7.1.2", + "object-assign": "^4.1.1", + "postcss": "^6.0.9", + "postcss-value-parser": "^3.3.0" + } + }, + "postcss-gap-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", + "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-image-set-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", + "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-import": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz", + "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-initial": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.2.tgz", + "integrity": "sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA==", + "dev": true, + "requires": { + "lodash.template": "^4.5.0", + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-inline-svg": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-inline-svg/-/postcss-inline-svg-3.1.1.tgz", + "integrity": "sha512-G2BkarW6gGpGFGAiKzW7aiulUS0/6QuCgq1riZEiX4oMaUTpU1pdW7BU6UFRDrdKkwS0r4icK2pU0bg6sCSOjw==", + "dev": true, + "requires": { + "css-select": "^1.2.0", + "dom-serializer": "^0.1.0", + "htmlparser2": "^3.9.0", + "postcss": "^6.0.1", + "postcss-value-parser": "^3.2.3" + }, + "dependencies": { + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "postcss-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz", + "integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==", + "requires": { + "camelcase-css": "^2.0.1", + "postcss": "^7.0.18" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-lab-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", + "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", + "dev": true, + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", + "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + }, + "dependencies": { + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-logical": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", + "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-media-minmax": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", + "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-mixins": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/postcss-mixins/-/postcss-mixins-6.2.3.tgz", + "integrity": "sha512-gfH5d09YilzDn/CLGFA9Lwv7GTezuyHgnAyXC8AfvhUMpl67ZTewhcpNuOgawClCOD+76XePE2IHO1xMgsOlvA==", + "dev": true, + "requires": { + "globby": "^8.0.1", + "postcss": "^7.0.21", + "postcss-js": "^2.0.3", + "postcss-simple-vars": "^5.0.2", + "sugarss": "^2.0.0" + }, + "dependencies": { + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-simple-vars": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-5.0.2.tgz", + "integrity": "sha512-xWIufxBoINJv6JiLb7jl5oElgp+6puJwvT5zZHliUSydoLz4DADRB3NDDsYgfKVwojn4TDLiseoC65MuS8oGGg==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dev": true, + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-nested": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.3.tgz", + "integrity": "sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw==", + "requires": { + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-nesting": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-4.2.1.tgz", + "integrity": "sha512-IkyWXICwagCnlaviRexi7qOdwPw3+xVVjgFfGsxmztvRVaNxAlrypOIKqDE5mxY+BVxnId1rnUKBRQoNE2VDaA==", + "dev": true, + "requires": { + "postcss": "^6.0.11" + } + }, + "postcss-normalize": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-8.0.1.tgz", + "integrity": "sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ==", + "dev": true, + "requires": { + "@csstools/normalize.css": "^10.1.0", + "browserslist": "^4.6.2", + "postcss": "^7.0.17", + "postcss-browser-comments": "^3.0.0", + "sanitize.css": "^10.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-overflow-shorthand": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", + "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-page-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", + "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-place": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", + "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-preset-env": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", + "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", + "dev": true, + "requires": { + "autoprefixer": "^9.6.1", + "browserslist": "^4.6.4", + "caniuse-lite": "^1.0.30000981", + "css-blank-pseudo": "^0.1.4", + "css-has-pseudo": "^0.10.0", + "css-prefers-color-scheme": "^3.1.1", + "cssdb": "^4.4.0", + "postcss": "^7.0.17", + "postcss-attribute-case-insensitive": "^4.0.1", + "postcss-color-functional-notation": "^2.0.1", + "postcss-color-gray": "^5.0.0", + "postcss-color-hex-alpha": "^5.0.3", + "postcss-color-mod-function": "^3.0.3", + "postcss-color-rebeccapurple": "^4.0.1", + "postcss-custom-media": "^7.0.8", + "postcss-custom-properties": "^8.0.11", + "postcss-custom-selectors": "^5.1.2", + "postcss-dir-pseudo-class": "^5.0.0", + "postcss-double-position-gradients": "^1.0.0", + "postcss-env-function": "^2.0.2", + "postcss-focus-visible": "^4.0.0", + "postcss-focus-within": "^3.0.0", + "postcss-font-variant": "^4.0.0", + "postcss-gap-properties": "^2.0.0", + "postcss-image-set-function": "^3.0.1", + "postcss-initial": "^3.0.0", + "postcss-lab-function": "^2.0.1", + "postcss-logical": "^3.0.0", + "postcss-media-minmax": "^4.0.0", + "postcss-nesting": "^7.0.0", + "postcss-overflow-shorthand": "^2.0.0", + "postcss-page-break": "^2.0.0", + "postcss-place": "^4.0.1", + "postcss-pseudo-class-any-link": "^6.0.0", + "postcss-replace-overflow-wrap": "^3.0.0", + "postcss-selector-matches": "^4.0.0", + "postcss-selector-not": "^4.0.0" + }, + "dependencies": { + "autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-nesting": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", + "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-pseudo-class-any-link": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", + "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", + "dev": true, + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-replace-overflow-wrap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", + "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-safe-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", + "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-selector-matches": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", + "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-selector-not": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz", + "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-selector-parser": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", + "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1", + "util-deprecate": "^1.0.2" + } + }, + "postcss-simple-vars": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-4.1.0.tgz", + "integrity": "sha512-J/TRomA8EqXhS4VjQJsPCYTFIa9FYN/dkJK/8oZ0BYeVIPx91goqM8T+ljsP57+4bwSEywFOuB7EZ8n1gjjxZw==", + "dev": true, + "requires": { + "postcss": "^6.0.9" + } + }, + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "requires": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "postcss-values-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", + "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", + "dev": true, + "requires": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } + } + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" + }, + "prismjs": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", + "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", + "dev": true, + "requires": { + "clipboard": "^2.0.0" + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true, + "peer": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise.allsettled": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.4.tgz", + "integrity": "sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag==", + "dev": true, + "requires": { + "array.prototype.map": "^1.0.3", + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.0.2", + "iterate-value": "^1.0.2" + } + }, + "promise.prototype.finally": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz", + "integrity": "sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.0", + "function-bind": "^1.1.1" + } + }, + "prompt-actions": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/prompt-actions/-/prompt-actions-3.0.2.tgz", + "integrity": "sha512-dhz2Fl7vK+LPpmnQ/S/eSut4BnH4NZDLyddHKi5uTU/2PDn3grEMGkgsll16V5RpVUh/yxdiam0xsM0RD4xvtg==", + "dev": true, + "requires": { + "debug": "^2.6.8" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "prompt-base": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prompt-base/-/prompt-base-4.1.0.tgz", + "integrity": "sha512-svGzgLUKZoqomz9SGMkf1hBG8Wl3K7JGuRCXc/Pv7xw8239hhaTBXrmjt7EXA9P/QZzdyT8uNWt9F/iJTXq75g==", + "dev": true, + "requires": { + "component-emitter": "^1.2.1", + "debug": "^3.0.1", + "koalas": "^1.0.2", + "log-utils": "^0.2.1", + "prompt-actions": "^3.0.2", + "prompt-question": "^5.0.1", + "readline-ui": "^2.2.3", + "readline-utils": "^2.2.3", + "static-extend": "^0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "prompt-choices": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prompt-choices/-/prompt-choices-4.1.0.tgz", + "integrity": "sha512-ZNYLv6rW9z9n0WdwCkEuS+w5nUAGzRgtRt6GQ5aFNFz6MIcU7nHFlHOwZtzy7RQBk80KzUGPSRQphvMiQzB8pg==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "arr-swap": "^1.0.1", + "choices-separator": "^2.0.0", + "clone-deep": "^4.0.0", + "collection-visit": "^1.0.0", + "define-property": "^2.0.2", + "is-number": "^6.0.0", + "kind-of": "^6.0.2", + "koalas": "^1.0.2", + "log-utils": "^0.2.1", + "pointer-symbol": "^1.0.0", + "radio-symbol": "^2.0.0", + "set-value": "^3.0.0", + "strip-color": "^0.1.0", + "terminal-paginator": "^2.0.2", + "toggle-array": "^1.0.1" + }, + "dependencies": { + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "is-number": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-6.0.0.tgz", + "integrity": "sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + } + } + }, + "prompt-confirm": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prompt-confirm/-/prompt-confirm-2.0.4.tgz", + "integrity": "sha512-X5lzbC8/kMNHdPOqQPfMKpH4VV2f7v2OTRJoN69ZYBirSwTeQaf9ZhmzPEO9ybMA0YV2Pha5MV27u2/U4ahWfg==", + "dev": true, + "requires": { + "ansi-cyan": "^0.1.1", + "prompt-base": "^4.0.1" + } + }, + "prompt-question": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/prompt-question/-/prompt-question-5.0.2.tgz", + "integrity": "sha512-wreaLbbu8f5+7zXds199uiT11Ojp59Z4iBi6hONlSLtsKGTvL2UY8VglcxQ3t/X4qWIxsNCg6aT4O8keO65v6Q==", + "dev": true, + "requires": { + "clone-deep": "^1.0.0", + "debug": "^3.0.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "kind-of": "^5.0.2", + "koalas": "^1.0.2", + "prompt-choices": "^4.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "prompts": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", + "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dev": true, + "requires": { + "xtend": "^4.0.0" + } + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true, + "peer": true + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", + "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=" + }, + "purgecss": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-2.3.0.tgz", + "integrity": "sha512-BE5CROfVGsx2XIhxGuZAT7rTH9lLeQx/6M0P7DTXQH4IUc3BBzs9JUzt4yzGf3JrH9enkeq6YJBe9CTtkm1WmQ==", + "requires": { + "commander": "^5.0.0", + "glob": "^7.0.0", + "postcss": "7.0.32", + "postcss-selector-parser": "^6.0.2" + }, + "dependencies": { + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quote-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", + "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", + "requires": { + "buffer-equal": "0.0.1", + "minimist": "^1.1.3", + "through2": "^2.0.0" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "radio-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/radio-symbol/-/radio-symbol-2.0.0.tgz", + "integrity": "sha1-eqm/xQSFY21S3XbWqOYxspB5muE=", + "dev": true, + "requires": { + "ansi-gray": "^0.1.1", + "ansi-green": "^0.1.1", + "is-windows": "^1.0.1" + } + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "requires": { + "performance-now": "^2.1.0" + } + }, + "ramda": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz", + "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "raw-loader": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", + "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "rc-align": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-2.4.5.tgz", + "integrity": "sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==", + "requires": { + "babel-runtime": "^6.26.0", + "dom-align": "^1.7.0", + "prop-types": "^15.5.8", + "rc-util": "^4.0.4" + } + }, + "rc-animate": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.11.1.tgz", + "integrity": "sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ==", + "requires": { + "babel-runtime": "6.x", + "classnames": "^2.2.6", + "css-animation": "^1.3.2", + "prop-types": "15.x", + "raf": "^3.4.0", + "rc-util": "^4.15.3", + "react-lifecycles-compat": "^3.0.4" + } + }, + "rc-time-picker": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.7.3.tgz", + "integrity": "sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg==", + "requires": { + "classnames": "2.x", + "moment": "2.x", + "prop-types": "^15.5.8", + "raf": "^3.4.1", + "rc-trigger": "^2.2.0", + "react-lifecycles-compat": "^3.0.4" + } + }, + "rc-trigger": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.6.5.tgz", + "integrity": "sha512-m6Cts9hLeZWsTvWnuMm7oElhf+03GOjOLfTuU0QmdB9ZrW7jR2IpI5rpNM7i9MvAAlMAmTx5Zr7g3uu/aMvZAw==", + "requires": { + "babel-runtime": "6.x", + "classnames": "^2.2.6", + "prop-types": "15.x", + "rc-align": "^2.4.0", + "rc-animate": "2.x", + "rc-util": "^4.4.0", + "react-lifecycles-compat": "^3.0.4" + } + }, + "rc-util": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz", + "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==", + "requires": { + "add-dom-event-listener": "^1.1.0", + "prop-types": "^15.5.10", + "react-is": "^16.12.0", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-addons-pure-render-mixin": { + "version": "15.6.3", + "resolved": "https://registry.npmjs.org/react-addons-pure-render-mixin/-/react-addons-pure-render-mixin-15.6.3.tgz", + "integrity": "sha512-e7F2OsLiyYGr9SHWHGlI/FfHRh+kbYx0hNfdN5zivHIf4vzeno7gsRJKXg71E35CpUCnre+JfM6UgWWgsvJBzA==", + "requires": { + "object-assign": "^4.1.0" + } + }, + "react-app-polyfill": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz", + "integrity": "sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g==", + "dev": true, + "requires": { + "core-js": "^3.5.0", + "object-assign": "^4.1.1", + "promise": "^8.0.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.3", + "whatwg-fetch": "^3.0.0" + }, + "dependencies": { + "promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "dev": true, + "requires": { + "asap": "~2.0.6" + } + } + } + }, + "react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "requires": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + } + }, + "react-base16-styling": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz", + "integrity": "sha1-OFjyTpxN2MvT9wLz901YHKKRcmk=", + "requires": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, + "react-circular-progressbar": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/react-circular-progressbar/-/react-circular-progressbar-2.0.3.tgz", + "integrity": "sha512-YKN+xAShXA3gYihevbQZbavfiJxo83Dt1cUxqg/cltj4VVsRQpDr7Fg1mvjDG3x1KHGtd9NmYKvJ2mMrPwbKyw==", + "requires": {} + }, + "react-codemirror2": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-5.1.0.tgz", + "integrity": "sha512-Cksbgbviuf2mJfMyrKmcu7ycK6zX/ukuQO8dvRZdFWqATf5joalhjFc6etnBdGCcPA2LbhIwz+OPnQxLN/j1Fw==", + "requires": {} + }, + "react-color": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "dev": true, + "requires": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + } + }, + "react-confirm": { + "version": "0.1.23", + "resolved": "https://registry.npmjs.org/react-confirm/-/react-confirm-0.1.23.tgz", + "integrity": "sha512-G853O0XapIQXF0bx2iFWBLgGIzCu2ZjGJWJp0IFMNoim89yh/cz6i/xcSM/N8zKLWIvrVAWm/Zn/w3d5E7uv3g==", + "requires": {} + }, + "react-datepicker": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-2.16.0.tgz", + "integrity": "sha512-TvcmSY27rn0JKvuJuIXNNS+niGQNdgtuG/CsBttVYhPOA9KmSw7c2PvQBPVEvzkyV+QPNJ8jN/KVJNj9uvopqA==", + "requires": { + "classnames": "^2.2.6", + "date-fns": "^2.0.1", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.9.0", + "react-popper": "^1.3.4" + } + }, + "react-daterange-picker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-daterange-picker/-/react-daterange-picker-2.0.1.tgz", + "integrity": "sha512-xPBtMONOfljnausiL6ftlfg6EHHvjdiDcH0j71FblAv35IWUJ9VDH3lXaUX9MZYdIynTN7hW+oqPcRK5xls1Nw==", + "requires": { + "calendar": "^0.1.0", + "classnames": "^2.1.1", + "create-react-class": "^15.6.3", + "immutable": "^3.7.2", + "prop-types": "^15.6.0", + "react-addons-pure-render-mixin": "^15.6.2" + }, + "dependencies": { + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + } + } + }, + "react-dev-utils": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", + "integrity": "sha512-dx0LvIGHcOPtKbeiSUM4jqpBl3TcY7CDjZdfOIcKeznE7BWr9dg0iPG90G5yfVQ+p/rGNMXdbfStvzQZEVEi4A==", + "dev": true, + "requires": { + "@babel/code-frame": "7.10.4", + "address": "1.1.2", + "browserslist": "4.14.2", + "chalk": "2.4.2", + "cross-spawn": "7.0.3", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "2.0.0", + "filesize": "6.1.0", + "find-up": "4.1.0", + "fork-ts-checker-webpack-plugin": "4.1.6", + "global-modules": "2.0.0", + "globby": "11.0.1", + "gzip-size": "5.1.1", + "immer": "8.0.1", + "is-root": "2.1.0", + "loader-utils": "2.0.0", + "open": "^7.0.2", + "pkg-up": "3.1.0", + "prompts": "2.4.0", + "react-error-overlay": "^6.0.9", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "browserslist": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.2.tgz", + "integrity": "sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001125", + "electron-to-chromium": "^1.3.564", + "escalade": "^3.0.2", + "node-releases": "^1.1.61" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + } + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "react-dnd": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-2.6.0.tgz", + "integrity": "sha1-f6JWds+CfViokSk+PBq1naACVFo=", + "requires": { + "disposables": "^1.0.1", + "dnd-core": "^2.6.0", + "hoist-non-react-statics": "^2.1.0", + "invariant": "^2.1.0", + "lodash": "^4.2.0", + "prop-types": "^15.5.10" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + } + } + }, + "react-dnd-html5-backend": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-2.6.0.tgz", + "integrity": "sha1-WQzRzKeEQbsnTt1XH+9MCxbdz44=", + "requires": { + "lodash": "^4.2.0" + } + }, + "react-docgen": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.3.1.tgz", + "integrity": "sha512-YG7YujVTwlLslr2Ny8nQiUfbBuEwKsLHJdQTSdEga1eY/nRFh/7LjCWUn6ogYhu2WDKg4z+6W/BJtUi+DPUIlA==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@babel/runtime": "^7.7.6", + "ast-types": "^0.14.2", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "neo-async": "^2.6.1", + "node-dir": "^0.1.10", + "strip-indent": "^3.0.0" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "react-docgen-typescript": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-1.21.0.tgz", + "integrity": "sha512-E4y/OcXwHukgiVafCGlxwoNHr4BDmM70Ww7oimL/QkMo5dmGALhceewe/xmVjdMxxI7E5syOGOc9/tbHL742rg==", + "dev": true, + "requires": {} + }, + "react-docgen-typescript-plugin": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-0.6.3.tgz", + "integrity": "sha512-av1S/fmWBNFGgNa4qtkidFjjOz23eEi6EdCtwSWo9WNhGzUMyMygbD/DosMWoeFlZpk9R3MXPkRE7PDH6j5GMQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "endent": "^2.0.1", + "micromatch": "^4.0.2", + "react-docgen-typescript": "^1.20.5", + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, + "react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-draggable": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz", + "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", + "dev": true, + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, + "react-error-overlay": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", + "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==", + "dev": true + }, + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==", + "dev": true + }, + "react-google-recaptcha": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-1.1.0.tgz", + "integrity": "sha512-GMWZEsIKyBVG+iXfVMwtMVKFJATu5c+oguL/5i95H3Jb5d5CG4DY0W9t4QhdSSulgkXbZMgv0VSuGF/GV1ENTA==", + "requires": { + "prop-types": "^15.5.0", + "react-async-script": "^1.0.0" + } + }, + "react-helmet-async": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.0.9.tgz", + "integrity": "sha512-N+iUlo9WR3/u9qGMmP4jiYfaD6pe9IvDTapZLFJz2D3xlTlCM1Bzy4Ab3g72Nbajo/0ZyW+W9hdz8Hbe4l97pQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + } + }, + "react-highlight": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.14.0.tgz", + "integrity": "sha512-kWE+KXOXidS7SABhVopOgMnowbI3RAfeGZbnrduLNlWrYAED8sycL9l/Fvw3w0PFpIIawB7mRDnyhDcM/cIIGA==", + "requires": { + "highlight.js": "^10.5.0" + } + }, + "react-hotkeys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz", + "integrity": "sha512-3n3OU8vLX/pfcJrR3xJ1zlww6KS1kEJt0Whxc4FiGV+MJrQ1mYSYI3qS/11d2MJDFm8IhOXMTFQirfu6AVOF6Q==", + "dev": true, + "requires": { + "prop-types": "^15.6.1" + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "react-json-tree": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.11.2.tgz", + "integrity": "sha512-aYhUPj1y5jR3ZQ+G3N7aL8FbTyO03iLwnVvvEikLcNFqNTyabdljo9xDftZndUBFyyyL0aK3qGO9+8EilILHUw==", + "requires": { + "babel-runtime": "^6.6.1", + "prop-types": "^15.5.8", + "react-base16-styling": "^0.5.1" + } + }, + "react-json-view": { + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", + "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", + "requires": { + "flux": "^4.0.1", + "react-base16-styling": "^0.6.0", + "react-lifecycles-compat": "^3.0.4", + "react-textarea-autosize": "^8.3.2" + }, + "dependencies": { + "react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", + "integrity": "sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=", + "requires": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + } + } + }, + "react-lazyload": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-lazyload/-/react-lazyload-3.2.0.tgz", + "integrity": "sha512-zJlrG8QyVZz4+xkYZH5v1w3YaP5wEFaYSUWC4CT9UXfK75IfRAIEdnyIUF+dXr3kX2MOtL1lUaZmaQZqrETwgw==", + "requires": {} + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-onclickoutside": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.10.0.tgz", + "integrity": "sha512-7i2L3ef+0ILXpL6P+Hg304eCQswh4jl3ynwR71BSlMU49PE2uk31k8B2GkP6yE9s2D4jTGKnzuSpzWxu4YxfQQ==", + "requires": {} + }, + "react-popper": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz", + "integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==", + "requires": { + "@babel/runtime": "^7.1.2", + "@hypnosphi/create-react-context": "^0.3.1", + "deep-equal": "^1.1.1", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.7", + "warning": "^4.0.2" + } + }, + "react-popper-tooltip": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz", + "integrity": "sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@popperjs/core": "^2.5.4", + "react-popper": "^2.2.4" + }, + "dependencies": { + "react-popper": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.4.tgz", + "integrity": "sha512-NacOu4zWupdQjVXq02XpTD3yFPSfg5a7fex0wa3uGKVkFK7UN6LvVxgcb+xYr56UCuWiNPMH20tntdVdJRwYew==", + "dev": true, + "requires": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + } + } + } + }, + "react-redux": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.2.tgz", + "integrity": "sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q==", + "requires": { + "@babel/runtime": "^7.1.2", + "hoist-non-react-statics": "^3.3.0", + "invariant": "^2.2.4", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.1", + "react-is": "^16.6.0", + "react-lifecycles-compat": "^3.0.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "react-refresh": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", + "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==", + "dev": true + }, + "react-resize-detector": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-2.3.0.tgz", + "integrity": "sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ==", + "requires": { + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "prop-types": "^15.6.0", + "resize-observer-polyfill": "^1.5.0" + } + }, + "react-router": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", + "integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==", + "requires": { + "history": "^4.7.2", + "hoist-non-react-statics": "^2.5.0", + "invariant": "^2.2.4", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.1", + "warning": "^4.0.1" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz", + "integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==", + "requires": { + "history": "^4.7.2", + "invariant": "^2.2.4", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.1", + "react-router": "^4.3.1", + "warning": "^4.0.1" + } + }, + "react-scripts": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.4.tgz", + "integrity": "sha512-7J7GZyF/QvZkKAZLneiOIhHozvOMHey7hO9cdO9u68jjhGZlI8hDdOm6UyuHofn6Ajc9Uji5I6Psm/nKNuWdyw==", + "dev": true, + "requires": { + "@babel/core": "7.9.0", + "@svgr/webpack": "4.3.3", + "@typescript-eslint/eslint-plugin": "^2.10.0", + "@typescript-eslint/parser": "^2.10.0", + "babel-eslint": "10.1.0", + "babel-jest": "^24.9.0", + "babel-loader": "8.1.0", + "babel-plugin-named-asset-import": "^0.3.6", + "babel-preset-react-app": "^9.1.2", + "camelcase": "^5.3.1", + "case-sensitive-paths-webpack-plugin": "2.3.0", + "css-loader": "3.4.2", + "dotenv": "8.2.0", + "dotenv-expand": "5.1.0", + "eslint": "^6.6.0", + "eslint-config-react-app": "^5.2.1", + "eslint-loader": "3.0.3", + "eslint-plugin-flowtype": "4.6.0", + "eslint-plugin-import": "2.20.1", + "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-react": "7.19.0", + "eslint-plugin-react-hooks": "^1.6.1", + "file-loader": "4.3.0", + "fs-extra": "^8.1.0", + "fsevents": "2.1.2", + "html-webpack-plugin": "4.0.0-beta.11", + "identity-obj-proxy": "3.0.0", + "jest": "24.9.0", + "jest-environment-jsdom-fourteen": "1.0.1", + "jest-resolve": "24.9.0", + "jest-watch-typeahead": "0.4.2", + "mini-css-extract-plugin": "0.9.0", + "optimize-css-assets-webpack-plugin": "5.0.3", + "pnp-webpack-plugin": "1.6.4", + "postcss-flexbugs-fixes": "4.1.0", + "postcss-loader": "3.0.0", + "postcss-normalize": "8.0.1", + "postcss-preset-env": "6.7.0", + "postcss-safe-parser": "4.0.1", + "react-app-polyfill": "^1.0.6", + "react-dev-utils": "^10.2.1", + "resolve": "1.15.0", + "resolve-url-loader": "3.1.2", + "sass-loader": "8.0.2", + "semver": "6.3.0", + "style-loader": "0.23.1", + "terser-webpack-plugin": "2.3.8", + "ts-pnp": "1.1.6", + "url-loader": "2.3.0", + "webpack": "4.42.0", + "webpack-dev-server": "3.11.0", + "webpack-manifest-plugin": "2.2.0", + "workbox-webpack-plugin": "4.3.1" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", + "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.34.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/parser": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", + "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + } + }, + "browserslist": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.10.0.tgz", + "integrity": "sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001035", + "electron-to-chromium": "^1.3.378", + "node-releases": "^1.1.52", + "pkg-up": "^3.1.0" + } + }, + "cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "dev": true, + "requires": { + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^7.0.0", + "unique-filename": "^1.1.1" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", + "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==", + "dev": true + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "css-loader": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz", + "integrity": "sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.23", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.1.1", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.0.2", + "schema-utils": "^2.6.0" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + } + } + }, + "eslint-config-react-app": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz", + "integrity": "sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.9" + } + }, + "eslint-loader": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-3.0.3.tgz", + "integrity": "sha512-+YRqB95PnNvxNp1HEjQmvf9KNvCin5HXYYseOXVC2U0KEcw4IkQ2IQEBG46j7+gW39bMzeu0GsUhVbBY3Votpw==", + "dev": true, + "requires": { + "fs-extra": "^8.1.0", + "loader-fs-cache": "^1.0.2", + "loader-utils": "^1.2.3", + "object-hash": "^2.0.1", + "schema-utils": "^2.6.1" + } + }, + "eslint-plugin-flowtype": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", + "integrity": "sha512-W5hLjpFfZyZsXfo5anlu7HM970JBDqbEshAJUkeczP6BFCIfJXuiIBQXyberLRtOStT0OGPF8efeTbxlHk4LpQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "eslint-plugin-import": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", + "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz", + "integrity": "sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.5", + "aria-query": "^3.0.0", + "array-includes": "^3.0.3", + "ast-types-flow": "^0.0.7", + "axobject-query": "^2.0.2", + "damerau-levenshtein": "^1.0.4", + "emoji-regex": "^7.0.2", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.1" + } + }, + "eslint-plugin-react": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", + "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.3", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.15.1", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" + }, + "dependencies": { + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "dependencies": { + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + } + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz", + "integrity": "sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.5.0" + } + }, + "filesize": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz", + "integrity": "sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==", + "dev": true + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "fork-ts-checker-webpack-plugin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz", + "integrity": "sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^3.3.0", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "html-webpack-plugin": { + "version": "4.0.0-beta.11", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz", + "integrity": "sha512-4Xzepf0qWxf8CGg7/WQM5qBB2Lc/NFI7MhU59eUDTkuQp3skZczH4UA1d6oQyDEIoMDgERVhRyTdtUPZ5s5HBg==", + "dev": true, + "requires": { + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.15", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "immer": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", + "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==", + "dev": true + }, + "inquirer": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", + "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "jest-worker": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", + "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsx-ast-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", + "integrity": "sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "object.assign": "^4.1.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + } + } + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "postcss-flexbugs-fixes": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", + "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "react-dev-utils": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz", + "integrity": "sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ==", + "dev": true, + "requires": { + "@babel/code-frame": "7.8.3", + "address": "1.1.2", + "browserslist": "4.10.0", + "chalk": "2.4.2", + "cross-spawn": "7.0.1", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "2.0.0", + "filesize": "6.0.1", + "find-up": "4.1.0", + "fork-ts-checker-webpack-plugin": "3.1.1", + "global-modules": "2.0.0", + "globby": "8.0.2", + "gzip-size": "5.1.1", + "immer": "1.10.0", + "inquirer": "7.0.4", + "is-root": "2.1.0", + "loader-utils": "1.2.3", + "open": "^7.0.2", + "pkg-up": "3.1.0", + "react-error-overlay": "^6.0.7", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "sockjs": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz", + "integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.4.0", + "websocket-driver": "0.6.5" + }, + "dependencies": { + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "sockjs-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "ssri": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", + "integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==", + "dev": true, + "requires": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.3.1", + "jest-worker": "^25.4.0", + "p-limit": "^2.3.0", + "schema-utils": "^2.6.6", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.6.12", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "ts-pnp": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz", + "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "url-loader": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-2.3.0.tgz", + "integrity": "sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "mime": "^2.4.4", + "schema-utils": "^2.5.0" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "webpack": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", + "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.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.1", + "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.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "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" + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + } + } + }, + "webpack-dev-server": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz", + "integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.20", + "sockjs-client": "1.4.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "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" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "websocket-driver": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "dev": true, + "requires": { + "websocket-extensions": ">=0.1.1" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "react-sizeme": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/react-sizeme/-/react-sizeme-2.6.12.tgz", + "integrity": "sha512-tL4sCgfmvapYRZ1FO2VmBmjPVzzqgHA7kI8lSJ6JS6L78jXFNRdOZFpXyK6P1NBZvKPPCZxReNgzZNUajAerZw==", + "dev": true, + "requires": { + "element-resize-detector": "^1.2.1", + "invariant": "^2.2.4", + "shallowequal": "^1.1.0", + "throttle-debounce": "^2.1.0" + } + }, + "react-smooth": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-1.0.6.tgz", + "integrity": "sha512-B2vL4trGpNSMSOzFiAul9kFAsxTukL9Wyy9EXtkQy3GJr6sZqW9e1nShdVOJ3hRYamPZ94O17r3Q0bjSw3UYtg==", + "requires": { + "lodash": "~4.17.4", + "prop-types": "^15.6.0", + "raf": "^3.4.0", + "react-transition-group": "^2.5.0" + }, + "dependencies": { + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + } + } + }, + "react-syntax-highlighter": { + "version": "13.5.3", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz", + "integrity": "sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.1.1", + "lowlight": "^1.14.0", + "prismjs": "^1.21.0", + "refractor": "^3.1.0" + } + }, + "react-textarea-autosize": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.2.tgz", + "integrity": "sha512-JrMWVgQSaExQByP3ggI1eA8zF4mF0+ddVuX7acUeK2V7bmrpjVOY72vmLz2IXFJSAXoY3D80nEzrn0GWajWK3Q==", + "requires": { + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.0.0", + "use-latest": "^1.0.0" + } + }, + "react-toastify": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-5.5.0.tgz", + "integrity": "sha512-jsVme7jALIFGRyQsri/g4YTsRuaaGI70T6/ikjwZMB4mwTZaCWqj5NqxhGrRStKlJc5npXKKvKeqTiRGQl78LQ==", + "requires": { + "@babel/runtime": "^7.4.2", + "classnames": "^2.2.6", + "prop-types": "^15.7.2", + "react-transition-group": "^4" + } + }, + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "react-virtualized": { + "version": "9.22.3", + "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz", + "integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==", + "requires": { + "@babel/runtime": "^7.7.2", + "clsx": "^1.0.4", + "dom-helpers": "^5.1.3", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + } + }, + "reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "dev": true, + "requires": { + "lodash": "^4.0.1" + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "dependencies": { + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "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" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "readline-ui": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/readline-ui/-/readline-ui-2.2.3.tgz", + "integrity": "sha512-ix7jz0PxqQqcIuq3yQTHv1TOhlD2IHO74aNO+lSuXsRYm1d+pdyup1yF3zKyLK1wWZrVNGjkzw5tUegO2IDy+A==", + "dev": true, + "requires": { + "component-emitter": "^1.2.1", + "debug": "^2.6.8", + "readline-utils": "^2.2.1", + "string-width": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + } + } + }, + "readline-utils": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/readline-utils/-/readline-utils-2.2.3.tgz", + "integrity": "sha1-b4R9a48ZFcORtYHDZ81HhzhiNRo=", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "extend-shallow": "^2.0.1", + "is-buffer": "^1.1.5", + "is-number": "^3.0.0", + "is-windows": "^1.0.1", + "koalas": "^1.0.2", + "mute-stream": "0.0.7", + "strip-color": "^0.1.0", + "window-size": "^1.1.0" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + } + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "recharts": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-1.8.5.tgz", + "integrity": "sha512-tM9mprJbXVEBxjM7zHsIy6Cc41oO/pVYqyAsOHLxlJrbNBuLs0PHB3iys2M+RqCF0//k8nJtZF6X6swSkWY3tg==", + "requires": { + "classnames": "^2.2.5", + "core-js": "^2.6.10", + "d3-interpolate": "^1.3.0", + "d3-scale": "^2.1.0", + "d3-shape": "^1.2.0", + "lodash": "^4.17.5", + "prop-types": "^15.6.0", + "react-resize-detector": "^2.3.0", + "react-smooth": "^1.0.5", + "recharts-scale": "^0.4.2", + "reduce-css-calc": "^1.3.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + } + } + }, + "recharts-scale": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.4.tgz", + "integrity": "sha512-e7MCnuD1+gtY9N7TYxzB+QXvi4s30kvNqVbI1p5m4rf47GusEQaEHxi8zvlZkdOOZ90UhpGHcnkYlyYkUJ2JoQ==", + "requires": { + "decimal.js-light": "^2.4.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "requires": { + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + } + } + }, + "reduce-function-call": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", + "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, + "redux-immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redux-immutable/-/redux-immutable-4.0.0.tgz", + "integrity": "sha1-Ohoy32Y2ZGK2NpHw4dw15HK7yfM=", + "requires": {} + }, + "redux-thunk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", + "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" + }, + "refractor": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.3.1.tgz", + "integrity": "sha512-vaN6R56kLMuBszHSWlwTpcZ8KTMG6aUCok4GrxYDT20UIOXxOc5o6oDc8tNTzSlH3m2sI+Eu9Jo2kVdDcUTWYw==", + "dev": true, + "requires": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.23.0" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true, + "peer": true + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", + "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", + "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", + "dev": true, + "requires": { + "css-select": "^2.0.2", + "dom-converter": "^0.2", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "dev": true + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "peer": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + } + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "dev": true, + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "peer": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true, + "peer": true + } + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "reselect": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", + "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=", + "dev": true, + "peer": true + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + } + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "resolve-url-loader": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz", + "integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "3.0.0", + "camelcase": "5.3.1", + "compose-function": "3.0.3", + "convert-source-map": "1.7.0", + "es6-iterator": "2.0.3", + "loader-utils": "1.2.3", + "postcss": "7.0.21", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "postcss": { + "version": "7.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz", + "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rework": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", + "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", + "dev": true, + "requires": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + }, + "dependencies": { + "convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=", + "dev": true + } + } + }, + "rework-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", + "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true, + "peer": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "peer": true, + "requires": { + "rx-lite": "*" + } + }, + "rxjs": { + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz", + "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "sanitize.css": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz", + "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==", + "dev": true + }, + "sass-loader": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz", + "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.6.1", + "semver": "^6.3.0" + }, + "dependencies": { + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + } + } + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", + "dev": true + }, + "saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "dev": true, + "requires": { + "xmlchars": "^2.1.1" + } + }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "dev": true, + "optional": true + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", + "dev": true, + "requires": { + "node-forge": "^0.10.0" + } + }, + "semantic-ui-react": { + "version": "0.87.3", + "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.87.3.tgz", + "integrity": "sha512-YJgFYEheeFBMm/epZpIpWKF9glgSShdLPiY8zoUi+KJ0IKtLtbI8RbMD/ELbZkY+SO/IWbK/f/86pWt3PVvMVA==", + "requires": { + "@babel/runtime": "^7.1.2", + "@semantic-ui-react/event-stack": "^3.1.0", + "classnames": "^2.2.6", + "keyboard-key": "^1.0.4", + "lodash": "^4.17.11", + "prop-types": "^15.6.2", + "react-is": "^16.7.0", + "react-popper": "^1.3.3", + "shallowequal": "^1.1.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=", + "dev": true, + "requires": { + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + } + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-getter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", + "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", + "dev": true, + "requires": { + "to-object-path": "^0.3.0" + } + }, + "set-value": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-3.0.2.tgz", + "integrity": "sha512-npjkVoz+ank0zjlV9F47Fdbjfj/PfXyVhZvGALWsyIYU/qrMzpi6avjKW3/7KeSU2Df3I46BrN1xOI1+6vW0hA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" + }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "shapefile": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/shapefile/-/shapefile-0.3.1.tgz", + "integrity": "sha1-m7mkKb1ghqDPsDli0Uz99CD/uhI=", + "requires": { + "d3-queue": "1", + "iconv-lite": "0.2", + "optimist": "0.3" + }, + "dependencies": { + "d3-queue": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-1.2.3.tgz", + "integrity": "sha1-FDpwHPpl/gISkvMhwQ0U6Yq9SRs=" + }, + "iconv-lite": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", + "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=" + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "dependencies": { + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + } + } + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "peer": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "peer": true + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.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" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "socket.io-client": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-3.1.3.tgz", + "integrity": "sha512-4sIGOGOmCg3AOgGi7EEr6ZkTZRkrXwub70bBB/F0JSkMOUFpA77WsL87o34DffQQ31PkbMUIadGOk+3tx1KGbw==", + "requires": { + "@types/component-emitter": "^1.2.10", + "backo2": "~1.0.2", + "component-emitter": "~1.3.0", + "debug": "~4.3.1", + "engine.io-client": "~4.1.0", + "parseuri": "0.0.6", + "socket.io-parser": "~4.0.4" + } + }, + "socket.io-parser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", + "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "requires": { + "@types/component-emitter": "^1.2.10", + "component-emitter": "~1.3.0", + "debug": "~4.3.1" + } + }, + "sockjs": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", + "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "sockjs-client": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.0.tgz", + "integrity": "sha512-8Dt3BDi4FYNrCFGTL/HtwVzkARrENdwOUf1ZoW/9p3M8lZdFT35jVdrHza+qgxuG9H3/shR4cuX/X9umUrjP8Q==", + "dev": true, + "requires": { + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.4.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "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": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "stack-utils": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.4.tgz", + "integrity": "sha512-IPDJfugEGbfizBwBZRZ3xpccMdRyP5lqsBWXGQWimVjua/ccLCeMOAVjlc1R7LxFjo5sEDhyNIXd8mo/AiDS9w==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", + "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", + "dev": true + }, + "static-eval": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz", + "integrity": "sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==", + "requires": { + "escodegen": "^1.11.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + } + } + }, + "static-module": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/static-module/-/static-module-2.2.5.tgz", + "integrity": "sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ==", + "requires": { + "concat-stream": "~1.6.0", + "convert-source-map": "^1.5.1", + "duplexer2": "~0.1.4", + "escodegen": "~1.9.0", + "falafel": "^2.1.0", + "has": "^1.0.1", + "magic-string": "^0.22.4", + "merge-source-map": "1.0.4", + "object-inspect": "~1.4.0", + "quote-stream": "~1.0.2", + "readable-stream": "~2.3.3", + "shallow-copy": "~0.0.1", + "static-eval": "^2.0.0", + "through2": "~2.0.3" + }, + "dependencies": { + "escodegen": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", + "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + }, + "object-inspect": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.4.1.tgz", + "integrity": "sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "store2": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/store2/-/store2-2.12.0.tgz", + "integrity": "sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw==", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string.prototype.matchall": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", + "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + } + }, + "string.prototype.padend": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz", + "integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, + "string.prototype.padstart": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.padstart/-/string.prototype.padstart-3.1.2.tgz", + "integrity": "sha512-HDpngIP3pd0DeazrfqzuBrQZa+D2arKWquEHfGt5LzVjd+roLC3cjqVI0X8foaZz5rrrhcu8oJAQamW8on9dqw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-color": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", + "integrity": "sha1-EG9l09PmotlAHKwOsM6LinArT3s=", + "dev": true + }, + "strip-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", + "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", + "dev": true, + "requires": { + "babel-extract-comments": "^1.0.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "peer": true + }, + "style-loader": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "success-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/success-symbol/-/success-symbol-0.1.0.tgz", + "integrity": "sha1-JAIuSG878c3KCUKDt2nEctO3KJc=", + "dev": true + }, + "sugarss": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz", + "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "dev": true + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + } + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "symbol.prototype.description": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/symbol.prototype.description/-/symbol.prototype.description-1.0.4.tgz", + "integrity": "sha512-fZkHwJ8ZNRVRzF/+/2OtygyyH06CjC0YZAQRHu9jKKw8RXlJpbizEHvGRUu22Qkg182wJk1ugb5Aovcv3UPrww==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.2" + } + }, + "syncod": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/syncod/-/syncod-0.0.1.tgz", + "integrity": "sha512-KHDsGQ4UcP+wSMaqH7wjH4DHxeHKRlmEO5jlSVCS+0x9xA4ZhdKYg/ameGF7RXaFDUcsti6Zj5s5W1Z4/YsbHA==" + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "peer": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "peer": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + } + } + }, + "tailwindcss": { + "version": "1.9.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.9.6.tgz", + "integrity": "sha512-nY8WYM/RLPqGsPEGEV2z63riyQPcHYZUJpAwdyBzVpxQHOHqHE+F/fvbCeXhdF1+TA5l72vSkZrtYCB9hRcwkQ==", + "requires": { + "@fullhuman/postcss-purgecss": "^2.1.2", + "autoprefixer": "^9.4.5", + "browserslist": "^4.12.0", + "bytes": "^3.0.0", + "chalk": "^3.0.0 || ^4.0.0", + "color": "^3.1.2", + "detective": "^5.2.0", + "fs-extra": "^8.0.0", + "html-tags": "^3.1.0", + "lodash": "^4.17.20", + "node-emoji": "^1.8.1", + "normalize.css": "^8.0.1", + "object-hash": "^2.0.3", + "postcss": "^7.0.11", + "postcss-functions": "^3.0.0", + "postcss-js": "^2.0.0", + "postcss-nested": "^4.1.1", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^4.1.0", + "pretty-hrtime": "^1.0.3", + "reduce-css-calc": "^2.1.6", + "resolve": "^1.14.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + }, + "reduce-css-calc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", + "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", + "requires": { + "css-unit-converter": "^1.1.1", + "postcss-value-parser": "^3.3.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + } + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "telejson": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-5.1.0.tgz", + "integrity": "sha512-Yy0N2OV0mosmr1SCZEm3Ezhu/oi5Dbao5RqauZu4+VI5I/XtVBHXajRk0txuqbFYtKdzzWGDZFGSif9ovVLjEA==", + "dev": true, + "requires": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.1", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.20", + "memoizerific": "^1.11.3" + }, + "dependencies": { + "isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true + } + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "terminal-paginator": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/terminal-paginator/-/terminal-paginator-2.0.2.tgz", + "integrity": "sha512-IZMT5ECF9p4s+sNCV8uvZSW9E1+9zy9Ji9xz2oee8Jfo7hUFpauyjxkhfRcIH6Lu3Wdepv5D1kVRc8Hx74/LfQ==", + "dev": true, + "requires": { + "debug": "^2.6.6", + "extend-shallow": "^2.0.1", + "log-utils": "^0.2.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-3.1.0.tgz", + "integrity": "sha512-cjdZte66fYkZ65rQ2oJfrdCAkkhJA7YLYk5eGOcGCSGlq0ieZupRdjedSQXYknMPo2IveQL+tPdrxUkERENCFA==", + "dev": true, + "requires": { + "cacache": "^15.0.5", + "find-cache-dir": "^3.3.1", + "jest-worker": "^26.2.1", + "p-limit": "^3.0.2", + "schema-utils": "^2.6.6", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.8.0", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "cacache": { + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz", + "integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==", + "dev": true, + "requires": { + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + } + } + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "dev": true, + "optional": true + }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toggle-array": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toggle-array/-/toggle-array-1.0.1.tgz", + "integrity": "sha1-y/WEB5K9UJfzMReugkyTKv/ofVg=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "topojson": { + "version": "1.6.27", + "resolved": "https://registry.npmjs.org/topojson/-/topojson-1.6.27.tgz", + "integrity": "sha1-rb4zpn4vFnPTON8SZErSD8ILQu0=", + "requires": { + "d3": "3", + "d3-geo-projection": "0.2", + "d3-queue": "2", + "optimist": "0.3", + "rw": "1", + "shapefile": "0.3" + } + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true, + "peer": true + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", + "dev": true + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "dev": true + }, + "ts-dedent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.1.0.tgz", + "integrity": "sha512-HbmrG+lCgk5W8LQTALxBxQRBDeAhQKRzdqVhHLUkVd5nYT+b6zDzbRMjiA8wqrWDa33X09WdnW4zEsdwQArTaw==", + "dev": true + }, + "ts-essentials": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", + "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" + }, + "ts-pnp": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", + "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==", + "dev": true + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typescript": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", + "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "dev": true, + "peer": true + }, + "ua-parser-js": { + "version": "0.7.25", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.25.tgz", + "integrity": "sha512-8NFExdfI24Ny8R3Vc6+uUytP/I7dpqk3JERlvxPWlrtx5YboqCgxAXYKPAifbPLV2zKbgmmPL53ufW7mUC/VOQ==" + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "unbox-primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz", + "integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.0", + "has-symbols": "^1.0.0", + "which-boxed-primitive": "^1.0.1" + } + }, + "underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "dev": true + }, + "unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "dependencies": { + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "url-parse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "use-composed-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz", + "integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==", + "requires": { + "ts-essentials": "^2.0.3" + } + }, + "use-isomorphic-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", + "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==", + "requires": {} + }, + "use-latest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz", + "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==", + "requires": { + "use-isomorphic-layout-effect": "^1.0.0" + } + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "dev": true, + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "warning-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/warning-symbol/-/warning-symbol-0.1.0.tgz", + "integrity": "sha1-uzHdEbeg+dZ6su2V9Fe2WCW7rSE=", + "dev": true + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dev": true, + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "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" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "dev": true, + "requires": { + "@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.5.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.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + } + } + }, + "webpack-bundle-analyzer": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz", + "integrity": "sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.19", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", + "dev": true + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", + "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true + } + } + }, + "webpack-dev-server": { + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz", + "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "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" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-filter-warnings-plugin": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/webpack-filter-warnings-plugin/-/webpack-filter-warnings-plugin-1.2.1.tgz", + "integrity": "sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg==", + "dev": true, + "requires": {} + }, + "webpack-hot-middleware": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.25.0.tgz", + "integrity": "sha512-xs5dPOrGPCzuRXNi8F6rwhawWvQQkeli5Ro48PRuQh8pYPCPmNnltP9itiUPT4xI8oW+y0m59lyyeQk54s5VgA==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "html-entities": "^1.2.0", + "querystring": "^0.2.0", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + } + } + }, + "webpack-manifest-plugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz", + "integrity": "sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ==", + "dev": true, + "requires": { + "fs-extra": "^7.0.0", + "lodash": ">=3.5 <5", + "object.entries": "^1.1.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "webpack-virtual-modules": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.2.2.tgz", + "integrity": "sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==", + "dev": true, + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==", + "dev": true + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + } + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "window-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-1.1.1.tgz", + "integrity": "sha512-5D/9vujkmVQ7pSmc0SCBmHXbkv6eaHwXEx65MywhmUMsI8sGqJ972APq1lotfcwMKPFLuCFfL8xGHLIp7jaBmA==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "is-number": "^3.0.0" + } + }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "dev": true, + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "dependencies": { + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "dev": true, + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "workbox-background-sync": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz", + "integrity": "sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-broadcast-update": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz", + "integrity": "sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-build": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-4.3.1.tgz", + "integrity": "sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.4", + "@hapi/joi": "^15.0.0", + "common-tags": "^1.8.0", + "fs-extra": "^4.0.2", + "glob": "^7.1.3", + "lodash.template": "^4.4.0", + "pretty-bytes": "^5.1.0", + "stringify-object": "^3.3.0", + "strip-comments": "^1.0.2", + "workbox-background-sync": "^4.3.1", + "workbox-broadcast-update": "^4.3.1", + "workbox-cacheable-response": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-expiration": "^4.3.1", + "workbox-google-analytics": "^4.3.1", + "workbox-navigation-preload": "^4.3.1", + "workbox-precaching": "^4.3.1", + "workbox-range-requests": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1", + "workbox-streams": "^4.3.1", + "workbox-sw": "^4.3.1", + "workbox-window": "^4.3.1" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "workbox-cacheable-response": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz", + "integrity": "sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-core": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-4.3.1.tgz", + "integrity": "sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg==", + "dev": true + }, + "workbox-expiration": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-4.3.1.tgz", + "integrity": "sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-google-analytics": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz", + "integrity": "sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg==", + "dev": true, + "requires": { + "workbox-background-sync": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1" + } + }, + "workbox-navigation-preload": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz", + "integrity": "sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-precaching": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-4.3.1.tgz", + "integrity": "sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-range-requests": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz", + "integrity": "sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-routing": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-4.3.1.tgz", + "integrity": "sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-strategies": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-4.3.1.tgz", + "integrity": "sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-streams": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-4.3.1.tgz", + "integrity": "sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-sw": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-4.3.1.tgz", + "integrity": "sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w==", + "dev": true + }, + "workbox-webpack-plugin": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz", + "integrity": "sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.0.0", + "json-stable-stringify": "^1.0.1", + "workbox-build": "^4.3.1" + } + }, + "workbox-window": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-4.3.1.tgz", + "integrity": "sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg==", + "dev": true, + "requires": { + "workbox-core": "^4.3.1" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "worker-rpc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz", + "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", + "dev": true, + "requires": { + "microevent.ts": "~0.1.1" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "peer": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "xregexp": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz", + "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", + "dev": true, + "requires": { + "@babel/runtime-corejs3": "^7.12.1" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "dependencies": { + "y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "dev": true + } + } + }, + "yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "dev": true + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 000000000..e96ab3dcd --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,113 @@ +{ + "name": "openreplay", + "version": "1.0.1", + "scripts": { + "start": "webpack-dev-server --watch --env=oss", + "build:oss": "npm run generate:icons && rm -rf public && webpack --env=oss", + "upload:minio": "node ./scripts/upload-minio.js", + "deploy:minio": "npm run build:minio && npm run upload:minio", + "lint": "eslint --fix app; exit 0", + "generate:constants": "node ./scripts/constants.js", + "generate:icons": "node ./scripts/icons.js", + "generate:colors": "node ./scripts/colors.js", + "storybook": "start-storybook", + "flow": "flow" + }, + "dependencies": { + "@sentry/browser": "^5.21.1", + "classnames": "^2.2.6", + "codemirror": "^5.56.0", + "copy-to-clipboard": "^3.3.1", + "datamaps": "^0.5.9", + "deep-diff": "^1.0.2", + "immutable": "^4.0.0-rc.12", + "jsbi": "^3.1.3", + "jshint": "^2.11.1", + "luxon": "^1.24.1", + "mobx": "^6.0.4", + "mobx-react-lite": "^3.1.6", + "moment": "^2.27.0", + "moment-range": "^4.0.2", + "optimal-select": "^4.0.1", + "rc-time-picker": "^3.7.3", + "react": "^16.13.1", + "react-circular-progressbar": "^2.0.3", + "react-codemirror2": "^5.1.0", + "react-confirm": "^0.1.20", + "react-datepicker": "^2.16.0", + "react-daterange-picker": "^2.0.1", + "react-dnd": "^2.6.0", + "react-dnd-html5-backend": "^2.6.0", + "react-dom": "^16.13.1", + "react-google-recaptcha": "^1.1.0", + "react-highlight": "^0.14.0", + "react-json-tree": "^0.11.2", + "react-json-view": "^1.19.1", + "react-lazyload": "^3.0.0", + "react-redux": "^5.1.2", + "react-router": "^4.3.1", + "react-router-dom": "^4.3.1", + "react-toastify": "^5.5.0", + "react-virtualized": "^9.22.2", + "recharts": "^1.8.5", + "redux": "^4.0.5", + "redux-immutable": "^4.0.0", + "redux-thunk": "^2.3.0", + "semantic-ui-react": "^0.87.3", + "socket.io-client": "^3.0.3", + "source-map": "^0.7.3", + "syncod": "^0.0.1", + "tailwindcss": "^1.5.2" + }, + "devDependencies": { + "@babel/cli": "^7.10.5", + "@babel/core": "^7.12.10", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-decorators": "^7.10.5", + "@babel/plugin-proposal-private-methods": "^7.10.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/preset-env": "^7.10.4", + "@babel/preset-flow": "^7.10.4", + "@babel/preset-react": "^7.10.4", + "@openreplay/sourcemap-uploader": "^3.0.0", + "@storybook/react": "^6.0.20", + "autoprefixer": "^7.2.5", + "babel-loader": "^8.1.0", + "babel-plugin-recharts": "^1.2.1", + "circular-dependency-plugin": "^5.2.0", + "copy-webpack-plugin": "^5.1.1", + "country-data": "0.0.31", + "css-loader": "^3.6.0", + "cssnano": "^4.1.10", + "deasync-promise": "^1.0.1", + "deploy-aws-s3-cloudfront": "^3.2.4", + "dotenv": "^6.2.0", + "eslint-config-airbnb": "^16.1.0", + "eslint-import-resolver-babel-module": "^4.0.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-jsx-a11y": "^6.3.1", + "eslint-plugin-react": "^7.20.6", + "faker": "^5.5.3", + "flow-bin": "^0.115.0", + "html-webpack-plugin": "^3.2.0", + "mini-css-extract-plugin": "^0.7.0", + "minio": "^7.0.18", + "moment-locales-webpack-plugin": "^1.2.0", + "postcss-import": "^12.0.1", + "postcss-inline-svg": "^3.1.1", + "postcss-loader": "^3.0.0", + "postcss-mixins": "^6.2.3", + "postcss-nesting": "^4.2.1", + "postcss-simple-vars": "^4.1.0", + "react-scripts": "^3.4.3", + "style-loader": "^0.23.1", + "svgo": "^1.3.2", + "webpack": "^4.44.0", + "webpack-bundle-analyzer": "^3.8.0", + "webpack-cli": "^3.3.12", + "webpack-dev-server": "^3.11.0" + }, + "engines": { + "node": ">=10.14.1" + } +} diff --git a/frontend/path-alias.js b/frontend/path-alias.js new file mode 100644 index 000000000..5ac058141 --- /dev/null +++ b/frontend/path-alias.js @@ -0,0 +1,13 @@ +const path = require('path'); + +module.exports = { + App: path.resolve(__dirname, './app'), + Duck: path.resolve(__dirname, './app/duck'), + Components: path.resolve(__dirname, './app/components'), + Shared: path.resolve(__dirname, './app/components/shared'), + UI: path.resolve(__dirname, './app/components/ui'), + HOCs: path.resolve(__dirname, './app/components/hocs'), + Types: path.resolve(__dirname, './app/types'), + Player: path.resolve(__dirname, './app/player'), + Issues: path.resolve(__dirname, './app/components/Session/Issues'), +}; \ No newline at end of file diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 000000000..a74b76340 --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,24 @@ +const path = require('path'); + +const colors = require('./app/theme/colors'); + +const cssnanoOptions = { zindex: false }; + +module.exports = ({ file, options, env }) => ({ + // parser: 'sugarss', // syntax check ? + plugins: { + 'postcss-import': { + path: path.join(__dirname, 'app/styles/import') + }, + 'postcss-mixins': {}, + 'postcss-simple-vars': { variables: colors }, + 'postcss-nesting': {}, + 'postcss-inline-svg': { + path: path.join(__dirname, 'app/svg'), + }, + 'tailwindcss': true, + autoprefixer: {}, + //'postcss-preset-env': {}, //includes autoprefixer + cssnano: env === 'production' ? cssnanoOptions : false, + } +}); \ No newline at end of file diff --git a/frontend/scripts/colors.js b/frontend/scripts/colors.js new file mode 100644 index 000000000..98c5baa3c --- /dev/null +++ b/frontend/scripts/colors.js @@ -0,0 +1,26 @@ +const fs = require('fs'); + +const COLORS_FILE = 'app/styles/import/colors.css'; + +const colors = fs.readFileSync(COLORS_FILE, 'utf8') + .split('\n') + .filter(s => s[0] === '$') + .map(s => s.split(':')[0].substr(1)); + + +fs.writeFileSync('app/styles/colors-autogen.css', `/* Auto-generated, DO NOT EDIT */ +@import 'colors.css'; + +/* fill */ +${ colors.map(color => `.fill-${ color } { fill: $${ color } }`).join('\n') } + +/* color */ +${ colors.map(color => `.color-${ color } { color: $${ color } }`).join('\n') } + +/* color */ +${ colors.map(color => `.hover-${ color }:hover { color: $${ color } }`).join('\n') } + +/* bg */ +${ colors.map(color => `.bg-${ color } { background-color: $${ color } }`).join('\n') } +`) + diff --git a/frontend/scripts/constants.js b/frontend/scripts/constants.js new file mode 100644 index 000000000..eb2d3e6d9 --- /dev/null +++ b/frontend/scripts/constants.js @@ -0,0 +1,48 @@ +const fs = require('fs'); +const countries = require('country-data').countries; + +delete countries['UK']; +delete countries['EU']; +for (code in countries) { + const country = countries[code]; + if (code.length != 2) { + delete countries[code]; + continue; + } + countries[code] = countries[code].name; +} + +function fromArray(data) { + const d = {}; + data.forEach(v => d[v.toLowerCase().replace(/ /g, '_')] = v); + return d; +}; +const os = fromArray(['Windows', 'Mac OS X', 'Android', 'Linux']); +const browsers = fromArray(['Chrome', 'Firefox', 'Opera', 'Edge', 'IE', 'Safari']); + +function toExport(name, data) { + return `\n\nexport const ${ name } = ${ JSON.stringify(data, null, 2) };`; +}; +fs.writeFileSync('app/constants.js', + "/* eslint-disable */" + + toExport('countries', countries) + + toExport('os', os) + + toExport('browsers', browsers) +); + +function toStyles(prefix, data) { + const r = Object.keys(data).map(key => `[data-${ prefix }="${ key }"] { + @mixin icon-before ${ prefix }/${ key }, $gray-medium, 12px { + display: inline-block; + vertical-align: middle; + margin-right: 5px; + } + &::after{ + color: $gray-medium; + content: "${ data[key] }"; + } +}`); + return "@import \"icons.css\";\n@import \"colors.css\";\n\n" + r.join("\n"); +}; +fs.writeFileSync('app/styles/browsers.css', toStyles('browser', browsers)); +fs.writeFileSync('app/styles/os.css', toStyles('os', os)); diff --git a/frontend/scripts/fs.js b/frontend/scripts/fs.js new file mode 100644 index 000000000..34be1b5b6 --- /dev/null +++ b/frontend/scripts/fs.js @@ -0,0 +1,20 @@ +const fs = require('fs'); + +function collectFilenames(dirName, filter = () => true) { + const files = fs.readdirSync(dirName, { withFileTypes: true }); + const names = []; + files.map((file) => { + if (file.isDirectory()) { + const namesFromDir = collectFilenames(`${ dirName }/${ file.name }`, filter) + .map(name => `${ file.name }/${ name }`); + [].push.apply(names, namesFromDir); + } else if(filter(file.name)) { + names.push(file.name); + } + }); + return names; +} + +module.exports = { + collectFilenames, +} \ No newline at end of file diff --git a/frontend/scripts/icons.js b/frontend/scripts/icons.js new file mode 100644 index 000000000..adc9352d0 --- /dev/null +++ b/frontend/scripts/icons.js @@ -0,0 +1,54 @@ +const fs = require('fs'); +const SVGO = require('svgo'); +const deasync = require('deasync-promise'); + +const { collectFilenames } = require('./fs'); + +const ICONS_DIRNAME = 'app/svg/icons'; +const UI_DIRNAME = 'app/components/ui'; + +const svgo = new SVGO({ plugins: [ + { removeAttrs: { attrs: [ "width", "height", "class", "data-name", "dataName" ] } }, + { addAttributesToSVGElement: { attributes: [ "width={ `${ width }px` }", "height={ `${ height }px` }" ] } }, + { convertPathData: true }, // ? + { removeViewBox: false }, // ? + // { removeXMLNS: true }, // ? + { inlineStyles: { onlyMatchedOnce: false } }, // ? + { replaceDashes: { + type: 'perItem', + fn: (item) => { + item.eachAttr(attr => { + attr.name = attr.name.replace(/-([a-z])/g, gr => gr[1].toUpperCase()) + }) + } + }} +]}); + +const svgRE = /\.svg$/; + +const icons = collectFilenames(ICONS_DIRNAME, n => svgRE.test(n)); + +fs.writeFileSync(`${ UI_DIRNAME }/SVG.js`, ` +/* Auto-generated, do not edit */ + +const SVG = ({ name, size, width=size, height=size }) => { + switch (name) { +${ icons.map(name => ` case '${ name.slice(0, -4) }': return ${ + deasync(svgo.optimize(fs.readFileSync( + `${ ICONS_DIRNAME }/${ name }`, + 'utf8', + ))).data + .replace(/xlink\:href/g, 'xlinkHref') + .replace(/xmlns\:xlink/g, 'xmlnsXlink') + }`).join('\n') } + default: + if (window.ENV.PRODUCTION) return null; + throw "unknown icon name " + name; + } +} + +SVG.displayName = 'SVG'; +export default SVG; +`); + +console.log('SVG.js generated') \ No newline at end of file diff --git a/frontend/scripts/upload-minio.js b/frontend/scripts/upload-minio.js new file mode 100644 index 000000000..3e59d9c4e --- /dev/null +++ b/frontend/scripts/upload-minio.js @@ -0,0 +1,20 @@ +const Minio = require('minio') +const { collectFilenames } = require('./fs'); + +const PUBLIC_DIR = 'public'; + +var minioClient = new Minio.Client({ + endPoint: window.ENV.MINIO_ENDPOINT, + port: window.ENV.MINIO_PORT, + useSSL: window.ENV.MINIO_USE_SSL, //? + accessKey: window.ENV.MINIO_ACCESS_KEY, + secretKey: window.ENV.MINIO_SECRET_KEY, +}); + +collectFilenames(PUBLIC_DIR, n => !n.includes('.DS_Store')).forEach(name => { + minioClient.fPutObject('frontend', name,`${PUBLIC_DIR}/${name}`, {}, function(err, etag) { + if (err != null) { + throw new Error(err); + } + }) +}); diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js new file mode 100644 index 000000000..1de3da356 --- /dev/null +++ b/frontend/tailwind.config.js @@ -0,0 +1,115 @@ +const colors = require('./app/theme/colors'); + +module.exports = { + purge: [], + corePlugins: [ + 'preflight', + 'container', + // 'accessibility', + // 'alignContent', + 'alignItems', + 'alignSelf', + //'appearance', + // 'backgroundAttachment', + // 'backgroundColor', // TODO: replace genscript + // 'backgroundOpacity', + // 'backgroundPosition', + // 'backgroundRepeat', + // 'backgroundSize', + // 'borderCollapse', + 'borderColor', + // 'borderOpacity', + 'borderRadius', + // 'borderStyle', + 'borderWidth', + // 'boxSizing', + // 'boxShadow', + // 'clear', + 'cursor', + 'display', + // 'divideColor', + // 'divideWidth', + // 'fill', + 'flex', + 'flexDirection', + // 'flexGrow', + 'flexShrink', + 'flexWrap', + // 'float', + 'gap', + 'gridAutoFlow', + 'gridColumn', + 'gridColumnStart', + 'gridColumnEnd', + 'gridRow', + 'gridRowStart', + 'gridRowEnd', + 'gridTemplateColumns', + 'gridTemplateRows', + 'fontFamily', + 'fontSize', + //'fontSmoothing', + 'fontStyle', + 'fontWeight', + 'height', + 'inset', + 'justifyContent', + 'letterSpacing', + 'lineHeight', + // 'listStylePosition', + // 'listStyleType', + 'margin', + // 'maxHeight', + // 'maxWidth', + // 'minHeight', + // 'minWidth', + // 'objectFit', + // 'objectPosition', + 'opacity', + // 'order', + 'outline', + 'overflow', + 'padding', + // 'placeholderColor', + // 'placeholderOpacity', + 'pointerEvents', + 'position', + // 'resize', + // 'rotate', + // 'scale', + // 'skew', + // 'space', + // 'stroke', + // 'strokeWidth', + // 'tableLayout', + 'textAlign', + // 'textColor', + // 'textOpacity', + // 'textDecoration', + 'textTransform', + // 'transform', + // 'transitionDuration', + // 'transitionProperty', + // 'transitionTimingFunction', + // 'translate', + // 'userSelect', + // 'verticalAlign', + 'visibility', + 'whitespace', + 'width', + 'wordBreak', + 'zIndex' + ], + theme: { + colors, + borderColor: { + default: '#DDDDDD', + "gray-light-shade": colors["gray-light-shade"], + }, + extend: {}, + }, + variants: { + visibility: ['responsive', 'hover', 'focus', 'group-hover'] + }, + plugins: [], +} diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js new file mode 100644 index 000000000..c8f3039ce --- /dev/null +++ b/frontend/webpack.config.js @@ -0,0 +1,171 @@ +const webpack = require('webpack'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +// const CircularDependencyPlugin = require('circular-dependency-plugin') +// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +const MomentLocalesPlugin = require('moment-locales-webpack-plugin'); //TODO: replace Moment with date-fns ?? +const path = require('path'); +const fs = require('fs'); +const alias = require('./path-alias'); +const environments = require('./env'); + + +const DIST_DIR = 'public'; + +const GLOBAL_STYLES_DIR = 'app/styles'; + +const cssEntrypoints = [ + 'codemirror/lib/codemirror.css', + 'codemirror/theme/yeti.css', + 'codemirror/addon/lint/lint.css', + 'react-daterange-picker/dist/css/react-calendar.css', + 'react-datepicker/dist/react-datepicker.css', + 'rc-time-picker/assets/index.css', +]; + +const cssFiles = fs.readdirSync(GLOBAL_STYLES_DIR, { withFileTypes: true }); +cssFiles.forEach(file => { + if (/.css$/.test(file.name)) { + const pathFullName = path.join(__dirname, GLOBAL_STYLES_DIR, file.name); + cssEntrypoints.push(pathFullName); + } +}); + + +function prepareEnv(env) { + const pEnv = {}; + Object.keys(env).forEach(key => { + pEnv[ `window.ENV.${ key }` ] = typeof env[ key ] === 'function' ? env[ key ]() : JSON.stringify(env[ key ]); + }); + return pEnv; +} + +module.exports = (envName = 'local') => { + const env = environments[ envName ]; + const cssFileLoader = { + loader: MiniCssExtractPlugin.loader, + options: { + hmr: !env.PRODUCTION, + }, + } + return { + // Polyfill only for async (TODO) + entry: [ './app/initialize.js' ].concat(cssEntrypoints), + output: { + path: path.join(__dirname, DIST_DIR), + filename: 'app-[contenthash:7].js', + publicPath: '/', + }, + plugins: [ + new webpack.ProvidePlugin({ + 'React': 'react' // back code compatability + }), + new MiniCssExtractPlugin({ + path: path.join(__dirname, DIST_DIR), + filename: 'app-[contenthash:7].css' + }), + new CopyWebpackPlugin([ 'app/assets' ]), + new HtmlWebpackPlugin({ + template: 'app/assets/index.html' + }), + new MomentLocalesPlugin(), + new webpack.DefinePlugin(prepareEnv(env)), + // new BundleAnalyzerPlugin({ analyzerMode: 'static'}), + // new CircularDependencyPlugin({ + // // exclude detection of files based on a RegExp + // exclude: /node_modules/, + // // add errors to webpack instead of warnings + // failOnError: true, + // // allow import cycles that include an asyncronous import, + // // e.g. via import(/* webpackMode: "weak" */ './file.js') + // allowAsyncCycles: false, + // // set the current working directory for displaying module paths + // cwd: process.cwd(), + // }) + ], + module: { + rules: [ + + // global and module css separation. TODO more beautyfull + { + test: /\.css$/, + exclude: [ /node_modules/, /app\/styles/ ], + use: [ + cssFileLoader, + { + loader: 'css-loader', + options: { + importLoaders: 1, + modules: { + localIdentName: '[name]_[local]_[hash:base64:7]' + }, + } + }, + 'postcss-loader' + ] + }, + { + test: /\.css$/, + include: [ /node_modules/, /app\/styles/ ], + use: [ + cssFileLoader, + { + loader: 'css-loader', + options: { + importLoaders: 1, + } + }, + 'postcss-loader' + ] + }, + + { + test: /\.svg$/, + use: ['@svgr/webpack'], + }, + + { + test: /\.js$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: [ + [ '@babel/preset-env', { // probably, use dynamic imports for polifills in future + "targets": "> 4%, not dead", + useBuiltIns: 'entry', + corejs: 3 + }], + '@babel/preset-react', + "@babel/preset-flow", + ], + plugins: [ + "@babel/plugin-syntax-bigint", + [ '@babel/plugin-proposal-decorators', { legacy: true } ], + [ '@babel/plugin-proposal-class-properties', { loose: true }], + [ '@babel/plugin-proposal-private-methods', { loose: true }], + // 'recharts' + ] + } + }, + } + ] + }, + resolve: { alias }, + mode: env.PRODUCTION ? 'production' : 'development', + optimization: { + splitChunks: { + chunks: 'all', + }, + }, + devServer: { + contentBase: path.join(__dirname, DIST_DIR), + //compress: true, + port: 3333, + historyApiFallback: true, + }, + stats: 'errors-only', + devtool: env.SOURCEMAP && 'source-map' + }; +}