From 461f98bbfc5eceb3a2fc005fb1b7d4cea25747db Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 14 Jul 2020 10:02:33 -0300 Subject: [PATCH 01/49] Update Ace Editor version (#5041) --- .../app/components/queries/QueryEditor/ace.js | 18 ++++++------- package-lock.json | 26 +++++++++---------- package.json | 4 +-- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/client/app/components/queries/QueryEditor/ace.js b/client/app/components/queries/QueryEditor/ace.js index b4c4689942..5e405a0a91 100644 --- a/client/app/components/queries/QueryEditor/ace.js +++ b/client/app/components/queries/QueryEditor/ace.js @@ -1,14 +1,14 @@ import { isNil, map } from "lodash"; import AceEditor from "react-ace"; -import ace from "brace"; +import ace from "ace-builds"; -import "brace/ext/language_tools"; -import "brace/mode/json"; -import "brace/mode/python"; -import "brace/mode/sql"; -import "brace/mode/yaml"; -import "brace/theme/textmate"; -import "brace/ext/searchbox"; +import "ace-builds/src-noconflict/ext-language_tools"; +import "ace-builds/src-noconflict/mode-json"; +import "ace-builds/src-noconflict/mode-python"; +import "ace-builds/src-noconflict/mode-sql"; +import "ace-builds/src-noconflict/mode-yaml"; +import "ace-builds/src-noconflict/theme-textmate"; +import "ace-builds/src-noconflict/ext-searchbox"; const langTools = ace.acequire("ace/ext/language_tools"); const snippetsModule = ace.acequire("ace/snippets"); @@ -31,12 +31,10 @@ function buildTableColumnKeywords(table) { const keywords = []; table.columns.forEach(column => { keywords.push({ - caption: column, name: `${table.name}.${column}`, value: `${table.name}.${column}`, score: 100, meta: "Column", - className: "completion", }); }); return keywords; diff --git a/package-lock.json b/package-lock.json index 45566abcc0..e9bae49195 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1516,6 +1516,11 @@ "negotiator": "0.6.1" } }, + "ace-builds": { + "version": "1.4.12", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.12.tgz", + "integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg==" + }, "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", @@ -2678,11 +2683,6 @@ "typedarray-pool": "^1.1.0" } }, - "brace": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz", - "integrity": "sha1-SJb8ydVE7vRfS7dmDbMg07N5/lg=" - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4571,9 +4571,9 @@ "dev": true }, "diff-match-patch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz", - "integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" }, "diff-sequences": { "version": "24.0.0", @@ -13701,15 +13701,15 @@ } }, "react-ace": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-6.4.0.tgz", - "integrity": "sha512-woTTgGk9x4GRRWiM4QLNOspjaJAYLX3UZ3J2XRYQvJiN6wyxrFY9x7rdOKc+4Tj+khb/ccPiDj/kll4UeJEDPw==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-9.1.1.tgz", + "integrity": "sha512-dL0w6GwtnS1opsOoWhJaF7rF7xCM+NOEOfePmDfiaeU+EyZQ6nRWDBgyzKsuiB3hyXH3G9D6FX37ur/LKUdKjA==", "requires": { - "brace": "^0.11.1", + "ace-builds": "^1.4.6", "diff-match-patch": "^1.0.4", "lodash.get": "^4.4.2", "lodash.isequal": "^4.5.0", - "prop-types": "^15.6.2" + "prop-types": "^15.7.2" } }, "react-dom": { diff --git a/package.json b/package.json index 9952a28789..de20ef4b8a 100644 --- a/package.json +++ b/package.json @@ -46,10 +46,10 @@ "@types/prop-types": "^15.5.2", "@types/react": "^16.3.13", "@types/react-dom": "^16.0.5", + "ace-builds": "^1.4.12", "antd": "^3.26.17", "axios": "^0.19.0", "bootstrap": "^3.3.7", - "brace": "^0.11.0", "classnames": "^2.2.6", "d3": "^3.5.17", "debug": "^3.1.0", @@ -68,7 +68,7 @@ "prop-types": "^15.6.1", "query-string": "^6.9.0", "react": "^16.8.3", - "react-ace": "^6.1.0", + "react-ace": "^9.1.1", "react-dom": "^16.8.3", "react-grid-layout": "^0.18.2", "react-resizable": "^1.10.1", From 6f9e79c64134d253d2ba264282bfb11fdd650db6 Mon Sep 17 00:00:00 2001 From: Levko Kravets Date: Tue, 14 Jul 2020 21:56:01 +0300 Subject: [PATCH 02/49] getredash/redash#5031 Counter is too large on Query View/Source pages (#5044) --- .../components/dashboards/dashboard-grid.less | 39 ++++++++++++++----- .../src/visualizations/counter/render.less | 1 + 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/client/app/components/dashboards/dashboard-grid.less b/client/app/components/dashboards/dashboard-grid.less index 572edbe933..2461b6aab3 100644 --- a/client/app/components/dashboards/dashboard-grid.less +++ b/client/app/components/dashboards/dashboard-grid.less @@ -113,15 +113,36 @@ overflow: hidden; } - .counter-visualization-content { - position: absolute; - left: 10px; - top: 15px; - right: 10px; - bottom: 15px; - height: auto; - overflow: hidden; - padding: 0; + .counter-visualization-container { + height: 100%; + + .counter-visualization-content { + position: absolute; + left: 10px; + top: 15px; + right: 10px; + bottom: 15px; + height: auto; + overflow: hidden; + padding: 0; + } + } +} + +.query-fixed-layout { + .visualization-renderer > .visualization-renderer-wrapper { + .counter-visualization-container { + // counter is too large on Query pages, so let's add some constraints + max-width: 600px; + max-height: 400px; + // center it + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + margin: auto; + } } } diff --git a/viz-lib/src/visualizations/counter/render.less b/viz-lib/src/visualizations/counter/render.less index 252d0c0242..db19ccb723 100755 --- a/viz-lib/src/visualizations/counter/render.less +++ b/viz-lib/src/visualizations/counter/render.less @@ -3,6 +3,7 @@ text-align: center; padding: 15px 10px; overflow: hidden; + position: relative; .counter-visualization-content { margin: 0; From d12691dc2a870049ffa714c78a56a655c1da608e Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 15 Jul 2020 11:35:59 -0300 Subject: [PATCH 03/49] Databricks Schema Browser: Allow eventlet worker instead of RQ (#5045) * Add loading button in UI * Handle databricks schema requests without RQ * Don't use gevent worker * Revert "Don't use gevent worker" This reverts commit 9704c70a941a68c249db73e0450961e608fc0507. * Use eventlet * Use first column instead of 'namespace' one * Revert "Add loading button in UI" This reverts commit c0e4dfb966714a9f9e23977ab659e64afb5ce255. * Remove databricks tasks * Update eventlet * Add libevent * Display logs on failure * Revert "Add libevent" This reverts commit a00d067cb77b6f4f9919cf47f1d15c34d107a18c. * Test updating gunicorn * Don't set eventlet as the default for Redash Co-authored-by: Arik Fraimovich * Remove fetchDataFromJob usage Co-authored-by: Arik Fraimovich --- .circleci/config.yml | 5 ++++ bin/docker-entrypoint | 1 - client/app/services/databricks-data-source.js | 26 ++++++++++++------- redash/handlers/databricks.py | 13 ++++++---- redash/query_runner/databricks.py | 3 ++- redash/tasks/databricks.py | 22 ---------------- requirements.txt | 3 ++- 7 files changed, 33 insertions(+), 40 deletions(-) delete mode 100644 redash/tasks/databricks.py diff --git a/.circleci/config.yml b/.circleci/config.yml index a18c644cb2..3b3a61e1ae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -108,6 +108,11 @@ jobs: - run: name: Execute Cypress tests command: npm run cypress run-ci + - run: + name: "Failure: output container logs to console" + command: | + docker-compose logs + when: on_fail build-docker-image: *build-docker-image-job build-preview-docker-image: *build-docker-image-job workflows: diff --git a/bin/docker-entrypoint b/bin/docker-entrypoint index eb112c8412..f54dd20643 100755 --- a/bin/docker-entrypoint +++ b/bin/docker-entrypoint @@ -126,4 +126,3 @@ case "$1" in exec "$@" ;; esac - diff --git a/client/app/services/databricks-data-source.js b/client/app/services/databricks-data-source.js index e12b3e8c26..cd83e4cd8b 100644 --- a/client/app/services/databricks-data-source.js +++ b/client/app/services/databricks-data-source.js @@ -1,16 +1,22 @@ -import { has } from "lodash"; import { axios } from "@/services/axios"; import DataSource from "@/services/data-source"; -import { fetchDataFromJob } from "@/services/query-result"; export default { ...DataSource, - getDatabases: ({ id }) => - axios - .get(`api/databricks/databases/${id}`) - .then(data => (has(data, "job.id") ? fetchDataFromJob(data.job.id, 300).catch(() => []) : Promise.resolve([]))), - getDatabaseTables: (data, databaseName) => - axios - .get(`api/databricks/databases/${data.id}/${databaseName}/tables`) - .then(data => (has(data, "job.id") ? fetchDataFromJob(data.job.id, 300).catch(() => []) : Promise.resolve([]))), + getDatabases: ({ id }, refresh = false) => { + const params = {}; + + if (refresh) { + params.refresh = true; + } + return axios.get(`api/databricks/databases/${id}`, { params }); + }, + getDatabaseTables: (data, databaseName, refresh = false) => { + const params = {}; + + if (refresh) { + params.refresh = true; + } + return axios.get(`api/databricks/databases/${data.id}/${databaseName}/tables`, { params }); + }, }; diff --git a/redash/handlers/databricks.py b/redash/handlers/databricks.py index e5743115c2..1e056afc45 100644 --- a/redash/handlers/databricks.py +++ b/redash/handlers/databricks.py @@ -5,7 +5,6 @@ require_access, view_only, ) -from redash.tasks.databricks import get_databricks_databases, get_databricks_schema from redash.serializers import serialize_job @@ -21,8 +20,10 @@ def get(self, data_source_id): 400, message="Resource only available for the Databricks query runner." ) - job = get_databricks_databases.delay(data_source.id) - return serialize_job(job) + try: + return data_source.query_runner.get_databases() + except Exception: + return {"error": {"code": 2, "message": "Error retrieving schema."}} class DatabricksSchemaResource(BaseResource): @@ -37,5 +38,7 @@ def get(self, data_source_id, database_name): 400, message="Resource only available for the Databricks query runner." ) - job = get_databricks_schema.delay(data_source.id, database_name) - return serialize_job(job) + try: + return data_source.query_runner.get_database_schema(database_name) + except Exception: + return {"error": {"code": 2, "message": "Error retrieving schema."}} diff --git a/redash/query_runner/databricks.py b/redash/query_runner/databricks.py index 14ce2abb19..613d2768d2 100644 --- a/redash/query_runner/databricks.py +++ b/redash/query_runner/databricks.py @@ -141,7 +141,8 @@ def get_databases(self): results = json_loads(results) - return [row["namespace"] for row in results["rows"]] + first_column_name = results["columns"][0]["name"] + return [row[first_column_name] for row in results["rows"]] def get_database_schema(self, database_name): schema = {} diff --git a/redash/tasks/databricks.py b/redash/tasks/databricks.py deleted file mode 100644 index 53e68d01f5..0000000000 --- a/redash/tasks/databricks.py +++ /dev/null @@ -1,22 +0,0 @@ -from rq.registry import FailedJobRegistry -from redash import models -from redash.worker import job -from redash.tasks.worker import Queue - - -@job("schemas", queue_class=Queue, at_front=True, timeout=300, ttl=90) -def get_databricks_databases(data_source_id): - try: - data_source = models.DataSource.get_by_id(data_source_id) - return data_source.query_runner.get_databases() - except Exception: - return {"error": {"code": 2, "message": "Error retrieving schema."}} - - -@job("schemas", queue_class=Queue, at_front=True, timeout=300, ttl=90) -def get_databricks_schema(data_source_id, database_name): - try: - data_source = models.DataSource.get_by_id(data_source_id) - return data_source.query_runner.get_database_schema(database_name) - except Exception: - return {"error": {"code": 2, "message": "Error retrieving schema."}} diff --git a/requirements.txt b/requirements.txt index 8fd7c04093..049fc305dd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,7 +33,7 @@ pyparsing==2.3.0 SQLAlchemy-Utils==0.34.2 sqlparse==0.3.0 statsd==3.3.0 -gunicorn==19.9.0 +gunicorn==20.0.4 rq==1.1.0 rq-scheduler==0.9.1 jsonschema==3.1.1 @@ -55,6 +55,7 @@ maxminddb-geolite2==2018.703 pypd==1.1.0 disposable-email-domains>=0.0.52 gevent==1.4.0 +eventlet==0.25.2 sshtunnel==0.1.5 supervisor==4.1.0 supervisor_checks==0.8.1 From cb97364771632672ac80915454b09df6362af269 Mon Sep 17 00:00:00 2001 From: Omer Lachish Date: Thu, 16 Jul 2020 23:03:59 +0300 Subject: [PATCH 04/49] Dashboard URL does not show new name when dashboard name is updated (#1009) * on dashboard api calls - take the id from the beginning of the slug, unless there is no number in it - in that case, take the entire slug as id * add dashboard id when showing links to dashboards * change path to include new name when renaming dashboards * move slug generation to backend * redirect to new name after changing (this time with a proper promise) * oh right, we already have a slug function * add spec that makes sure that renamed dashboards are redirected to the url which contains their new name * use id-slug in all Cypress specs * move dashboards from /dashboard/:slug to /dashboards/:id-:name_as_slug * Update dashboard url as its name changes * Update separator to be "/" * Update missing dashboard urls * Update api not to depend on int id * Use '-' instead of '/' as separator and update Dashboard.get calls * slug -> name_as_slug * Keep slug urls on cypress * Update route path * Use legacy attr for GET * Use getter for urlForDashboard * Update dashboard url when loaded by slug * Update Dashboard routes to use id instead of slug * Update Dashboard handler tests * Update Cypress tests * Fix create new dashboard spec * Use axios { params } * Drop Ternary operator * Send updated slug directly in 'slug' attr * Update multiple urls Dashboard test name * Update route names Co-authored-by: Levko Kravets Co-authored-by: Gabriel Dutra Co-authored-by: Levko Kravets --- .../dashboards/CreateDashboardDialog.jsx | 6 +-- .../queries/AddToDashboardDialog.jsx | 4 +- client/app/pages/dashboards/DashboardList.jsx | 2 +- client/app/pages/dashboards/DashboardPage.jsx | 31 +++++++++++++--- .../pages/dashboards/hooks/useDashboard.js | 13 ++++--- client/app/pages/home/Home.jsx | 2 +- client/app/services/dashboard.js | 23 +++++++++--- .../integration/dashboard/dashboard_spec.js | 37 +++++++++++++------ .../dashboard/dashboard_tags_spec.js | 2 +- .../integration/dashboard/filters_spec.js | 2 +- .../dashboard/grid_compliant_widgets_spec.js | 4 +- .../dashboard/parameter_mapping_spec.js | 4 +- .../integration/dashboard/sharing_spec.js | 4 +- .../integration/dashboard/textbox_spec.js | 4 +- .../integration/dashboard/widget_spec.js | 4 +- .../integration/visualizations/pivot_spec.js | 2 +- .../visualizations/sankey_sunburst_spec.js | 4 +- redash/handlers/api.py | 2 +- redash/handlers/dashboards.py | 27 +++++++------- redash/handlers/favorites.py | 4 +- redash/models/__init__.py | 6 ++- redash/serializers/__init__.py | 2 +- tests/handlers/test_dashboards.py | 20 +++++++--- 23 files changed, 137 insertions(+), 72 deletions(-) diff --git a/client/app/components/dashboards/CreateDashboardDialog.jsx b/client/app/components/dashboards/CreateDashboardDialog.jsx index 0993e89721..cb6bb8caa9 100644 --- a/client/app/components/dashboards/CreateDashboardDialog.jsx +++ b/client/app/components/dashboards/CreateDashboardDialog.jsx @@ -1,6 +1,5 @@ import { trim } from "lodash"; import React, { useState } from "react"; -import { axios } from "@/services/axios"; import Modal from "antd/lib/modal"; import Input from "antd/lib/input"; import DynamicComponent from "@/components/DynamicComponent"; @@ -8,6 +7,7 @@ import { wrap as wrapDialog, DialogPropType } from "@/components/DialogWrapper"; import navigateTo from "@/components/ApplicationArea/navigateTo"; import recordEvent from "@/services/recordEvent"; import { policy } from "@/services/policy"; +import { Dashboard } from "@/services/dashboard"; function CreateDashboardDialog({ dialog }) { const [name, setName] = useState(""); @@ -25,9 +25,9 @@ function CreateDashboardDialog({ dialog }) { if (name !== "") { setSaveInProgress(true); - axios.post("api/dashboards", { name }).then(data => { + Dashboard.save({ name }).then(data => { dialog.close(); - navigateTo(`dashboard/${data.slug}?edit`); + navigateTo(`${data.url}?edit`); }); recordEvent("create", "dashboard"); } diff --git a/client/app/components/queries/AddToDashboardDialog.jsx b/client/app/components/queries/AddToDashboardDialog.jsx index 48e9139811..4510ee4170 100644 --- a/client/app/components/queries/AddToDashboardDialog.jsx +++ b/client/app/components/queries/AddToDashboardDialog.jsx @@ -38,7 +38,7 @@ function AddToDashboardDialog({ dialog, visualization }) { function addWidgetToDashboard() { // Load dashboard with all widgets - Dashboard.get({ slug: selectedDashboard.slug }) + Dashboard.get(selectedDashboard) .then(dashboard => { dashboard.addWidget(visualization); return dashboard; @@ -51,7 +51,7 @@ function AddToDashboardDialog({ dialog, visualization }) { notification.success( "Widget added to dashboard", - notification.close(key)}> + notification.close(key)}> {dashboard.name} diff --git a/client/app/pages/dashboards/DashboardList.jsx b/client/app/pages/dashboards/DashboardList.jsx index 153429c8cf..a3f0d0d5dd 100644 --- a/client/app/pages/dashboards/DashboardList.jsx +++ b/client/app/pages/dashboards/DashboardList.jsx @@ -46,7 +46,7 @@ class DashboardList extends React.Component { Columns.custom.sortable( (text, item) => ( - + {item.name} +
{!isEmpty(globalParameters) && (
@@ -145,35 +147,52 @@ DashboardComponent.propTypes = { dashboard: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types }; -function DashboardPage({ dashboardSlug, onError }) { +function DashboardPage({ dashboardSlug, dashboardId, onError }) { const [dashboard, setDashboard] = useState(null); const handleError = useImmutableCallback(onError); useEffect(() => { - Dashboard.get({ slug: dashboardSlug }) + Dashboard.get({ id: dashboardId, slug: dashboardSlug }) .then(dashboardData => { recordEvent("view", "dashboard", dashboardData.id); setDashboard(dashboardData); + + // if loaded by slug, update location url to use the id + if (!dashboardId) { + location.setPath(url.parse(dashboardData.url).pathname, true); + } }) .catch(handleError); - }, [dashboardSlug, handleError]); + }, [dashboardId, dashboardSlug, handleError]); return
{dashboard && }
; } DashboardPage.propTypes = { - dashboardSlug: PropTypes.string.isRequired, + dashboardSlug: PropTypes.string, + dashboardId: PropTypes.string, onError: PropTypes.func, }; DashboardPage.defaultProps = { + dashboardSlug: null, + dashboardId: null, onError: PropTypes.func, }; +// route kept for backward compatibility routes.register( - "Dashboards.ViewOrEdit", + "Dashboards.LegacyViewOrEdit", routeWithUserSession({ path: "/dashboard/:dashboardSlug", render: pageProps => , }) ); + +routes.register( + "Dashboards.ViewOrEdit", + routeWithUserSession({ + path: "/dashboards/:dashboardId([^-]+)(-.*)?", + render: pageProps => , + }) +); diff --git a/client/app/pages/dashboards/hooks/useDashboard.js b/client/app/pages/dashboards/hooks/useDashboard.js index 3fd9d8da85..07614ff68c 100644 --- a/client/app/pages/dashboards/hooks/useDashboard.js +++ b/client/app/pages/dashboards/hooks/useDashboard.js @@ -2,6 +2,7 @@ import { useState, useEffect, useMemo, useCallback, useRef } from "react"; import { isEmpty, includes, compact, map, has, pick, keys, extend, every, get } from "lodash"; import notification from "@/services/notification"; import location from "@/services/location"; +import url from "@/services/url"; import { Dashboard, collectDashboardFilters } from "@/services/dashboard"; import { currentUser } from "@/services/auth"; import recordEvent from "@/services/recordEvent"; @@ -63,15 +64,17 @@ function useDashboard(dashboardData) { const updateDashboard = useCallback( (data, includeVersion = true) => { setDashboard(currentDashboard => extend({}, currentDashboard, data)); - // for some reason the request uses the id as slug - data = { ...data, slug: dashboard.id }; + data = { ...data, id: dashboard.id }; if (includeVersion) { data = { ...data, version: dashboard.version }; } return Dashboard.save(data) - .then(updatedDashboard => - setDashboard(currentDashboard => extend({}, currentDashboard, pick(updatedDashboard, keys(data)))) - ) + .then(updatedDashboard => { + setDashboard(currentDashboard => extend({}, currentDashboard, pick(updatedDashboard, keys(data)))); + if (has(data, "name")) { + location.setPath(url.parse(updatedDashboard.url).pathname, true); + } + }) .catch(error => { const status = get(error, "response.status"); if (status === 403) { diff --git a/client/app/pages/home/Home.jsx b/client/app/pages/home/Home.jsx index 68c7e9e26b..4fbd14b4dc 100644 --- a/client/app/pages/home/Home.jsx +++ b/client/app/pages/home/Home.jsx @@ -119,7 +119,7 @@ function DashboardAndQueryFavoritesList() { `dashboard/${dashboard.slug}`} + itemUrl={dashboard => dashboard.url} emptyState={

diff --git a/client/app/services/dashboard.js b/client/app/services/dashboard.js index f347048ca0..d2f1806fa6 100644 --- a/client/app/services/dashboard.js +++ b/client/app/services/dashboard.js @@ -6,6 +6,8 @@ import { currentUser } from "@/services/auth"; import location from "@/services/location"; import { cloneParameter } from "@/services/parameters"; +export const urlForDashboard = ({ id, slug }) => `dashboards/${id}-${slug}`; + export function collectDashboardFilters(dashboard, queryResults, urlParams) { const filters = {}; _.each(queryResults, queryResult => { @@ -123,6 +125,11 @@ function calculateNewWidgetPosition(existingWidgets, newWidget) { export function Dashboard(dashboard) { _.extend(this, dashboard); + Object.defineProperty(this, "url", { + get: function() { + return urlForDashboard(this); + }, + }); } function prepareDashboardWidgets(widgets) { @@ -147,17 +154,23 @@ function transformResponse(data) { return data; } -const saveOrCreateUrl = data => (data.slug ? `api/dashboards/${data.slug}` : "api/dashboards"); +const saveOrCreateUrl = data => (data.id ? `api/dashboards/${data.id}` : "api/dashboards"); const DashboardService = { - get: ({ slug }) => axios.get(`api/dashboards/${slug}`).then(transformResponse), + get: ({ id, slug }) => { + const params = {}; + if (!id) { + params.legacy = null; + } + return axios.get(`api/dashboards/${id || slug}`, { params }).then(transformResponse); + }, getByToken: ({ token }) => axios.get(`api/dashboards/public/${token}`).then(transformResponse), save: data => axios.post(saveOrCreateUrl(data), data).then(transformResponse), - delete: ({ slug }) => axios.delete(`api/dashboards/${slug}`).then(transformResponse), + delete: ({ id }) => axios.delete(`api/dashboards/${id}`).then(transformResponse), query: params => axios.get("api/dashboards", { params }).then(transformResponse), recent: params => axios.get("api/dashboards/recent", { params }).then(transformResponse), favorites: params => axios.get("api/dashboards/favorites", { params }).then(transformResponse), - favorite: ({ slug }) => axios.post(`api/dashboards/${slug}/favorite`), - unfavorite: ({ slug }) => axios.delete(`api/dashboards/${slug}/favorite`), + favorite: ({ id }) => axios.post(`api/dashboards/${id}/favorite`), + unfavorite: ({ id }) => axios.delete(`api/dashboards/${id}/favorite`), }; _.extend(Dashboard, DashboardService); diff --git a/client/cypress/integration/dashboard/dashboard_spec.js b/client/cypress/integration/dashboard/dashboard_spec.js index 489a07ea5f..2410c51a1a 100644 --- a/client/cypress/integration/dashboard/dashboard_spec.js +++ b/client/cypress/integration/dashboard/dashboard_spec.js @@ -25,19 +25,19 @@ describe("Dashboard", () => { }); cy.wait("@NewDashboard").then(xhr => { - const slug = Cypress._.get(xhr, "response.body.slug"); - assert.isDefined(slug, "Dashboard api call returns slug"); + const id = Cypress._.get(xhr, "response.body.id"); + assert.isDefined(id, "Dashboard api call returns id"); cy.visit("/dashboards"); cy.getByTestId("DashboardLayoutContent").within(() => { - cy.getByTestId(slug).should("exist"); + cy.getByTestId(`DashboardId${id}`).should("exist"); }); }); }); it("archives dashboard", () => { - createDashboard("Foo Bar").then(({ slug }) => { - cy.visit(`/dashboard/${slug}`); + createDashboard("Foo Bar").then(({ id }) => { + cy.visit(`/dashboards/${id}`); cy.getByTestId("DashboardMoreButton").click(); @@ -52,7 +52,22 @@ describe("Dashboard", () => { cy.visit("/dashboards"); cy.getByTestId("DashboardLayoutContent").within(() => { - cy.getByTestId(slug).should("not.exist"); + cy.getByTestId(`DashboardId${id}`).should("not.exist"); + }); + }); + }); + + it("is accessible through multiple urls", () => { + cy.server(); + cy.route("GET", "api/dashboards/*").as("LoadDashboard"); + createDashboard("Dashboard multiple urls").then(({ id, slug }) => { + [`/dashboards/${id}`, `/dashboards/${id}-anything-here`, `/dashboard/${slug}`].forEach(url => { + cy.visit(url); + cy.wait("@LoadDashboard"); + cy.getByTestId(`DashboardId${id}Container`).should("exist"); + + // assert it always use the "/dashboards/{id}" path + cy.location("pathname").should("contain", `/dashboards/${id}`); }); }); }); @@ -61,9 +76,9 @@ describe("Dashboard", () => { before(function() { cy.login(); createDashboard("Foo Bar") - .then(({ slug, id }) => { - this.dashboardUrl = `/dashboard/${slug}`; - this.dashboardEditUrl = `/dashboard/${slug}?edit`; + .then(({ id }) => { + this.dashboardUrl = `/dashboards/${id}`; + this.dashboardEditUrl = `/dashboards/${id}?edit`; return addTextbox(id, "Hello World!").then(getWidgetTestId); }) .then(elTestId => { @@ -117,8 +132,8 @@ describe("Dashboard", () => { context("viewport width is at 767px", () => { before(function() { cy.login(); - createDashboard("Foo Bar").then(({ slug }) => { - this.dashboardUrl = `/dashboard/${slug}`; + createDashboard("Foo Bar").then(({ id }) => { + this.dashboardUrl = `/dashboards/${id}`; }); }); diff --git a/client/cypress/integration/dashboard/dashboard_tags_spec.js b/client/cypress/integration/dashboard/dashboard_tags_spec.js index 9d8ef131ae..c7dd91e649 100644 --- a/client/cypress/integration/dashboard/dashboard_tags_spec.js +++ b/client/cypress/integration/dashboard/dashboard_tags_spec.js @@ -4,7 +4,7 @@ import { expectTagsToContain, typeInTagsSelectAndSave } from "../../support/tags describe("Dashboard Tags", () => { beforeEach(function() { cy.login(); - createDashboard("Foo Bar").then(({ slug }) => cy.visit(`/dashboard/${slug}`)); + createDashboard("Foo Bar").then(({ id }) => cy.visit(`/dashboards/${id}`)); }); it("is possible to add and edit tags", () => { diff --git a/client/cypress/integration/dashboard/filters_spec.js b/client/cypress/integration/dashboard/filters_spec.js index 47091c600a..b05b8c3e6c 100644 --- a/client/cypress/integration/dashboard/filters_spec.js +++ b/client/cypress/integration/dashboard/filters_spec.js @@ -29,7 +29,7 @@ describe("Dashboard Filters", () => { .as("widget1TestId") .then(() => createQueryAndAddWidget(dashboard.id, queryData, { position: { col: 4 } })) .as("widget2TestId") - .then(() => cy.visit(`/dashboard/${dashboard.slug}`)); + .then(() => cy.visit(`/dashboards/${dashboard.id}`)); }); }); diff --git a/client/cypress/integration/dashboard/grid_compliant_widgets_spec.js b/client/cypress/integration/dashboard/grid_compliant_widgets_spec.js index 31a7361979..27fcdbafb5 100644 --- a/client/cypress/integration/dashboard/grid_compliant_widgets_spec.js +++ b/client/cypress/integration/dashboard/grid_compliant_widgets_spec.js @@ -10,8 +10,8 @@ describe("Grid compliant widgets", () => { cy.login(); cy.viewport(1215 + menuWidth, 800); createDashboard("Foo Bar") - .then(({ slug, id }) => { - this.dashboardUrl = `/dashboard/${slug}`; + .then(({ id }) => { + this.dashboardUrl = `/dashboards/${id}`; return addTextbox(id, "Hello World!").then(getWidgetTestId); }) .then(elTestId => { diff --git a/client/cypress/integration/dashboard/parameter_mapping_spec.js b/client/cypress/integration/dashboard/parameter_mapping_spec.js index 04dc58a439..4223f35dff 100644 --- a/client/cypress/integration/dashboard/parameter_mapping_spec.js +++ b/client/cypress/integration/dashboard/parameter_mapping_spec.js @@ -5,9 +5,9 @@ describe("Parameter Mapping", () => { beforeEach(function() { cy.login(); createDashboard("Foo Bar") - .then(({ slug, id }) => { + .then(({ id }) => { this.dashboardId = id; - this.dashboardUrl = `/dashboard/${slug}`; + this.dashboardUrl = `/dashboards/${id}`; }) .then(() => { const queryData = { diff --git a/client/cypress/integration/dashboard/sharing_spec.js b/client/cypress/integration/dashboard/sharing_spec.js index adba653603..4c7369dc4a 100644 --- a/client/cypress/integration/dashboard/sharing_spec.js +++ b/client/cypress/integration/dashboard/sharing_spec.js @@ -6,9 +6,9 @@ import { editDashboard, shareDashboard, createQueryAndAddWidget } from "../../su describe("Dashboard Sharing", () => { beforeEach(function() { cy.login(); - createDashboard("Foo Bar").then(({ slug, id }) => { + createDashboard("Foo Bar").then(({ id }) => { this.dashboardId = id; - this.dashboardUrl = `/dashboard/${slug}`; + this.dashboardUrl = `/dashboards/${id}`; }); }); diff --git a/client/cypress/integration/dashboard/textbox_spec.js b/client/cypress/integration/dashboard/textbox_spec.js index 7e5beffa54..3e4c7910a8 100644 --- a/client/cypress/integration/dashboard/textbox_spec.js +++ b/client/cypress/integration/dashboard/textbox_spec.js @@ -6,9 +6,9 @@ import { getWidgetTestId, editDashboard } from "../../support/dashboard"; describe("Textbox", () => { beforeEach(function() { cy.login(); - createDashboard("Foo Bar").then(({ slug, id }) => { + createDashboard("Foo Bar").then(({ id }) => { this.dashboardId = id; - this.dashboardUrl = `/dashboard/${slug}`; + this.dashboardUrl = `/dashboards/${id}`; }); }); diff --git a/client/cypress/integration/dashboard/widget_spec.js b/client/cypress/integration/dashboard/widget_spec.js index 2eff9e4f21..60501f2ab7 100644 --- a/client/cypress/integration/dashboard/widget_spec.js +++ b/client/cypress/integration/dashboard/widget_spec.js @@ -6,9 +6,9 @@ import { createQueryAndAddWidget, editDashboard, resizeBy } from "../../support/ describe("Widget", () => { beforeEach(function() { cy.login(); - createDashboard("Foo Bar").then(({ slug, id }) => { + createDashboard("Foo Bar").then(({ id }) => { this.dashboardId = id; - this.dashboardUrl = `/dashboard/${slug}`; + this.dashboardUrl = `/dashboards/${id}`; }); }); diff --git a/client/cypress/integration/visualizations/pivot_spec.js b/client/cypress/integration/visualizations/pivot_spec.js index 54d4cf53ab..1e2f153ce3 100644 --- a/client/cypress/integration/visualizations/pivot_spec.js +++ b/client/cypress/integration/visualizations/pivot_spec.js @@ -143,7 +143,7 @@ describe("Pivot", () => { createDashboard("Pivot Visualization") .then(dashboard => { - this.dashboardUrl = `/dashboard/${dashboard.slug}`; + this.dashboardUrl = `/dashboards/${dashboard.id}`; return cy.all( pivotTables.map(pivot => () => createVisualization(this.queryId, "PIVOT", pivot.name, pivot.options).then(visualization => diff --git a/client/cypress/integration/visualizations/sankey_sunburst_spec.js b/client/cypress/integration/visualizations/sankey_sunburst_spec.js index 5bb8eda9e9..190b7c96c2 100644 --- a/client/cypress/integration/visualizations/sankey_sunburst_spec.js +++ b/client/cypress/integration/visualizations/sankey_sunburst_spec.js @@ -99,7 +99,7 @@ describe("Sankey and Sunburst", () => { it("takes a snapshot with Sunburst (1 - 5 stages)", function() { createDashboard("Sunburst Visualization").then(dashboard => { - this.dashboardUrl = `/dashboard/${dashboard.slug}`; + this.dashboardUrl = `/dashboards/${dashboard.id}`; return cy .all( STAGES_WIDGETS.map(sunburst => () => @@ -123,7 +123,7 @@ describe("Sankey and Sunburst", () => { it("takes a snapshot with Sankey (1 - 5 stages)", function() { createDashboard("Sankey Visualization").then(dashboard => { - this.dashboardUrl = `/dashboard/${dashboard.slug}`; + this.dashboardUrl = `/dashboards/${dashboard.id}`; return cy .all( STAGES_WIDGETS.map(sankey => () => diff --git a/redash/handlers/api.py b/redash/handlers/api.py index 8f7cc1a369..1292d63100 100644 --- a/redash/handlers/api.py +++ b/redash/handlers/api.py @@ -127,7 +127,7 @@ def json_representation(data, code, headers=None): api.add_org_resource(DashboardListResource, "/api/dashboards", endpoint="dashboards") api.add_org_resource( - DashboardResource, "/api/dashboards/", endpoint="dashboard" + DashboardResource, "/api/dashboards/", endpoint="dashboard" ) api.add_org_resource( PublicDashboardResource, diff --git a/redash/handlers/dashboards.py b/redash/handlers/dashboards.py index 1575fe2e28..cfc710930f 100644 --- a/redash/handlers/dashboards.py +++ b/redash/handlers/dashboards.py @@ -115,11 +115,11 @@ def post(self): class DashboardResource(BaseResource): @require_permission("list_dashboards") - def get(self, dashboard_slug=None): + def get(self, dashboard_id=None): """ Retrieves a dashboard. - :qparam string slug: Slug of dashboard to retrieve. + :qparam number id: Id of dashboard to retrieve. .. _dashboard-response-label: @@ -149,9 +149,12 @@ def get(self, dashboard_slug=None): :>json string widget.created_at: ISO format timestamp for widget creation :>json string widget.updated_at: ISO format timestamp for last widget modification """ - dashboard = get_object_or_404( - models.Dashboard.get_by_slug_and_org, dashboard_slug, self.current_org - ) + if request.args.get("legacy") is not None: + fn = models.Dashboard.get_by_slug_and_org + else: + fn = models.Dashboard.get_by_id_and_org + + dashboard = get_object_or_404(fn, dashboard_id, self.current_org) response = DashboardSerializer( dashboard, with_widgets=True, user=self.current_user ).serialize() @@ -175,11 +178,11 @@ def get(self, dashboard_slug=None): return response @require_permission("edit_dashboard") - def post(self, dashboard_slug): + def post(self, dashboard_id): """ Modifies a dashboard. - :qparam string slug: Slug of dashboard to retrieve. + :qparam number id: Id of dashboard to retrieve. Responds with the updated :ref:`dashboard `. @@ -188,7 +191,7 @@ def post(self, dashboard_slug): """ dashboard_properties = request.get_json(force=True) # TODO: either convert all requests to use slugs or ids - dashboard = models.Dashboard.get_by_id_and_org(dashboard_slug, self.current_org) + dashboard = models.Dashboard.get_by_id_and_org(dashboard_id, self.current_org) require_object_modify_permission(dashboard, self.current_user) @@ -231,17 +234,15 @@ def post(self, dashboard_slug): return result @require_permission("edit_dashboard") - def delete(self, dashboard_slug): + def delete(self, dashboard_id): """ Archives a dashboard. - :qparam string slug: Slug of dashboard to retrieve. + :qparam number id: Id of dashboard to retrieve. Responds with the archived :ref:`dashboard `. """ - dashboard = models.Dashboard.get_by_slug_and_org( - dashboard_slug, self.current_org - ) + dashboard = models.Dashboard.get_by_id_and_org(dashboard_id, self.current_org) dashboard.is_archived = True dashboard.record_changes(changed_by=self.current_user) models.db.session.add(dashboard) diff --git a/redash/handlers/favorites.py b/redash/handlers/favorites.py index 71ac3a20b8..71a0ac3db1 100644 --- a/redash/handlers/favorites.py +++ b/redash/handlers/favorites.py @@ -51,7 +51,7 @@ def delete(self, query_id): class DashboardFavoriteResource(BaseResource): def post(self, object_id): dashboard = get_object_or_404( - models.Dashboard.get_by_slug_and_org, object_id, self.current_org + models.Dashboard.get_by_id_and_org, object_id, self.current_org ) fav = models.Favorite( org_id=self.current_org.id, object=dashboard, user=self.current_user @@ -76,7 +76,7 @@ def post(self, object_id): def delete(self, object_id): dashboard = get_object_or_404( - models.Dashboard.get_by_slug_and_org, object_id, self.current_org + models.Dashboard.get_by_id_and_org, object_id, self.current_org ) models.Favorite.query.filter( models.Favorite.object == dashboard, diff --git a/redash/models/__init__.py b/redash/models/__init__.py index 1bd2fab77f..4e7b97cb90 100644 --- a/redash/models/__init__.py +++ b/redash/models/__init__.py @@ -5,7 +5,7 @@ import numbers import pytz -from sqlalchemy import distinct, or_, and_, UniqueConstraint +from sqlalchemy import distinct, or_, and_, UniqueConstraint, cast from sqlalchemy.dialects import postgresql from sqlalchemy.event import listens_for from sqlalchemy.ext.hybrid import hybrid_property @@ -1099,6 +1099,10 @@ class Dashboard(ChangeTrackingMixin, TimestampMixin, BelongsToOrgMixin, db.Model def __str__(self): return "%s=%s" % (self.id, self.name) + @property + def name_as_slug(self): + return utils.slugify(self.name) + @classmethod def all(cls, org, group_ids, user_id): query = ( diff --git a/redash/serializers/__init__.py b/redash/serializers/__init__.py index b82c1b9f17..83b1fa266b 100644 --- a/redash/serializers/__init__.py +++ b/redash/serializers/__init__.py @@ -245,7 +245,7 @@ def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state= d = { "id": obj.id, - "slug": obj.slug, + "slug": obj.name_as_slug, "name": obj.name, "user_id": obj.user_id, "user": { diff --git a/tests/handlers/test_dashboards.py b/tests/handlers/test_dashboards.py index b60fe627a9..f89e553b4b 100644 --- a/tests/handlers/test_dashboards.py +++ b/tests/handlers/test_dashboards.py @@ -53,7 +53,17 @@ def test_search_term(self): class TestDashboardResourceGet(BaseTestCase): def test_get_dashboard(self): d1 = self.factory.create_dashboard() - rv = self.make_request("get", "/api/dashboards/{0}".format(d1.slug)) + rv = self.make_request("get", "/api/dashboards/{0}".format(d1.id)) + self.assertEqual(rv.status_code, 200) + + expected = serialize_dashboard(d1, with_widgets=True, with_favorite_state=False) + actual = json_loads(rv.data) + + self.assertResponseEqual(expected, actual) + + def test_get_dashboard_with_slug(self): + d1 = self.factory.create_dashboard() + rv = self.make_request("get", "/api/dashboards/{0}?legacy".format(d1.slug)) self.assertEqual(rv.status_code, 200) expected = serialize_dashboard(d1, with_widgets=True, with_favorite_state=False) @@ -76,13 +86,13 @@ def test_get_dashboard_filters_unauthorized_widgets(self): dashboard.layout = "[[{}, {}]]".format(widget.id, restricted_widget.id) db.session.commit() - rv = self.make_request("get", "/api/dashboards/{0}".format(dashboard.slug)) + rv = self.make_request("get", "/api/dashboards/{0}".format(dashboard.id)) self.assertEqual(rv.status_code, 200) self.assertTrue(rv.json["widgets"][0]["restricted"]) self.assertNotIn("restricted", rv.json["widgets"][1]) def test_get_non_existing_dashboard(self): - rv = self.make_request("get", "/api/dashboards/not_existing") + rv = self.make_request("get", "/api/dashboards/-1") self.assertEqual(rv.status_code, 404) @@ -156,10 +166,10 @@ class TestDashboardResourceDelete(BaseTestCase): def test_delete_dashboard(self): d = self.factory.create_dashboard() - rv = self.make_request("delete", "/api/dashboards/{0}".format(d.slug)) + rv = self.make_request("delete", "/api/dashboards/{0}".format(d.id)) self.assertEqual(rv.status_code, 200) - d = Dashboard.get_by_slug_and_org(d.slug, d.org) + d = Dashboard.get_by_id_and_org(d.id, d.org) self.assertTrue(d.is_archived) From 41a691328a9c13e534dc2a3cf9cd557f6286fad7 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Thu, 16 Jul 2020 22:05:22 +0200 Subject: [PATCH 05/49] Fix bundle-extensions script to work on recent importlib-resources. (#5050) Also adds a test case for running the script. --- bin/bundle-extensions | 38 +++++++++---------- tests/extensions/redash-dummy/.gitignore | 2 + tests/extensions/redash-dummy/MANIFEST.in | 2 + .../redash_dummy.egg-info/PKG-INFO | 2 +- .../redash_dummy.egg-info/SOURCES.txt | 8 +++- .../redash_dummy.egg-info/entry_points.txt | 13 ++++--- .../redash-dummy/redash_dummy/__init__.py | 0 .../redash_dummy/bundle/WideFooter.jsx | 9 +++++ .../redash-dummy/redash_dummy/extension.py | 11 ++++++ .../{redash_dummy.py => redash_dummy/jobs.py} | 12 ------ tests/extensions/redash-dummy/setup.py | 20 ++++++---- tests/extensions/test_extensions.py | 34 +++++++++++++++-- 12 files changed, 100 insertions(+), 51 deletions(-) create mode 100644 tests/extensions/redash-dummy/.gitignore create mode 100644 tests/extensions/redash-dummy/MANIFEST.in create mode 100644 tests/extensions/redash-dummy/redash_dummy/__init__.py create mode 100644 tests/extensions/redash-dummy/redash_dummy/bundle/WideFooter.jsx create mode 100644 tests/extensions/redash-dummy/redash_dummy/extension.py rename tests/extensions/redash-dummy/{redash_dummy.py => redash_dummy/jobs.py} (57%) diff --git a/bin/bundle-extensions b/bin/bundle-extensions index a8c1e3cae1..ce0e300854 100755 --- a/bin/bundle-extensions +++ b/bin/bundle-extensions @@ -6,8 +6,8 @@ from pathlib import Path from shutil import copy from collections import OrderedDict as odict -from importlib_metadata import entry_points -from importlib_resources import contents, is_resource, path +import importlib_metadata +import importlib_resources # Name of the subdirectory BUNDLE_DIRECTORY = "bundle" @@ -25,18 +25,6 @@ if not extensions_directory.exists(): os.environ["EXTENSIONS_DIRECTORY"] = str(extensions_relative_path) -def resource_isdir(module, resource): - """Whether a given resource is a directory in the given module - - https://importlib-resources.readthedocs.io/en/latest/migration.html#pkg-resources-resource-isdir - """ - try: - return resource in contents(module) and not is_resource(module, resource) - except (ImportError, TypeError): - # module isn't a package, so can't have a subdirectory/-package - return False - - def entry_point_module(entry_point): """Returns the dotted module path for the given entry point""" return entry_point.pattern.match(entry_point.value).group("module") @@ -77,18 +65,28 @@ def load_bundles(): """ bundles = odict() - for entry_point in entry_points().get("redash.bundles", []): + for entry_point in importlib_metadata.entry_points().get("redash.bundles", []): logger.info('Loading Redash bundle "%s".', entry_point.name) module = entry_point_module(entry_point) # Try to get a list of bundle files - if not resource_isdir(module, BUNDLE_DIRECTORY): + try: + bundle_dir = importlib_resources.files(module).joinpath(BUNDLE_DIRECTORY) + except (ImportError, TypeError): + # Module isn't a package, so can't have a subdirectory/-package logger.error( - 'Redash bundle directory "%s" could not be found.', entry_point.name + 'Redash bundle module "%s" could not be imported: "%s"', + entry_point.name, + module, ) continue - with path(module, BUNDLE_DIRECTORY) as bundle_dir: - bundles[entry_point.name] = list(bundle_dir.rglob("*")) - + if not bundle_dir.is_dir(): + logger.error( + 'Redash bundle directory "%s" could not be found or is not a directory: "%s"', + entry_point.name, + bundle_dir, + ) + continue + bundles[entry_point.name] = list(bundle_dir.rglob("*")) return bundles diff --git a/tests/extensions/redash-dummy/.gitignore b/tests/extensions/redash-dummy/.gitignore new file mode 100644 index 0000000000..1b823a2c19 --- /dev/null +++ b/tests/extensions/redash-dummy/.gitignore @@ -0,0 +1,2 @@ +dist +build diff --git a/tests/extensions/redash-dummy/MANIFEST.in b/tests/extensions/redash-dummy/MANIFEST.in new file mode 100644 index 0000000000..f42f7bd471 --- /dev/null +++ b/tests/extensions/redash-dummy/MANIFEST.in @@ -0,0 +1,2 @@ +include README.md +recursive-include redash_dummy *.jsx diff --git a/tests/extensions/redash-dummy/redash_dummy.egg-info/PKG-INFO b/tests/extensions/redash-dummy/redash_dummy.egg-info/PKG-INFO index bc2dd35d73..5da2ff60c4 100644 --- a/tests/extensions/redash-dummy/redash_dummy.egg-info/PKG-INFO +++ b/tests/extensions/redash-dummy/redash_dummy.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: redash-dummy -Version: 0.1 +Version: 0.2 Summary: Redash extensions for testing Home-page: UNKNOWN Author: Redash authors diff --git a/tests/extensions/redash-dummy/redash_dummy.egg-info/SOURCES.txt b/tests/extensions/redash-dummy/redash_dummy.egg-info/SOURCES.txt index cccc4cf677..8a4946a14d 100644 --- a/tests/extensions/redash-dummy/redash_dummy.egg-info/SOURCES.txt +++ b/tests/extensions/redash-dummy/redash_dummy.egg-info/SOURCES.txt @@ -1,8 +1,12 @@ +MANIFEST.in README.md -redash_dummy.py setup.py +redash_dummy/__init__.py +redash_dummy/extension.py +redash_dummy/jobs.py redash_dummy.egg-info/PKG-INFO redash_dummy.egg-info/SOURCES.txt redash_dummy.egg-info/dependency_links.txt redash_dummy.egg-info/entry_points.txt -redash_dummy.egg-info/top_level.txt \ No newline at end of file +redash_dummy.egg-info/top_level.txt +redash_dummy/bundle/WideFooter.jsx \ No newline at end of file diff --git a/tests/extensions/redash-dummy/redash_dummy.egg-info/entry_points.txt b/tests/extensions/redash-dummy/redash_dummy.egg-info/entry_points.txt index 3baf150ef9..f6b2aed61e 100644 --- a/tests/extensions/redash-dummy/redash_dummy.egg-info/entry_points.txt +++ b/tests/extensions/redash-dummy/redash_dummy.egg-info/entry_points.txt @@ -1,10 +1,13 @@ +[redash.bundles] +wide_footer = redash_dummy + [redash.extensions] -assertive_extension = redash_dummy:assertive_extension -non_callable_extension = redash_dummy:module_attribute -not_findable_extension = redash_dummy:missing_attribute +assertive_extension = redash_dummy.extension:assertive_extension +non_callable_extension = redash_dummy.extension:module_attribute +not_findable_extension = redash_dummy.extension:missing_attribute not_importable_extension = missing_extension_module:extension -working_extension = redash_dummy:extension +working_extension = redash_dummy.extension:extension [redash.periodic_jobs] -dummy_periodic_job = redash_dummy:periodic_job +dummy_periodic_job = redash_dummy.jobs:periodic_job diff --git a/tests/extensions/redash-dummy/redash_dummy/__init__.py b/tests/extensions/redash-dummy/redash_dummy/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/extensions/redash-dummy/redash_dummy/bundle/WideFooter.jsx b/tests/extensions/redash-dummy/redash_dummy/bundle/WideFooter.jsx new file mode 100644 index 0000000000..f735ed1e03 --- /dev/null +++ b/tests/extensions/redash-dummy/redash_dummy/bundle/WideFooter.jsx @@ -0,0 +1,9 @@ +import React from "react"; + +export default function WideFooter() { + return ( +

+ This is a wide footer +
+ ); +} diff --git a/tests/extensions/redash-dummy/redash_dummy/extension.py b/tests/extensions/redash-dummy/redash_dummy/extension.py new file mode 100644 index 0000000000..28145ebc17 --- /dev/null +++ b/tests/extensions/redash-dummy/redash_dummy/extension.py @@ -0,0 +1,11 @@ +module_attribute = "hello!" + + +def extension(app): + """This extension will work""" + return "extension loaded" + + +def assertive_extension(app): + """This extension won't work""" + assert False diff --git a/tests/extensions/redash-dummy/redash_dummy.py b/tests/extensions/redash-dummy/redash_dummy/jobs.py similarity index 57% rename from tests/extensions/redash-dummy/redash_dummy.py rename to tests/extensions/redash-dummy/redash_dummy/jobs.py index 16837dfe0c..834cdc8e99 100644 --- a/tests/extensions/redash-dummy/redash_dummy.py +++ b/tests/extensions/redash-dummy/redash_dummy/jobs.py @@ -1,17 +1,5 @@ from datetime import timedelta -module_attribute = "hello!" - - -def extension(app): - """This extension will work""" - return "extension loaded" - - -def assertive_extension(app): - """This extension won't work""" - assert False - def job_callback(): return "result" diff --git a/tests/extensions/redash-dummy/setup.py b/tests/extensions/redash-dummy/setup.py index 496f03c41d..8d90587b0c 100644 --- a/tests/extensions/redash-dummy/setup.py +++ b/tests/extensions/redash-dummy/setup.py @@ -1,21 +1,25 @@ -from setuptools import setup +from setuptools import setup, find_packages setup( name="redash-dummy", - version="0.1", + version="0.2", description="Redash extensions for testing", author="Redash authors", license="MIT", + packages=find_packages(), + include_package_data=True, entry_points={ "redash.extensions": [ - "working_extension = redash_dummy:extension", - "non_callable_extension = redash_dummy:module_attribute", - "not_findable_extension = redash_dummy:missing_attribute", + "working_extension = redash_dummy.extension:extension", + "non_callable_extension = redash_dummy.extension:module_attribute", + "not_findable_extension = redash_dummy.extension:missing_attribute", "not_importable_extension = missing_extension_module:extension", - "assertive_extension = redash_dummy:assertive_extension", + "assertive_extension = redash_dummy.extension:assertive_extension", + ], + "redash.periodic_jobs": ["dummy_periodic_job = redash_dummy.jobs:periodic_job"], + "redash.bundles": [ + "wide_footer = redash_dummy", ], - "redash.periodic_jobs": ["dummy_periodic_job = redash_dummy:periodic_job"], }, - py_modules=["redash_dummy"], ) diff --git a/tests/extensions/test_extensions.py b/tests/extensions/test_extensions.py index 10a0efaf2f..fa955511ac 100644 --- a/tests/extensions/test_extensions.py +++ b/tests/extensions/test_extensions.py @@ -1,6 +1,8 @@ import logging -import os +import shutil +import subprocess import sys +from pathlib import Path from redash import extensions from redash.tasks import periodic_job_definitions @@ -8,7 +10,13 @@ logger = logging.getLogger(__name__) dummy_extension = "redash-dummy" -dummy_path = os.path.join(os.path.dirname(__file__), dummy_extension) + +this_dir = Path(__file__).parent.resolve() +app_dir = this_dir.parent.parent +dummy_path = str(this_dir / dummy_extension) +test_bundle = ( + app_dir / "client" / "app" / "extensions" / "wide_footer" / "WideFooter.jsx" +) class TestExtensions(BaseTestCase): @@ -47,5 +55,25 @@ def test_dummy_periodic_task(self): def test_dummy_periodic_task_definitions(self): jobs = periodic_job_definitions() - from redash_dummy import job_callback + from redash_dummy.jobs import job_callback + self.assertIn(job_callback, [job.get("func", None) for job in jobs]) + + +class TestBundles(BaseTestCase): + @classmethod + def setUpClass(cls): + # Install the redash-dummy package temporarily using pip + # in the user's local site package directory under ~/.local/ + subprocess.call(["pip", "install", "--user", dummy_path]) + + @classmethod + def tearDownClass(cls): + subprocess.call(["pip", "uninstall", "-y", "redash-dummy"]) + + def test_bundle_extensions(self): + # cleaning up after running bundle-extensions again + self.addCleanup(lambda: shutil.rmtree(test_bundle.parent)) + assert not test_bundle.exists() + subprocess.run(str(app_dir / "bin" / "bundle-extensions"), check=True) + assert test_bundle.exists() From 48924de700487482aa5b0fc69b4c6fddbfc96930 Mon Sep 17 00:00:00 2001 From: simonschneider-db <44668299+simonschneider-db@users.noreply.github.com> Date: Thu, 16 Jul 2020 22:05:44 +0200 Subject: [PATCH 06/49] Add TypeScript support (#5027) * TASK Add typescript dependencies to package.json * TASK Add typescript to build process and npm scripts and TASK Move example components to typescript and add an example definition file. * TASK Move back to ts-loader instead of babel typescript preset * FIX Remove unnecessary changes * FIX Explicitly mention tsconfig file in webpack.config.js to avoid `error while parsing tsconfig.json, The 'files' list in config file 'tsconfig.json' is empty` See (https://github.com/TypeStrong/ts-loader/issues/405#issuecomment-330108362) * FIX Move tsconfig to client subdirectory to make it accessible in docker container (only webpack.config.js is copied over from root folder in Dockerfile) * TASK Move from ts-loader to babel to reduce compatibility issues between ES6/7 and typescript compilation. * TASK Add types for classnames, hoist-non-react-statics and lodash. Fix default export of DashboardList and run prettier on eslintrc * Run npm install * Trigger tests * Run npm install 2 * Trigger tests --- client/.babelrc | 3 +- client/.eslintrc.js | 33 +- .../components/empty-state/EmptyState.d.ts | 18 + ...yState.jsx => DashboardListEmptyState.tsx} | 14 +- client/jsconfig.json | 9 - client/tsconfig.json | 35 + package-lock.json | 3275 ++++++++++++++--- package.json | 29 +- webpack.config.js | 5 +- 9 files changed, 2911 insertions(+), 510 deletions(-) create mode 100644 client/app/components/empty-state/EmptyState.d.ts rename client/app/pages/dashboards/components/{DashboardListEmptyState.jsx => DashboardListEmptyState.tsx} (78%) delete mode 100644 client/jsconfig.json create mode 100644 client/tsconfig.json diff --git a/client/.babelrc b/client/.babelrc index 0fe25a043c..3d2d378a0e 100644 --- a/client/.babelrc +++ b/client/.babelrc @@ -7,7 +7,8 @@ ], "useBuiltIns": "usage" }], - "@babel/preset-react" + "@babel/preset-react", + "@babel/preset-typescript" ], "plugins": [ "@babel/plugin-proposal-class-properties", diff --git a/client/.eslintrc.js b/client/.eslintrc.js index 152bf9ca3d..8bc0055d03 100644 --- a/client/.eslintrc.js +++ b/client/.eslintrc.js @@ -1,17 +1,40 @@ module.exports = { root: true, - extends: ["react-app", "plugin:compat/recommended", "prettier"], - plugins: ["jest", "compat", "no-only-tests"], + parser: "@typescript-eslint/parser", + extends: [ + "react-app", + "plugin:compat/recommended", + "prettier", + // Remove any typescript-eslint rules that would conflict with prettier + "prettier/@typescript-eslint", + ], + plugins: ["jest", "compat", "no-only-tests", "@typescript-eslint"], settings: { - "import/resolver": "webpack" + "import/resolver": "webpack", }, env: { browser: true, - node: true + node: true, }, rules: { // allow debugger during development "no-debugger": process.env.NODE_ENV === "production" ? 2 : 0, "jsx-a11y/anchor-is-valid": "off", - } + }, + overrides: [ + { + // Only run typescript-eslint on TS files + files: ["*.ts", "*.tsx", ".*.ts", ".*.tsx"], + extends: ["plugin:@typescript-eslint/recommended"], + rules: { + // Do not require functions (especially react components) to have explicit returns + "@typescript-eslint/explicit-function-return-type": "off", + // Do not require to type every import from a JS file to speed up development + "@typescript-eslint/no-explicit-any": "off", + // Do not complain about useless contructors in declaration files + "no-useless-constructor": "off", + "@typescript-eslint/no-useless-constructor": "error", + }, + }, + ], }; diff --git a/client/app/components/empty-state/EmptyState.d.ts b/client/app/components/empty-state/EmptyState.d.ts new file mode 100644 index 0000000000..4ad6707851 --- /dev/null +++ b/client/app/components/empty-state/EmptyState.d.ts @@ -0,0 +1,18 @@ +import React from "react"; + +export interface EmptyStateProps { + header?: string; + icon?: string; + description: string; + illustration: string; + helpLink: string; + + onboardingMode?: boolean; + showAlertStep?: boolean; + showDashboardStep?: boolean; + showInviteStep?: boolean; +} + +declare const EmptyState: React.FunctionComponent; + +export default EmptyState; diff --git a/client/app/pages/dashboards/components/DashboardListEmptyState.jsx b/client/app/pages/dashboards/components/DashboardListEmptyState.tsx similarity index 78% rename from client/app/pages/dashboards/components/DashboardListEmptyState.jsx rename to client/app/pages/dashboards/components/DashboardListEmptyState.tsx index bef53e7617..2478c1b984 100644 --- a/client/app/pages/dashboards/components/DashboardListEmptyState.jsx +++ b/client/app/pages/dashboards/components/DashboardListEmptyState.tsx @@ -1,10 +1,16 @@ -import React from "react"; -import PropTypes from "prop-types"; +import * as React from "react"; +import * as PropTypes from "prop-types"; import BigMessage from "@/components/BigMessage"; import NoTaggedObjectsFound from "@/components/NoTaggedObjectsFound"; import EmptyState from "@/components/empty-state/EmptyState"; -export default function DashboardListEmptyState({ page, searchTerm, selectedTags }) { +export interface DashboardListEmptyStateProps { + page: string; + searchTerm: string; + selectedTags: string[]; +} + +export default function DashboardListEmptyState({ page, searchTerm, selectedTags }: DashboardListEmptyStateProps) { if (searchTerm !== "") { return ; } @@ -30,5 +36,5 @@ export default function DashboardListEmptyState({ page, searchTerm, selectedTags DashboardListEmptyState.propTypes = { page: PropTypes.string.isRequired, searchTerm: PropTypes.string.isRequired, - selectedTags: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types + selectedTags: PropTypes.array.isRequired, }; diff --git a/client/jsconfig.json b/client/jsconfig.json deleted file mode 100644 index fe68d7ac70..0000000000 --- a/client/jsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "./", - "paths": { - "@/*": ["./app/*"] - } - }, - "exclude": ["dist"] -} \ No newline at end of file diff --git a/client/tsconfig.json b/client/tsconfig.json new file mode 100644 index 0000000000..cee94d6637 --- /dev/null +++ b/client/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + // Target latest version of ECMAScript. + "target": "esnext", + // Search under node_modules for non-relative imports. + "moduleResolution": "node", + // Process & infer types from .js files. + "allowJs": true, + // Don't emit; allow Babel to transform files. + "noEmit": true, + // Enable strictest settings like strictNullChecks & noImplicitAny. + "strict": true, + // Import non-ES modules as default imports. + "esModuleInterop": true, + "jsx": "react", + "allowSyntheticDefaultImports": true, + "noUnusedLocals": true, + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "forceConsistentCasingInFileNames": true, + "baseUrl": "./", + "paths": { + "@/*": ["./app/*"] + } + }, + "include": [ + "app/**/*" + ], + "exclude": [ + "dist" + ] +} diff --git a/package-lock.json b/package-lock.json index e9bae49195..6a0c300935 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,94 @@ "babel-runtime": "^6.26.0" } }, + "@babel/cli": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.10.4.tgz", + "integrity": "sha512-xX99K4V1BzGJdQANK5cwK+EpF1vP9gvqhn+iWvG+TubCjecplW7RSQimJ2jcCvu6fnK5pY6mZMdu6EWTj32QVA==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.13", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + }, + "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" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "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" + } + }, + "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, + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "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 + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "optional": true + } + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -59,28 +147,156 @@ "@babel/highlight": "^7.0.0" } }, - "@babel/core": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.3.4.tgz", - "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", + "@babel/compat-data": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.10.4.tgz", + "integrity": "sha512-t+rjExOrSVvjQQXNp5zAIYDp00KjdvGl/TpDX5REPr0S9IAIPQMTilcfG6q8c0QFmj9lSTVySV2VTsyggvtNIw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helpers": "^7.2.0", - "@babel/parser": "^7.3.4", - "@babel/template": "^7.2.2", - "@babel/traverse": "^7.3.4", - "@babel/types": "^7.3.4", - "convert-source-map": "^1.1.0", + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "semver": "^5.5.0" + } + }, + "@babel/core": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.4.tgz", + "integrity": "sha512-3A0tS0HWpy4XujGc7QtOIHTeNwUgWaZc/WuS5YQrfhU67jnVmsD6OGPc1AKHH0LJHQICGncy3+YUjIhVlfDdcA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4", + "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", + "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": { + "@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" + } + }, + "@babel/generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.4.tgz", + "integrity": "sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.4.tgz", + "integrity": "sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -90,6 +306,18 @@ "ms": "^2.1.1" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -126,22 +354,60 @@ } }, "@babel/helper-annotate-as-pure": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", - "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", - "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } } }, "@babel/helper-builder-react-jsx": { @@ -154,299 +420,1563 @@ "esutils": "^2.0.0" } }, - "@babel/helper-call-delegate": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz", - "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", + "@babel/helper-compilation-targets": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", + "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.0.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/compat-data": "^7.10.4", + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "semver": "^5.5.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.4.tgz", - "integrity": "sha512-uFpzw6L2omjibjxa8VGZsJUPL5wJH0zzGKpoz0ccBkzIa6C8kWNUbiBmQ0rgOKWlHJ6qzmfa6lTiGchiV8SC+g==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.3.4", - "@babel/helper-split-export-declaration": "^7.0.0" - } - }, - "@babel/helper-define-map": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz", - "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.0.0", - "lodash": "^4.17.10" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", - "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.4.tgz", + "integrity": "sha512-9raUiOsXPxzzLjCXeosApJItoMnX3uyT4QdM2UldffuGApNrF8e938MwNpDCK9CPoyxrEoCgT+hObJc3mZa6lQ==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4" + }, + "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" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } } }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "@babel/helper-create-regexp-features-plugin": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", + "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^7.10.4", + "regexpu-core": "^4.7.0" } }, - "@babel/helper-hoist-variables": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz", - "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", + "@babel/helper-define-map": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.4.tgz", + "integrity": "sha512-nIij0oKErfCnLUCWaCaHW0Bmtl2RO9cN7+u2QT8yqTywgALKlyUVOvHDElh+b5DwVC6YB1FOYFOTWcN/+41EDA==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.4", + "lodash": "^4.17.13" + }, + "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" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } } }, - "@babel/helper-member-expression-to-functions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", - "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", + "@babel/helper-explode-assignable-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz", + "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==", "dev": true, "requires": { - "@babel/types": "^7.0.0" - } - }, + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "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" + } + }, + "@babel/generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.4.tgz", + "integrity": "sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.4.tgz", + "integrity": "sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "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/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.4.tgz", + "integrity": "sha512-m5j85pK/KZhuSdM/8cHUABQTAslV47OjfIB9Cc7P+PvlAoBzdb79BGNfw8RhT5Mq3p+xGd0ZfAKixbrUZx0C7A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, "@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, + "@babel/helper-module-transforms": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.4.tgz", + "integrity": "sha512-Er2FQX0oa3nV7eM1o0tNCTx7izmQtwAQsIiaLRWtavAAEcskb0XJ5OjJbVrYXWOTr8om921Scabn4/tzlx7j1Q==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4", + "lodash": "^4.17.13" + }, + "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" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.4.tgz", + "integrity": "sha512-inWpnHGgtg5NOF0eyHlC0/74/VkdRITY9dtTpB2PrxKKn+AkVMRiZz/Adrx+Ssg+MLDesi2zohBW6MVq6b4pOQ==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + }, + "dependencies": { + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz", + "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "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" + } + }, + "@babel/generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.4.tgz", + "integrity": "sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.4.tgz", + "integrity": "sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "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/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "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" + } + }, + "@babel/generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.4.tgz", + "integrity": "sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.4.tgz", + "integrity": "sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "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/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "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" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, + "@babel/helper-split-export-declaration": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", "dev": true, "requires": { "@babel/types": "^7.0.0" } }, - "@babel/helper-module-transforms": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz", - "integrity": "sha512-YRD7I6Wsv+IHuTPkAmAS4HhY0dkPobgLftHp0cRGZSdrRvmZY8rFvae/GVu3bD00qscuvK3WPHB3YdNpBXUqrA==", + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", + "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/template": "^7.2.2", - "@babel/types": "^7.2.2", - "lodash": "^4.17.10" + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "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" + } + }, + "@babel/generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.4.tgz", + "integrity": "sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.4.tgz", + "integrity": "sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "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/helper-optimise-call-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", - "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "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" + } + }, + "@babel/generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.4.tgz", + "integrity": "sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.4.tgz", + "integrity": "sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "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/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true - }, - "@babel/helper-regex": { + "@babel/highlight": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz", - "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, "requires": { - "lodash": "^4.17.10" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" } }, - "@babel/helper-remap-async-to-generator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", - "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "@babel/parser": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.4.tgz", + "integrity": "sha512-MJbxGSmejEFVOANAezdO39SObkURO5o/8b6fSH6D1pi9RZQt+ldppKPXfqgUWpSQ9asM6xaSaSJIaeWMDRP0Zg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/helper-replace-supers": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz", - "integrity": "sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==", + "@babel/plugin-proposal-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", + "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.3.4", - "@babel/types": "^7.3.4" + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "@babel/plugin-proposal-dynamic-import": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", + "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", "dev": true, "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/helper-split-export-declaration": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", - "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "@babel/plugin-proposal-json-strings": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", + "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/helper-wrap-function": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", - "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", + "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/helpers": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz", - "integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==", + "@babel/plugin-proposal-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", + "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", "dev": true, "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.5", - "@babel/types": "^7.3.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz", + "integrity": "sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA==", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@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/parser": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", - "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", - "dev": true - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", - "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", + "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.2.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/plugin-proposal-class-properties": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.4.tgz", - "integrity": "sha512-lUf8D3HLs4yYlAo8zjuneLvfxN7qfKv1Yzbj5vjqaqMJxgJA3Ipwp4VUJ+OrOdz53Wbww6ahwB8UhB2HQyLotA==", + "@babel/plugin-proposal-optional-chaining": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.4.tgz", + "integrity": "sha512-ZIhQIEeavTgouyMSdZRap4VPPHqJJ3NEs2cuHs5p0erH+iz6khB0qfgU8g7UuJkG88+fBMy23ZiU+nuHvekJeQ==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.3.4", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/plugin-proposal-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", - "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "@babel/plugin-proposal-private-methods": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", + "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.2.0" + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz", - "integrity": "sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA==", + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", + "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "@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.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz", - "integrity": "sha512-LvRVYb7kikuOtIoUeWTkOxQEV1kYvL5B6U3iWEGCzPNRus1MzJweFqORTj+0jkxozkTSYNJozPOddxmqdqsRpw==", + "@babel/plugin-syntax-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", + "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.2.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, - "@babel/plugin-syntax-async-generators": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", - "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "@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.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-syntax-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", - "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "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.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-syntax-jsx": { @@ -458,6 +1988,40 @@ "@babel/helper-plugin-utils": "^7.0.0" } }, + "@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" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, + "@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" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, "@babel/plugin-syntax-object-rest-spread": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", @@ -468,202 +2032,588 @@ } }, "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "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.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, + "@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" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", + "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.4.tgz", + "integrity": "sha512-oSAEz1YkBCAKr5Yiq8/BNtvSAPwkp/IyUnwZogd8p+F0RuYQQrLeRUzIQhueQTTBy/F+a40uS7OFKxnkRvmvFQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", - "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", + "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz", - "integrity": "sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", + "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", - "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", + "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-block-scoping": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz", - "integrity": "sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.4.tgz", + "integrity": "sha512-J3b5CluMg3hPUii2onJDRiaVbPtKFPLEaV5dOPY5OeAbDi1iU/UbbFFTgwb7WnanaDy7bjU35kc26W3eM5Qa0A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.11" + "@babel/helper-plugin-utils": "^7.10.4", + "lodash": "^4.17.13" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } } }, "@babel/plugin-transform-classes": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz", - "integrity": "sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.1.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.3.4", - "@babel/helper-split-export-declaration": "^7.0.0", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", + "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", "globals": "^11.1.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" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } } }, "@babel/plugin-transform-computed-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", - "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", + "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-destructuring": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz", - "integrity": "sha512-Lrj/u53Ufqxl/sGxyjsJ2XNtNuEjDyjpqdhMNh5aZ+XFOdThL46KBj27Uem4ggoezSYBxKWAil6Hu8HtwqesYw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", + "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz", - "integrity": "sha512-sKxnyHfizweTgKZf7XsXu/CNupKhzijptfTM+bozonIuyVrLWVUvYjE2bhuSBML8VQeMxq4Mm63Q9qvcvUcciQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", + "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.1.3" + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", - "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", + "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", - "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", + "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-for-of": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz", - "integrity": "sha512-Kz7Mt0SsV2tQk6jG5bBv5phVbkd0gd27SgYD4hH1aLMJRchM0dzHaXvrWhVZ+WxAlDoAKZ7Uy3jVTW2mKXQ1WQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", + "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-function-name": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz", - "integrity": "sha512-kWgksow9lHdvBC2Z4mxTsvc7YdY7w/V6B2vy9cTIPtLEE9NhwoWivaxdNM/S37elu5bqlLP/qOY906LukO9lkQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", + "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "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" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", + "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } } }, "@babel/plugin-transform-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", - "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", + "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", + "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-modules-amd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", - "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.4.tgz", + "integrity": "sha512-3Fw+H3WLUrTlzi3zMiZWp3AR4xadAEMv6XRCYnd5jAlLM61Rn+CRJaZMaNvIpcJpQ3vs1kyifYvEVPFfoSkKOA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz", - "integrity": "sha512-V6y0uaUQrQPXUrmj+hgnks8va2L0zcZymeU7TtWEgdRLNkceafKXEduv7QzgQAE4lT+suwooG9dC7LFhdRAbVQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", + "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0" + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz", - "integrity": "sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.4.tgz", + "integrity": "sha512-Tb28LlfxrTiOTGtZFsvkjpyjCl9IoaRI52AEU/VIwOwvDQWtbNJsAqTXzh+5R7i74e/OZHH2c2w2fsOqAfnQYQ==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-modules-umd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", - "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", + "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz", - "integrity": "sha512-NxIoNVhk9ZxS+9lSoAQ/LM0V2UEvARLttEHUrRDGKFaAxOYQcrkN/nLRE+BbbicCAvZPl7wMP0X60HsHE5DtQw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", + "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", "dev": true, "requires": { - "regexp-tree": "^0.1.0" + "@babel/helper-create-regexp-features-plugin": "^7.10.4" } }, "@babel/plugin-transform-new-target": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz", - "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", + "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-object-assign": { @@ -676,24 +2626,82 @@ } }, "@babel/plugin-transform-object-super": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", - "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", + "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-parameters": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.3.3.tgz", - "integrity": "sha512-IrIP25VvXWu/VlBWTpsjGptpomtIkYrN/3aDp4UKm7xK6UxZY88kcJ1UwETbzHAlwN21MnNfwlar0u8y3KpiXw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.4.tgz", + "integrity": "sha512-RurVtZ/D5nYfEg0iVERXYKEgDFeesHrHfx8RT05Sq57ucj2eOYAP6eu5fynL4Adju4I/mP/I6SO0DqNWAXjfLQ==", "dev": true, "requires": { - "@babel/helper-call-delegate": "^7.1.0", - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", + "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-react-display-name": { @@ -737,121 +2745,308 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz", - "integrity": "sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", + "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", + "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", "dev": true, "requires": { - "regenerator-transform": "^0.13.4" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", - "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", + "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-spread": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", - "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.4.tgz", + "integrity": "sha512-1e/51G/Ni+7uH5gktbWv+eCED9pP8ZpRhZB3jOaI3mmzfvJTWHkuyYTv0Z5PYtyM+Tr2Ccr9kUdQxn60fI5WuQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", - "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", + "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-template-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz", - "integrity": "sha512-FkPix00J9A/XWXv4VoKJBMeSkyY9x/TqIh76wzcdfl57RJJcf8CehQ08uwfhCDNtRQYtHQKBTwKZDEyjE13Lwg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.4.tgz", + "integrity": "sha512-4NErciJkAYe+xI5cqfS8pV/0ntlY5N5Ske/4ImxAVX7mk9Rxt2bwDTGv1Msc2BRJvWQcmYEC+yoMLdX22aE4VQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", - "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", + "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.10.4.tgz", + "integrity": "sha512-3WpXIKDJl/MHoAN0fNkSr7iHdUMHZoppXjf2HJ9/ed5Xht5wNIsXllJXdityKOxeA3Z8heYRb1D3p2H5rfCdPw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-typescript": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", + "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz", - "integrity": "sha512-m48Y0lMhrbXEJnVUaYly29jRXbQ3ksxPrS1Tg8t+MHqzXhtBYAvI51euOBaoAlZLPHsieY9XPVMf80a5x0cPcA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", + "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.1.3" + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } } }, "@babel/preset-env": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.3.4.tgz", - "integrity": "sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.10.4.tgz", + "integrity": "sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.10.4", + "@babel/helper-compilation-targets": "^7.10.4", + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-proposal-async-generator-functions": "^7.10.4", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-dynamic-import": "^7.10.4", + "@babel/plugin-proposal-json-strings": "^7.10.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", + "@babel/plugin-proposal-numeric-separator": "^7.10.4", + "@babel/plugin-proposal-object-rest-spread": "^7.10.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", + "@babel/plugin-proposal-optional-chaining": "^7.10.4", + "@babel/plugin-proposal-private-methods": "^7.10.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.10.4", + "@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.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.10.4", + "@babel/plugin-transform-arrow-functions": "^7.10.4", + "@babel/plugin-transform-async-to-generator": "^7.10.4", + "@babel/plugin-transform-block-scoped-functions": "^7.10.4", + "@babel/plugin-transform-block-scoping": "^7.10.4", + "@babel/plugin-transform-classes": "^7.10.4", + "@babel/plugin-transform-computed-properties": "^7.10.4", + "@babel/plugin-transform-destructuring": "^7.10.4", + "@babel/plugin-transform-dotall-regex": "^7.10.4", + "@babel/plugin-transform-duplicate-keys": "^7.10.4", + "@babel/plugin-transform-exponentiation-operator": "^7.10.4", + "@babel/plugin-transform-for-of": "^7.10.4", + "@babel/plugin-transform-function-name": "^7.10.4", + "@babel/plugin-transform-literals": "^7.10.4", + "@babel/plugin-transform-member-expression-literals": "^7.10.4", + "@babel/plugin-transform-modules-amd": "^7.10.4", + "@babel/plugin-transform-modules-commonjs": "^7.10.4", + "@babel/plugin-transform-modules-systemjs": "^7.10.4", + "@babel/plugin-transform-modules-umd": "^7.10.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", + "@babel/plugin-transform-new-target": "^7.10.4", + "@babel/plugin-transform-object-super": "^7.10.4", + "@babel/plugin-transform-parameters": "^7.10.4", + "@babel/plugin-transform-property-literals": "^7.10.4", + "@babel/plugin-transform-regenerator": "^7.10.4", + "@babel/plugin-transform-reserved-words": "^7.10.4", + "@babel/plugin-transform-shorthand-properties": "^7.10.4", + "@babel/plugin-transform-spread": "^7.10.4", + "@babel/plugin-transform-sticky-regex": "^7.10.4", + "@babel/plugin-transform-template-literals": "^7.10.4", + "@babel/plugin-transform-typeof-symbol": "^7.10.4", + "@babel/plugin-transform-unicode-escapes": "^7.10.4", + "@babel/plugin-transform-unicode-regex": "^7.10.4", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.10.4", + "browserslist": "^4.12.0", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@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/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz", + "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.3.4", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.2.0", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-json-strings": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.3.4", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.3.4", - "@babel/plugin-transform-classes": "^7.3.4", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.2.0", - "@babel/plugin-transform-dotall-regex": "^7.2.0", - "@babel/plugin-transform-duplicate-keys": "^7.2.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.2.0", - "@babel/plugin-transform-function-name": "^7.2.0", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.2.0", - "@babel/plugin-transform-modules-commonjs": "^7.2.0", - "@babel/plugin-transform-modules-systemjs": "^7.3.4", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.3.0", - "@babel/plugin-transform-new-target": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.2.0", - "@babel/plugin-transform-parameters": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.3.4", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.2.0", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.2.0", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.2.0", - "browserslist": "^4.3.4", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.3.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" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", + "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + } } }, "@babel/preset-react": { @@ -867,6 +3062,24 @@ "@babel/plugin-transform-react-jsx-source": "^7.0.0" } }, + "@babel/preset-typescript": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.10.4.tgz", + "integrity": "sha512-SdYnvGPv+bLlwkF2VkJnaX/ni1sMNetcGI1+nThF1gyv6Ph8Qucc4ZZAjM5yZcE/AKRXIOTZz7eSRDWOEjPyRQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + } + } + }, "@babel/runtime": { "version": "7.7.7", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.7.tgz", @@ -1153,18 +3366,40 @@ "@turf/helpers": "6.x" } }, + "@types/classnames": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.10.tgz", + "integrity": "sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ==", + "dev": true + }, "@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/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/json-schema": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", "dev": true }, + "@types/lodash": { + "version": "4.14.157", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.157.tgz", + "integrity": "sha512-Ft5BNFmv2pHDgxV5JDsndOWTRJ+56zte0ZpYLowp03tW+K+t8u8YMOzAnpuqPgzX6WO1XpDIUm7u04M8vdDiVQ==", + "dev": true + }, "@types/node": { "version": "11.9.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.5.tgz", @@ -1172,23 +3407,24 @@ "dev": true }, "@types/prop-types": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.0.tgz", - "integrity": "sha512-eItQyV43bj4rR3JPV0Skpl1SncRCdziTEK9/v8VwXmV6d/qOUO8/EuWeHBbCZcsfSHfzI5UyMJLCSXtxxznyZg==" + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" }, "@types/react": { - "version": "16.8.5", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.5.tgz", - "integrity": "sha512-8LRySaaSJVLNZb2dbOGvGmzn88cbAfrgDpuWy+6lLgQ0OJFgHHvyuaCX4/7ikqJlpmCPf4uazJAZcfTQRdJqdQ==", + "version": "16.9.41", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.41.tgz", + "integrity": "sha512-6cFei7F7L4wwuM+IND/Q2cV1koQUvJ8iSV+Gwn0c3kvABZ691g7sp3hfEQHOUBJtccl1gPi+EyNjMIl9nGA0ug==", "requires": { "@types/prop-types": "*", "csstype": "^2.2.0" } }, "@types/react-dom": { - "version": "16.8.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.8.2.tgz", - "integrity": "sha512-MX7n1wq3G/De15RGAAqnmidzhr2Y9O/ClxPxyqaNg96pGyeXUYPSvujgzEVpLo9oIP4Wn1UETl+rxTN02KEpBw==", + "version": "16.9.8", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz", + "integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==", + "dev": true, "requires": { "@types/react": "*" } @@ -2250,6 +4486,15 @@ "babel-runtime": "^6.22.0" } }, + "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-istanbul": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", @@ -2811,14 +5056,23 @@ } }, "browserslist": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.2.tgz", - "integrity": "sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.13.0.tgz", + "integrity": "sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000939", - "electron-to-chromium": "^1.3.113", - "node-releases": "^1.1.8" + "caniuse-lite": "^1.0.30001093", + "electron-to-chromium": "^1.3.488", + "escalade": "^3.0.1", + "node-releases": "^1.1.58" + }, + "dependencies": { + "electron-to-chromium": { + "version": "1.3.496", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.496.tgz", + "integrity": "sha512-TXY4mwoyowwi4Lsrq9vcTUYBThyc1b2hXaTZI13p8/FRhY2CTaq5lK+DVjhYkKiTLsKt569Xes+0J5JsVXFurQ==", + "dev": true + } } }, "bser": { @@ -3037,9 +5291,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30000939", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000939.tgz", - "integrity": "sha512-oXB23ImDJOgQpGjRv1tCtzAvJr4/OvrHi5SO2vUgB0g0xpdZZoA/BxfImiWfdwoYdUTtQrPsXsvYU/dmCSM8gg==", + "version": "1.0.30001097", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001097.tgz", + "integrity": "sha512-TeuSleKt/vWXaPkLVFqGDnbweYfq4IaZ6rUugFf3rWY6dlII8StUZ8Ddin0PkADfgYZ4wRqCdO2ORl4Rn5eZIA==", "dev": true }, "canvas-fit": { @@ -3861,6 +6115,24 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.4.tgz", "integrity": "sha512-05qQ5hXShcqGkPZpXEFLIpxayZscVD2kuMBZewxiIPPEagukO4mqgPA9CWhUvFBJfy3ODdK2p9xyHh7FTU9/7A==" }, + "core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "requires": { + "browserslist": "^4.8.5", + "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.4.7", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.4.7.tgz", @@ -4181,9 +6453,9 @@ } }, "csstype": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.2.tgz", - "integrity": "sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==" + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.11.tgz", + "integrity": "sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw==" }, "cubic-hermite": { "version": "1.0.0", @@ -5133,6 +7405,12 @@ "es6-symbol": "^3.1.1" } }, + "escalade": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.1.tgz", + "integrity": "sha512-DR6NO3h9niOT+MZs7bjxlj2a1k+POu5RN8CLTPX2+i78bRi9eLe7+0zXgUHMnGXWybYcL61E9hGhPKqedy8tQA==", + "dev": true + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -6785,6 +9063,12 @@ "universalify": "^0.1.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", @@ -7309,6 +9593,12 @@ "resolved": "https://registry.npmjs.org/gamma/-/gamma-0.1.0.tgz", "integrity": "sha1-MxVkNAO/J5BsqAqzfDbs6UQO8zA=" }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, "geojson-vt": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", @@ -9925,12 +12215,6 @@ "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", "dev": true }, - "js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10052,12 +12336,20 @@ "dev": true }, "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", "dev": true, "requires": { - "minimist": "^1.2.0" + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } } }, "jsonfile": { @@ -10215,6 +12507,23 @@ "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", "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" + }, + "dependencies": { + "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 + } + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -11422,13 +13731,10 @@ } }, "node-releases": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.8.tgz", - "integrity": "sha512-gQm+K9mGCiT/NXHy+V/ZZS1N/LOaGGqRAAJJs3X9Ah1g+CIbRcBgNyoNYQ+SEtcyAtB9KqDruu+fF7nWjsqRaA==", - "dev": true, - "requires": { - "semver": "^5.3.0" - } + "version": "1.1.59", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.59.tgz", + "integrity": "sha512-H3JrdUczbdiwxN5FuJPyCHnGHIFqQ0wWxo+9j1kAXAzqNMAHlo+4I/sYYxpyK0irQ73HgdiyzD32oqQDcU2Osw==", + "dev": true }, "nopt": { "version": "2.1.2", @@ -12888,12 +15194,6 @@ } } }, - "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 - }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -14003,9 +16303,9 @@ "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" }, "regenerate-unicode-properties": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz", - "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", + "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" @@ -14017,12 +16317,29 @@ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "regenerator-transform": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.4.tgz", - "integrity": "sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A==", + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", "dev": true, "requires": { - "private": "^0.1.6" + "@babel/runtime": "^7.8.4" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.4.tgz", + "integrity": "sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + } } }, "regex-not": { @@ -14061,12 +16378,6 @@ "resolved": "https://registry.npmjs.org/regex-regex/-/regex-regex-1.0.0.tgz", "integrity": "sha1-kEih6uuHD01IDavHb8Qs3MC8OnI=" }, - "regexp-tree": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.5.tgz", - "integrity": "sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ==", - "dev": true - }, "regexp.prototype.flags": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", @@ -14161,29 +16472,29 @@ "dev": true }, "regexpu-core": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.4.0.tgz", - "integrity": "sha512-eDDWElbwwI3K0Lo6CqbQbA6FwgtCz4kYTarrri1okfkRLZAqstU+B3voZBCjg8Fl6iq0gXrJG6MvRgLthfvgOA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", "dev": true, "requires": { "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^7.0.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.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.0.2" + "unicode-match-property-value-ecmascript": "^1.2.0" } }, "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "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.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -16970,6 +19281,12 @@ "dup": "^1.0.0" } }, + "typescript": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz", + "integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==", + "dev": true + }, "ua-parser-js": { "version": "0.7.21", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", @@ -17013,9 +19330,9 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz", - "integrity": "sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==", + "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": { diff --git a/package.json b/package.json index de20ef4b8a..72678fe7d6 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,15 @@ "webpack-dev-server": "webpack-dev-server", "analyze": "npm run clean && BUNDLE_ANALYZER=on webpack", "analyze:build": "npm run clean && NODE_ENV=production BUNDLE_ANALYZER=on webpack", - "lint": "npm run lint:base -- --ext .js --ext .jsx ./client", - "lint:fix": "npm run lint:base -- --fix --ext .js --ext .jsx ./client", + "lint": "npm run lint:base -- --ext .js --ext .jsx --ext .ts --ext .tsx ./client", + "lint:fix": "npm run lint:base -- --fix --ext .js --ext .jsx --ext .ts --ext .tsx ./client", "lint:base": "eslint --config ./client/.eslintrc.js --ignore-path ./client/.eslintignore", "lint:ci": "npm run lint -- --max-warnings 0 --format junit --output-file /tmp/test-results/eslint/results.xml", - "prettier": "prettier --write 'client/app/**/*.{js,jsx}' 'client/cypress/**/*.js'", - "test": "TZ=Africa/Khartoum jest", + "prettier": "prettier --write 'client/app/**/*.{js,jsx,ts,tsx}' 'client/cypress/**/*.{js,jsx,ts,tsx}'", + "type-check": "tsc --noEmit --project client/tsconfig.json", + "type-check:watch": "npm run type-check -- --watch", + "jest": "TZ=Africa/Khartoum jest", + "test": "run-s type-check jest", "test:watch": "jest --watch", "cypress:install": "npm install --no-save cypress@~4.5.0 @percy/agent@0.26.2 @percy/cypress@^2.2.0 atob@2.1.2", "cypress": "node client/cypress/cypress.js", @@ -43,9 +46,6 @@ "homepage": "https://redash.io/", "dependencies": { "@redash/viz": "file:viz-lib", - "@types/prop-types": "^15.5.2", - "@types/react": "^16.3.13", - "@types/react-dom": "^16.0.5", "ace-builds": "^1.4.12", "antd": "^3.26.17", "axios": "^0.19.0", @@ -78,11 +78,19 @@ "use-media": "^1.4.0" }, "devDependencies": { - "@babel/core": "^7.2.2", - "@babel/plugin-proposal-class-properties": "^7.3.0", + "@babel/cli": "^7.10.4", + "@babel/core": "^7.10.4", + "@babel/plugin-proposal-class-properties": "^7.10.4", "@babel/plugin-transform-object-assign": "^7.2.0", - "@babel/preset-env": "^7.3.1", + "@babel/preset-env": "^7.10.4", "@babel/preset-react": "^7.0.0", + "@babel/preset-typescript": "^7.10.4", + "@types/classnames": "^2.2.10", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/lodash": "^4.14.157", + "@types/prop-types": "^15.7.3", + "@types/react": "^16.9.41", + "@types/react-dom": "^16.9.8", "@typescript-eslint/eslint-plugin": "^2.10.0", "@typescript-eslint/parser": "^2.10.0", "babel-eslint": "^10.0.3", @@ -122,6 +130,7 @@ "raw-loader": "^0.5.1", "react-test-renderer": "^16.5.2", "request": "^2.88.0", + "typescript": "^3.9.6", "url-loader": "^1.1.2", "webpack": "^4.20.2", "webpack-build-notifier": "^0.1.30", diff --git a/webpack.config.js b/webpack.config.js index 522671b306..e1af0b0706 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -9,6 +9,7 @@ const CopyWebpackPlugin = require("copy-webpack-plugin"); const LessPluginAutoPrefix = require("less-plugin-autoprefix"); const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") .BundleAnalyzerPlugin; +const fs = require("fs"); const path = require("path"); @@ -40,7 +41,7 @@ const config = { }, resolve: { symlinks: false, - extensions: [".js", ".jsx"], + extensions: [".js", ".jsx", ".ts", ".tsx"], alias: { "@": appPath, extensions: extensionPath @@ -86,7 +87,7 @@ const config = { module: { rules: [ { - test: /\.jsx?$/, + test: /\.(t|j)sx?$/, exclude: /node_modules/, use: ["babel-loader", "eslint-loader"] }, From 95c28c47ade39db9c1345c7f7477123011af1240 Mon Sep 17 00:00:00 2001 From: Omer Lachish Date: Thu, 16 Jul 2020 23:29:47 +0300 Subject: [PATCH 07/49] Eager load outdated queries (#5049) * eager load outdated queries * explicitly use .all() instead of list() --- redash/models/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/redash/models/__init__.py b/redash/models/__init__.py index 4e7b97cb90..a7c210e699 100644 --- a/redash/models/__init__.py +++ b/redash/models/__init__.py @@ -638,6 +638,7 @@ def outdated_queries(cls): ) .filter(Query.schedule.isnot(None)) .order_by(Query.id) + .all() ) now = utils.utcnow() From 6c349ea70a4394e9cf4849838c3ece8d3ccf554e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2020 22:41:16 -0300 Subject: [PATCH 08/49] Bump lodash from 4.17.15 to 4.17.19 in /viz-lib (#5051) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- viz-lib/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/viz-lib/package-lock.json b/viz-lib/package-lock.json index 8fd0d7ece9..338412872d 100644 --- a/viz-lib/package-lock.json +++ b/viz-lib/package-lock.json @@ -7853,9 +7853,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" }, "lodash.escape": { "version": "4.0.1", From a1255b41442da27b8bff70f70018265b7a2a1540 Mon Sep 17 00:00:00 2001 From: Levko Kravets Date: Fri, 17 Jul 2020 11:28:15 +0300 Subject: [PATCH 09/49] Fix wrong Y-axis range for stacked bar chart (#5029) * getredash/redash#5026 Fix wrong Y-axis range for stacked bar chart * Update tests * Use Plotly's built-in algorinthm to compute Y-axis range * Update tests * Revert previous solution (yRange-related code) * Revert other unrelated changes * Revert other unrelated changes * Move chart rendering to own file and ensure that rendering steps will occur in necessary order * Reduce amount of plot updates by mergin separate updates into a sigle cumulative update * Give better names for several functions --- .../chart/Renderer/PlotlyChart.jsx | 99 ++++--------- .../chart/Renderer/initChart.js | 134 ++++++++++++++++++ .../prepareLayout/box-single-axis.json | 4 +- .../prepareLayout/box-with-second-axis.json | 13 +- .../prepareLayout/default-single-axis.json | 4 +- .../default-with-second-axis.json | 13 +- .../prepareLayout/default-with-stacking.json | 4 +- .../prepareLayout/default-without-legend.json | 4 +- .../src/visualizations/chart/plotly/index.js | 8 +- .../chart/plotly/prepareLayout.js | 12 +- ...applyLayoutFixes.js => updateChartSize.js} | 73 ++++++---- .../chart/plotly/updateLayout.js | 18 --- .../chart/plotly/updateYRanges.js | 44 ++++++ .../src/visualizations/chart/plotly/utils.js | 18 +-- 14 files changed, 284 insertions(+), 164 deletions(-) create mode 100644 viz-lib/src/visualizations/chart/Renderer/initChart.js rename viz-lib/src/visualizations/chart/plotly/{applyLayoutFixes.js => updateChartSize.js} (55%) delete mode 100644 viz-lib/src/visualizations/chart/plotly/updateLayout.js create mode 100644 viz-lib/src/visualizations/chart/plotly/updateYRanges.js diff --git a/viz-lib/src/visualizations/chart/Renderer/PlotlyChart.jsx b/viz-lib/src/visualizations/chart/Renderer/PlotlyChart.jsx index a8ba95ce0f..29e802d36d 100644 --- a/viz-lib/src/visualizations/chart/Renderer/PlotlyChart.jsx +++ b/viz-lib/src/visualizations/chart/Renderer/PlotlyChart.jsx @@ -1,87 +1,48 @@ -import { isArray, isString, isObject, startsWith } from "lodash"; -import React, { useState, useEffect, useContext } from "react"; +import React, { useState, useEffect, useContext, useRef } from "react"; import useMedia from "use-media"; import { ErrorBoundaryContext } from "@/components/ErrorBoundary"; import { RendererPropTypes } from "@/visualizations/prop-types"; -import resizeObserver from "@/services/resizeObserver"; import { visualizationsSettings } from "@/visualizations/visualizationsSettings"; import getChartData from "../getChartData"; -import { Plotly, prepareData, prepareLayout, updateData, updateLayout, applyLayoutFixes } from "../plotly"; - -function catchErrors(func, errorHandler) { - return (...args) => { - try { - return func(...args); - } catch (error) { - // This error happens only when chart width is 20px and looks that - // it's safe to just ignore it: 1px less or more and chart will get fixed. - if (isString(error) && startsWith(error, "ax.dtick error")) { - return; - } - errorHandler.handleError(error); - } - }; -} +import initChart from "./initChart"; export default function PlotlyChart({ options, data }) { const [container, setContainer] = useState(null); + const [chart, setChart] = useState(null); + const errorHandler = useContext(ErrorBoundaryContext); - const isMobile = useMedia({ maxWidth: 768 }); + const errorHandlerRef = useRef(); + errorHandlerRef.current = errorHandler; - useEffect( - catchErrors(() => { - if (container) { - const plotlyOptions = { - showLink: false, - displaylogo: false, - }; + const isMobile = useMedia({ maxWidth: 768 }); + const isMobileRef = useRef(); + isMobileRef.current = isMobile; - if (visualizationsSettings.hidePlotlyModeBar) { - plotlyOptions.displayModeBar = false; + useEffect(() => { + if (container) { + let isDestroyed = false; + + const chartData = getChartData(data.rows, options); + const _chart = initChart(container, options, chartData, visualizationsSettings, error => { + errorHandlerRef.current.handleError(error); + }); + _chart.initialized.then(() => { + if (!isDestroyed) { + setChart(_chart); } + }); + return () => { + isDestroyed = true; + _chart.destroy(); + }; + } + }, [options, data, container]); - const chartData = getChartData(data.rows, options); - const plotlyData = prepareData(chartData, options); - const plotlyLayout = { ...prepareLayout(container, options, plotlyData), dragmode: !isMobile ? "zoom" : false }; - - // It will auto-purge previous graph - Plotly.newPlot(container, plotlyData, plotlyLayout, plotlyOptions).then( - catchErrors(() => { - applyLayoutFixes(container, plotlyLayout, options, (e, u) => Plotly.relayout(e, u)); - }, errorHandler) - ); - - container.on( - "plotly_restyle", - catchErrors(updates => { - // This event is triggered if some plotly data/layout has changed. - // We need to catch only changes of traces visibility to update stacking - if (isArray(updates) && isObject(updates[0]) && updates[0].visible) { - updateData(plotlyData, options); - updateLayout(plotlyLayout, options, plotlyData); - Plotly.relayout(container, plotlyLayout); - } - }, errorHandler) - ); - - const unwatch = resizeObserver( - container, - catchErrors(() => { - applyLayoutFixes(container, plotlyLayout, options, (e, u) => Plotly.relayout(e, u)); - }, errorHandler) - ); - return unwatch; - } - }, errorHandler), - [options, data, container, isMobile] - ); - - // Cleanup when component destroyed useEffect(() => { - if (container) { - return () => Plotly.purge(container); + if (chart) { + chart.setZoomEnabled(!isMobile); } - }, [container]); + }, [chart, isMobile]); return
; } diff --git a/viz-lib/src/visualizations/chart/Renderer/initChart.js b/viz-lib/src/visualizations/chart/Renderer/initChart.js new file mode 100644 index 0000000000..6e9c8794ce --- /dev/null +++ b/viz-lib/src/visualizations/chart/Renderer/initChart.js @@ -0,0 +1,134 @@ +import { isArray, isObject, isString, isFunction, startsWith, reduce, merge, map, each } from "lodash"; +import resizeObserver from "@/services/resizeObserver"; +import { Plotly, prepareData, prepareLayout, updateData, updateYRanges, updateChartSize } from "../plotly"; + +function createErrorHandler(errorHandler) { + return error => { + // This error happens only when chart width is 20px and looks that + // it's safe to just ignore it: 1px less or more and chart will get fixed. + if (isString(error) && startsWith(error, "ax.dtick error")) { + return; + } + errorHandler(error); + }; +} + +// This utility is intended to reduce amount of plot updates when multiple Plotly.relayout +// calls needed in order to compute/update the plot. +// `.append()` method takes an array of two element: first one is a object with updates for layout, +// and second is an optional function that will be called when plot is updated. That function may +// return an array with same structure if further updates needed. +// `.process()` merges all updates into a single object and calls `Plotly.relayout()`. After that +// it calls all callbacks, collects their return values and does another loop if needed. +function initPlotUpdater() { + let actions = []; + + const updater = { + append(action) { + if (isArray(action) && isObject(action[0])) { + actions.push(action); + } + return updater; + }, + process(plotlyElement) { + if (actions.length > 0) { + const updates = reduce(actions, (updates, action) => merge(updates, action[0]), {}); + const handlers = map(actions, action => (isFunction(action[1]) ? action[1] : () => null)); + actions = []; + return Plotly.relayout(plotlyElement, updates).then(() => { + each(handlers, handler => updater.append(handler())); + return updater.process(plotlyElement); + }); + } else { + return Promise.resolve(); + } + }, + }; + + return updater; +} + +export default function initChart(container, options, data, additionalOptions, onError) { + const handleError = createErrorHandler(onError); + + const plotlyOptions = { + showLink: false, + displaylogo: false, + }; + + if (additionalOptions.hidePlotlyModeBar) { + plotlyOptions.displayModeBar = false; + } + + const plotlyData = prepareData(data, options); + const plotlyLayout = prepareLayout(container, options, plotlyData); + + let isDestroyed = false; + + let updater = initPlotUpdater(); + + function createSafeFunction(fn) { + return (...args) => { + if (!isDestroyed) { + try { + return fn(...args); + } catch (error) { + handleError(error); + } + } + }; + } + + let unwatchResize = () => {}; + + const promise = Promise.resolve() + .then(() => Plotly.newPlot(container, plotlyData, plotlyLayout, plotlyOptions)) + .then( + createSafeFunction(() => + updater + .append(updateYRanges(container, plotlyLayout, options)) + .append(updateChartSize(container, plotlyLayout, options)) + .process(container) + ) + ) + .then( + createSafeFunction(() => { + container.on( + "plotly_restyle", + createSafeFunction(updates => { + // This event is triggered if some plotly data/layout has changed. + // We need to catch only changes of traces visibility to update stacking + if (isArray(updates) && isObject(updates[0]) && updates[0].visible) { + updateData(plotlyData, options); + updater.append(updateYRanges(container, plotlyLayout, options)).process(container); + } + }) + ); + + unwatchResize = resizeObserver( + container, + createSafeFunction(() => { + updater.append(updateChartSize(container, plotlyLayout, options)).process(container); + }) + ); + }) + ) + .catch(handleError); + + const result = { + initialized: promise.then(() => result), + setZoomEnabled: createSafeFunction(allowZoom => { + const layoutUpdates = { dragmode: allowZoom ? "zoom" : false }; + return Plotly.relayout(container, layoutUpdates); + }), + destroy: createSafeFunction(() => { + isDestroyed = true; + container.removeAllListeners("plotly_restyle"); + unwatchResize(); + delete container.__previousSize; // added by `updateChartSize` + Plotly.purge(container); + }), + }; + + return result; +} diff --git a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/box-single-axis.json b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/box-single-axis.json index bd1323b2db..7332ce9886 100644 --- a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/box-single-axis.json +++ b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/box-single-axis.json @@ -33,8 +33,8 @@ "automargin": true, "title": null, "type": "linear", - "autorange": false, - "range": [0, 0] + "autorange": true, + "range": null } } } diff --git a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/box-with-second-axis.json b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/box-with-second-axis.json index d58d918e4d..c54a771f22 100644 --- a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/box-with-second-axis.json +++ b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/box-with-second-axis.json @@ -9,7 +9,10 @@ "traceorder": "normal" } }, - "series": [{ "name": "a" }, { "name": "b", "yaxis": "y2" }] + "series": [ + { "name": "a" }, + { "name": "b", "yaxis": "y2" } + ] }, "output": { "layout": { @@ -33,15 +36,15 @@ "automargin": true, "title": null, "type": "linear", - "autorange": false, - "range": [0, 0] + "autorange": true, + "range": null }, "yaxis2": { "automargin": true, "title": null, "type": "linear", - "autorange": false, - "range": [0, 0], + "autorange": true, + "range": null, "overlaying": "y", "side": "right" } diff --git a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-single-axis.json b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-single-axis.json index d77400aa35..3cd303b58f 100644 --- a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-single-axis.json +++ b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-single-axis.json @@ -31,8 +31,8 @@ "automargin": true, "title": null, "type": "linear", - "autorange": false, - "range": [0, 0] + "autorange": true, + "range": null } } } diff --git a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-with-second-axis.json b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-with-second-axis.json index 7df58dfa02..3e9379cfdc 100644 --- a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-with-second-axis.json +++ b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-with-second-axis.json @@ -9,7 +9,10 @@ "traceorder": "normal" } }, - "series": [{ "name": "a" }, { "name": "b", "yaxis": "y2" }] + "series": [ + { "name": "a" }, + { "name": "b", "yaxis": "y2" } + ] }, "output": { "layout": { @@ -31,15 +34,15 @@ "automargin": true, "title": null, "type": "linear", - "autorange": false, - "range": [0, 0] + "autorange": true, + "range": null }, "yaxis2": { "automargin": true, "title": null, "type": "linear", - "autorange": false, - "range": [0, 0], + "autorange": true, + "range": null, "overlaying": "y", "side": "right" } diff --git a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-with-stacking.json b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-with-stacking.json index 7081d89eac..beef4f243f 100644 --- a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-with-stacking.json +++ b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-with-stacking.json @@ -30,8 +30,8 @@ "automargin": true, "title": null, "type": "linear", - "autorange": false, - "range": [0, 0] + "autorange": true, + "range": null } } } diff --git a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-without-legend.json b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-without-legend.json index 97f971156c..529e216820 100644 --- a/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-without-legend.json +++ b/viz-lib/src/visualizations/chart/plotly/fixtures/prepareLayout/default-without-legend.json @@ -29,8 +29,8 @@ "automargin": true, "title": null, "type": "linear", - "autorange": false, - "range": [0, 0] + "autorange": true, + "range": null } } } diff --git a/viz-lib/src/visualizations/chart/plotly/index.js b/viz-lib/src/visualizations/chart/plotly/index.js index 940ca8c6c8..6ebb37e7e1 100644 --- a/viz-lib/src/visualizations/chart/plotly/index.js +++ b/viz-lib/src/visualizations/chart/plotly/index.js @@ -8,8 +8,8 @@ import heatmap from "plotly.js/lib/heatmap"; import prepareData from "./prepareData"; import prepareLayout from "./prepareLayout"; import updateData from "./updateData"; -import updateLayout from "./updateLayout"; -import applyLayoutFixes from "./applyLayoutFixes"; +import updateYRanges from "./updateYRanges"; +import updateChartSize from "./updateChartSize"; import { prepareCustomChartData, createCustomChartRenderer } from "./customChartUtils"; Plotly.register([bar, pie, histogram, box, heatmap]); @@ -22,8 +22,8 @@ export { prepareData, prepareLayout, updateData, - updateLayout, - applyLayoutFixes, + updateYRanges, + updateChartSize, prepareCustomChartData, createCustomChartRenderer, }; diff --git a/viz-lib/src/visualizations/chart/plotly/prepareLayout.js b/viz-lib/src/visualizations/chart/plotly/prepareLayout.js index 1b2e35deee..fcc9228155 100644 --- a/viz-lib/src/visualizations/chart/plotly/prepareLayout.js +++ b/viz-lib/src/visualizations/chart/plotly/prepareLayout.js @@ -1,6 +1,5 @@ import { isObject, isUndefined, filter, map } from "lodash"; import { getPieDimensions } from "./preparePieData"; -import { calculateAxisRange } from "./utils"; function getAxisTitle(axis) { return isObject(axis.title) ? axis.title.text : null; @@ -39,13 +38,13 @@ function prepareXAxis(axisOptions, additionalOptions) { return axis; } -function prepareYAxis(axisOptions, additionalOptions, data) { +function prepareYAxis(axisOptions) { return { title: getAxisTitle(axisOptions), type: getAxisScaleType(axisOptions), automargin: true, - autorange: false, - range: calculateAxisRange(data, axisOptions.rangeMin, axisOptions.rangeMax), + autorange: true, + range: null, }; } @@ -77,14 +76,13 @@ function preparePieLayout(layout, options, data) { } function prepareDefaultLayout(layout, options, data) { - const ySeries = data.filter(s => s.yaxis !== "y2"); const y2Series = data.filter(s => s.yaxis === "y2"); layout.xaxis = prepareXAxis(options.xAxis, options); - layout.yaxis = prepareYAxis(options.yAxis[0], options, ySeries); + layout.yaxis = prepareYAxis(options.yAxis[0]); if (y2Series.length > 0) { - layout.yaxis2 = prepareYAxis(options.yAxis[1], options, y2Series); + layout.yaxis2 = prepareYAxis(options.yAxis[1]); layout.yaxis2.overlaying = "y"; layout.yaxis2.side = "right"; } diff --git a/viz-lib/src/visualizations/chart/plotly/applyLayoutFixes.js b/viz-lib/src/visualizations/chart/plotly/updateChartSize.js similarity index 55% rename from viz-lib/src/visualizations/chart/plotly/applyLayoutFixes.js rename to viz-lib/src/visualizations/chart/plotly/updateChartSize.js index 365dcd812c..8e3fb8fc92 100644 --- a/viz-lib/src/visualizations/chart/plotly/applyLayoutFixes.js +++ b/viz-lib/src/visualizations/chart/plotly/updateChartSize.js @@ -14,7 +14,7 @@ function fixLegendContainer(plotlyElement) { } } -function placeLegendNextToPlot(plotlyElement, layout, updatePlot) { +function placeLegendNextToPlot(plotlyElement, layout) { const transformName = find( ["transform", "WebkitTransform", "MozTransform", "MsTransform", "OTransform"], prop => prop in plotlyElement.style @@ -35,16 +35,16 @@ function placeLegendNextToPlot(plotlyElement, layout, updatePlot) { legend.style[transformName] = null; } - updatePlot(plotlyElement, pick(layout, ["width", "height", "legend"])); + return [pick(layout, ["width", "height", "legend"]), null]; // no further updates } -function placeLegendBelowPlot(plotlyElement, layout, updatePlot) { +function placeLegendBelowPlot(plotlyElement, layout) { const transformName = find( ["transform", "WebkitTransform", "MozTransform", "MsTransform", "OTransform"], prop => prop in plotlyElement.style ); - // Save current `layout.height` value because `updatePlot().then(...)` handler may be called multiple + // Save current `layout.height` value because `Plotly.relayout().then(...)` handler may be called multiple // times within single update, and since the handler mutates `layout` object - it may lead to bugs const layoutHeight = layout.height; @@ -71,53 +71,64 @@ function placeLegendBelowPlot(plotlyElement, layout, updatePlot) { // position legend outside of it fixLegendContainer(plotlyElement); - updatePlot(plotlyElement, pick(layout, ["width", "height", "legend"])).then(() => { - const legend = plotlyElement.querySelector(".legend"); // eslint-disable-line no-shadow - if (legend) { - // compute real height of legend - items may be split into few columnns, - // also scrollbar may be shown - const bounds = legend.getBoundingClientRect(); - - // here we have two values: - // 1. height of plot container excluding height of legend items; - // it may be any value between 0 and plot container's height; - // 2. half of plot containers height. Legend cannot be larger than - // plot; if legend is too large, plotly will reduce it's height and - // show a scrollbar; in this case, height of plot === height of legend, - // so we can split container's height half by half between them. - layout.height = Math.floor(Math.max(layoutHeight / 2, layoutHeight - (bounds.bottom - bounds.top))); - // offset the legend - legend.style[transformName] = "translate(0, " + layout.height + "px)"; - updatePlot(plotlyElement, pick(layout, ["height"])); - } - }); + return [ + pick(layout, ["width", "height", "legend"]), + () => { + const legend = plotlyElement.querySelector(".legend"); // eslint-disable-line no-shadow + if (legend) { + // compute real height of legend - items may be split into few columnns, + // also scrollbar may be shown + const bounds = legend.getBoundingClientRect(); + + // here we have two values: + // 1. height of plot container excluding height of legend items; + // it may be any value between 0 and plot container's height; + // 2. half of plot containers height. Legend cannot be larger than + // plot; if legend is too large, plotly will reduce it's height and + // show a scrollbar; in this case, height of plot === height of legend, + // so we can split container's height half by half between them. + layout.height = Math.floor(Math.max(layoutHeight / 2, layoutHeight - (bounds.bottom - bounds.top))); + // offset the legend + legend.style[transformName] = "translate(0, " + layout.height + "px)"; + return [pick(layout, ["height"]), null]; // no further updates + } + }, + ]; } -function placeLegendAuto(plotlyElement, layout, updatePlot) { +function placeLegendAuto(plotlyElement, layout) { if (layout.width <= 600) { - placeLegendBelowPlot(plotlyElement, layout, updatePlot); + return placeLegendBelowPlot(plotlyElement, layout); } else { - placeLegendNextToPlot(plotlyElement, layout, updatePlot); + return placeLegendNextToPlot(plotlyElement, layout); } } -export default function applyLayoutFixes(plotlyElement, layout, options, updatePlot) { +export default function updateChartSize(plotlyElement, layout, options) { // update layout size to plot container // plot size should be at least 5x5px layout.width = Math.max(5, Math.floor(plotlyElement.offsetWidth)); layout.height = Math.max(5, Math.floor(plotlyElement.offsetHeight)); + const [previousWidth, previousHeight] = plotlyElement.__previousSize || []; + + if (layout.width === previousWidth && layout.height === previousHeight) { + return; + } + + plotlyElement.__previousSize = [layout.width, layout.height]; + if (options.legend.enabled) { switch (options.legend.placement) { case "auto": - placeLegendAuto(plotlyElement, layout, updatePlot); + return placeLegendAuto(plotlyElement, layout); break; case "below": - placeLegendBelowPlot(plotlyElement, layout, updatePlot); + return placeLegendBelowPlot(plotlyElement, layout); break; // no default } } else { - updatePlot(plotlyElement, pick(layout, ["width", "height"])); + return [pick(layout, ["width", "height"]), null]; // no further updates } } diff --git a/viz-lib/src/visualizations/chart/plotly/updateLayout.js b/viz-lib/src/visualizations/chart/plotly/updateLayout.js deleted file mode 100644 index 62d50f7f2e..0000000000 --- a/viz-lib/src/visualizations/chart/plotly/updateLayout.js +++ /dev/null @@ -1,18 +0,0 @@ -import { isObject, filter } from "lodash"; -import { calculateAxisRange } from "./utils"; - -export default function updateLayout(layout, options, seriesList) { - // Use only visible series - const visibleSeriesList = filter(seriesList, s => s.visible === true); - - if (isObject(layout.yaxis)) { - const series = visibleSeriesList.filter(s => s.yaxis !== "y2"); - const axisOptions = options.yAxis[0]; - layout.yaxis.range = calculateAxisRange(series, axisOptions.rangeMin, axisOptions.rangeMax); - } - if (isObject(layout.yaxis2)) { - const series = visibleSeriesList.filter(s => s.yaxis === "y2"); - const axisOptions = options.yAxis[1]; - layout.yaxis2.range = calculateAxisRange(series, axisOptions.rangeMin, axisOptions.rangeMax); - } -} diff --git a/viz-lib/src/visualizations/chart/plotly/updateYRanges.js b/viz-lib/src/visualizations/chart/plotly/updateYRanges.js new file mode 100644 index 0000000000..630ba4572d --- /dev/null +++ b/viz-lib/src/visualizations/chart/plotly/updateYRanges.js @@ -0,0 +1,44 @@ +import { isObject, isNumber } from "lodash"; + +function calculateAxisRange(range, min, max) { + return [isNumber(min) ? min : range[0], isNumber(max) ? max : range[1]]; +} + +export default function updateYRanges(plotlyElement, layout, options) { + const updates = {}; + if (isObject(layout.yaxis)) { + updates.yaxis = { + ...layout.yaxis, + autorange: true, + range: null, + }; + } + if (isObject(layout.yaxis2)) { + updates.yaxis2 = { + ...layout.yaxis2, + autorange: true, + range: null, + }; + } + + return [ + updates, + () => { + if (isObject(layout.yaxis)) { + const axisOptions = options.yAxis[0]; + const defaultRange = plotlyElement.layout.yaxis.range; + updates.yaxis.autorange = false; + updates.yaxis.range = calculateAxisRange(defaultRange, axisOptions.rangeMin, axisOptions.rangeMax); + } + + if (isObject(layout.yaxis2)) { + const axisOptions = options.yAxis[1]; + const defaultRange = plotlyElement.layout.yaxis2.range; + updates.yaxis2.autorange = false; + updates.yaxis2.range = calculateAxisRange(defaultRange, axisOptions.rangeMin, axisOptions.rangeMax); + } + + return [updates, null]; // no further updates + }, + ]; +} diff --git a/viz-lib/src/visualizations/chart/plotly/utils.js b/viz-lib/src/visualizations/chart/plotly/utils.js index a0bb9d0e98..71809fde38 100644 --- a/viz-lib/src/visualizations/chart/plotly/utils.js +++ b/viz-lib/src/visualizations/chart/plotly/utils.js @@ -1,4 +1,4 @@ -import { isNumber, isUndefined, map, max, min } from "lodash"; +import { isUndefined } from "lodash"; import moment from "moment"; import plotlyCleanNumber from "plotly.js/src/lib/clean_number"; @@ -23,19 +23,3 @@ export function normalizeValue(value, axisType, dateTimeFormat = "YYYY-MM-DD HH: } return value; } - -export function calculateAxisRange(seriesList, minValue, maxValue) { - if (!isNumber(minValue)) { - minValue = Math.min(0, min(map(seriesList, series => min(series.y))) || 0); - } - if (!isNumber(maxValue)) { - maxValue = max(map(seriesList, series => max(series.y))) || 0; - } - - // Expand range a little bit to ensure tha plot is fully visible and not cut on edges. - // Plotly does similar thing when autorange enabled - const range = maxValue - minValue; - const threshold = Math.min(0.25, range * 0.01); - - return [minValue - threshold, maxValue + threshold]; -} From 7f98d7b694a7abb960287d109bb5702672bdec5f Mon Sep 17 00:00:00 2001 From: Omer Lachish Date: Thu, 23 Jul 2020 11:05:20 +0300 Subject: [PATCH 10/49] Load extensions on db init (#5062) * Only try to create tables and stamp DB if not tables exist already. * load extensions when creating the database --- redash/cli/database.py | 30 ++++++++++++++++++++++++----- redash/settings/dynamic_settings.py | 4 ++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/redash/cli/database.py b/redash/cli/database.py index ce55b73c6f..777a04637b 100644 --- a/redash/cli/database.py +++ b/redash/cli/database.py @@ -8,6 +8,7 @@ from sqlalchemy.sql import select from sqlalchemy_utils.types.encrypted.encrypted_type import FernetEngine +from redash import settings from redash.models.base import Column from redash.models.types import EncryptedConfiguration from redash.utils.configuration import ConfigurationContainer @@ -26,6 +27,19 @@ def _wait_for_db_connection(db): retried = True + +def is_db_empty(): + from redash.models import db + + table_names = sqlalchemy.inspect(db.get_engine()).get_table_names() + return len(table_names) == 0 + + +def load_extensions(db): + with db.engine.connect() as connection: + for extension in settings.dynamic_settings.database_extensions: + connection.execute(f'CREATE EXTENSION IF NOT EXISTS "{extension}";') + @manager.command() def create_tables(): @@ -33,12 +47,18 @@ def create_tables(): from redash.models import db _wait_for_db_connection(db) - # To create triggers for searchable models, we need to call configure_mappers(). - sqlalchemy.orm.configure_mappers() - db.create_all() - # Need to mark current DB as up to date - stamp() + # We need to make sure we run this only if the DB is empty, because otherwise calling + # stamp() will stamp it with the latest migration value and migrations won't run. + if is_db_empty(): + load_extensions(db) + + # To create triggers for searchable models, we need to call configure_mappers(). + sqlalchemy.orm.configure_mappers() + db.create_all() + + # Need to mark current DB as up to date + stamp() @manager.command() diff --git a/redash/settings/dynamic_settings.py b/redash/settings/dynamic_settings.py index 836153ce36..1f15712238 100644 --- a/redash/settings/dynamic_settings.py +++ b/redash/settings/dynamic_settings.py @@ -57,3 +57,7 @@ def database_key_definitions(default): ) return definitions + +# Since you can define custom primary key types using `database_key_definitions`, you may want to load certain extensions when creating the database. +# To do so, simply add the name of the extension you'd like to load to this list. +database_extensions = [] \ No newline at end of file From fd76a2ecfb4b14f97df0775384e8784790323d86 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 23 Jul 2020 06:52:09 -0300 Subject: [PATCH 11/49] Add Column Type to Databricks schema browser (#5052) * Add Column Type to Databricks schema browser * Map schema columns to be an object * Format pg with Black * Add data_type for Postgres --- .../app/assets/less/inc/schema-browser.less | 7 + .../app/components/queries/QueryEditor/ace.js | 12 +- .../components/queries/QueryEditor/index.jsx | 9 +- .../app/components/queries/SchemaBrowser.jsx | 42 +++--- client/app/services/data-source.js | 25 ++-- redash/models/__init__.py | 2 +- redash/query_runner/databricks.py | 2 +- redash/query_runner/pg.py | 124 ++++++++++-------- 8 files changed, 131 insertions(+), 92 deletions(-) diff --git a/client/app/assets/less/inc/schema-browser.less b/client/app/assets/less/inc/schema-browser.less index 2f25f78665..3f2e66f28d 100644 --- a/client/app/assets/less/inc/schema-browser.less +++ b/client/app/assets/less/inc/schema-browser.less @@ -66,6 +66,13 @@ div.table-name { position: relative; height: 18px; + .column-type { + color: fade(@text-color, 80%); + font-size: 10px; + margin-left: 2px; + text-transform: uppercase; + } + .copy-to-editor { display: none; } diff --git a/client/app/components/queries/QueryEditor/ace.js b/client/app/components/queries/QueryEditor/ace.js index 5e405a0a91..b011ff14c4 100644 --- a/client/app/components/queries/QueryEditor/ace.js +++ b/client/app/components/queries/QueryEditor/ace.js @@ -1,4 +1,4 @@ -import { isNil, map } from "lodash"; +import { capitalize, isNil, map, get } from "lodash"; import AceEditor from "react-ace"; import ace from "ace-builds"; @@ -30,11 +30,12 @@ defineDummySnippets("yaml"); function buildTableColumnKeywords(table) { const keywords = []; table.columns.forEach(column => { + const columnName = get(column, "name"); keywords.push({ - name: `${table.name}.${column}`, - value: `${table.name}.${column}`, + name: `${table.name}.${columnName}`, + value: `${table.name}.${columnName}`, score: 100, - meta: "Column", + meta: capitalize(get(column, "type", "Column")), }); }); return keywords; @@ -54,7 +55,8 @@ function buildKeywordsFromSchema(schema) { }); tableColumnKeywords[table.name] = buildTableColumnKeywords(table); table.columns.forEach(c => { - columnKeywords[c] = "Column"; + const columnName = get(c, "name", c); + columnKeywords[columnName] = capitalize(get(c, "type", "Column")); }); }); diff --git a/client/app/components/queries/QueryEditor/index.jsx b/client/app/components/queries/QueryEditor/index.jsx index 9c1b978fb0..9d552ea256 100644 --- a/client/app/components/queries/QueryEditor/index.jsx +++ b/client/app/components/queries/QueryEditor/index.jsx @@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState, useCallback, useImperativeHandle } import PropTypes from "prop-types"; import cx from "classnames"; import { AceEditor, snippetsModule, updateSchemaCompleter } from "./ace"; +import { SchemaItemType } from "@/components/queries/SchemaBrowser"; import resizeObserver from "@/services/resizeObserver"; import QuerySnippet from "@/services/query-snippet"; @@ -157,13 +158,7 @@ QueryEditor.propTypes = { syntax: PropTypes.string, value: PropTypes.string, autocompleteEnabled: PropTypes.bool, - schema: PropTypes.arrayOf( - PropTypes.shape({ - name: PropTypes.string.isRequired, - size: PropTypes.number, - columns: PropTypes.arrayOf(PropTypes.string).isRequired, - }) - ), + schema: PropTypes.arrayOf(SchemaItemType), onChange: PropTypes.func, onSelectionChange: PropTypes.func, }; diff --git a/client/app/components/queries/SchemaBrowser.jsx b/client/app/components/queries/SchemaBrowser.jsx index 6eb0be502c..67df57a3c0 100644 --- a/client/app/components/queries/SchemaBrowser.jsx +++ b/client/app/components/queries/SchemaBrowser.jsx @@ -1,4 +1,4 @@ -import { isNil, map, filter, some, includes } from "lodash"; +import { isNil, map, filter, some, includes, get } from "lodash"; import cx from "classnames"; import React, { useState, useCallback, useMemo, useEffect } from "react"; import PropTypes from "prop-types"; @@ -12,10 +12,15 @@ import useDataSourceSchema from "@/pages/queries/hooks/useDataSourceSchema"; import useImmutableCallback from "@/lib/hooks/useImmutableCallback"; import LoadingState from "../items-list/components/LoadingState"; -const SchemaItemType = PropTypes.shape({ +const SchemaItemColumnType = PropTypes.shape({ + name: PropTypes.string.isRequired, + type: PropTypes.string, +}); + +export const SchemaItemType = PropTypes.shape({ name: PropTypes.string.isRequired, size: PropTypes.number, - columns: PropTypes.arrayOf(PropTypes.string).isRequired, + columns: PropTypes.arrayOf(SchemaItemColumnType).isRequired, }); const schemaTableHeight = 22; @@ -51,16 +56,20 @@ function SchemaItem({ item, expanded, onToggle, onSelect, ...props }) {
{expanded && (
- {map(item.columns, column => ( -
- {column} -