From 9594bcaaecc1204d0b183dd7411e30cb926d322f Mon Sep 17 00:00:00 2001 From: Matthias Courville Date: Mon, 21 Mar 2022 13:47:10 -0700 Subject: [PATCH 1/5] Added support for createStore to accept a reducer function as the first argument --- src/createStore.js | 32 ++++++++++++++++++------ src/tests/createStore.test.js | 47 +++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/createStore.js b/src/createStore.js index e81aee0..1146812 100644 --- a/src/createStore.js +++ b/src/createStore.js @@ -1,18 +1,36 @@ const { createStore: reduxCreateStore, combineReducers } = require('redux') -module.exports = (initialReducers = {}, ...args) => { - if (typeof initialReducers !== "object") { - console.error({initialReducers, args}) - throw new Error("initialReducers should be an object suitable to be passed to combineReducers") +module.exports = (initialReducer = {}, ...args) => { + let reducers + let combinedReducer + let rootReducer + + if (typeof initialReducer !== "object" && typeof initialReducer !== "function") { + console.error({initialReducer, args}) + throw new Error("initialReducer should be a reducing function (\"uncombined\") or an object suitable to be passed to combineReducers") + } else if (typeof initialReducer === "function") { + if (initialReducer.name === "combination") { + console.error({initialReducer, args}) + throw new Error("initialReducer should be a reducing function (\"uncombined\") or an object suitable to be passed to combineReducers") + } else { + reducers = {_stub_: (s) => s || 0} + rootReducer = (state, action) => { + const intermediateState = combinedReducer(state, action) + return initialReducer(intermediateState, action) + } + } + } else { + reducers = {...initialReducer, _stub_: (s) => s || 0} } - const reducers = {...initialReducers, _stub_: (s) => s || 0} - const store = reduxCreateStore(combineReducers(reducers), ...args) + combinedReducer = combineReducers(reducers); + const store = reduxCreateStore(rootReducer || combinedReducer, ...args) store.injectReducer = (key, reducer) => { if (reducers[key]) console.warn(`injectReducer: replacing reducer for key '${key}'`); reducers[key] = reducer - store.replaceReducer(combineReducers(reducers)) + combinedReducer = combineReducers(reducers); + store.replaceReducer(rootReducer || combinedReducer) } return store diff --git a/src/tests/createStore.test.js b/src/tests/createStore.test.js index bb4ae73..8b9fff5 100644 --- a/src/tests/createStore.test.js +++ b/src/tests/createStore.test.js @@ -1,6 +1,49 @@ -import { getStore } from "../index"; +import renderer from 'react-test-renderer'; +import { Provider, setStore, getStore, createStore, createReduxModule } from "../index"; + +describe("support default createStore API", () => { + + const reducer = (state = { count: 0 }, action) => { + switch (action.type) { + case 'INCREMENT_COUNT': + return {...state, count: (state.count || 0) + 1} + default: + return state + } + } + + const store = setStore(createStore(reducer)) + + const [useCount, {incrementCount}] = createReduxModule('count', 0, { + incrementCount: (state) => state + 1, + }) + + const [useMessage, {setMessage}] = createReduxModule('message', 'Hello!', { + setMessage: (state, message) => message, + }) + + it("initialize state", () => { + expect(store.getState().count).toEqual(0); + expect(store.getState().message).toEqual('Hello!'); + }) + + it("increment count with hook", () => { + renderer.act(() => {incrementCount()}) + expect(store.getState().count).toEqual(1); + }) + + it("increment count with dispatch", () => { + renderer.act(() => {store.dispatch({type: 'INCREMENT_COUNT'})}) + expect(store.getState().count).toEqual(2); + }) + + it("set slice which is not part of initial state", () => { + renderer.act(() => {setMessage('Goodbye!')}) + expect(store.getState().message).toEqual('Goodbye!'); + }) +}); it("injectReducer key must be unique", () => { getStore().injectReducer("myKey", () => 1); getStore().injectReducer("myKey", () => 2); // second call OK -}); +}); \ No newline at end of file From 065485d2746b8504856f3cc3f16471bcce25debb Mon Sep 17 00:00:00 2001 From: Matthias Courville Date: Tue, 22 Mar 2022 09:08:20 -0700 Subject: [PATCH 2/5] Added support for combined reducer at initialization --- src/createStore.js | 67 ++++++++++++++++++++++-------- src/tests/createStore.test.js | 77 +++++++++++++++++++++++++++++------ 2 files changed, 114 insertions(+), 30 deletions(-) diff --git a/src/createStore.js b/src/createStore.js index 1146812..ae1d5d9 100644 --- a/src/createStore.js +++ b/src/createStore.js @@ -1,35 +1,66 @@ const { createStore: reduxCreateStore, combineReducers } = require('redux') +const getRootReducerSlices = (state, reducers, initialReducer) => { + const initialSlices = initialReducer ? initialReducer({}, '') : {} + const initialKeys = Object.keys(initialSlices) + const knownKeys = Object.keys(reducers) + const slices = { + known: {}, + unknown: {} + } + + for (const key of Object.keys(state)) { + if (knownKeys.includes(key)) { + slices.known[key] = state[key] + } else { + slices.unknown[key] = state[key] + } + + if (initialKeys.includes(key)) { + slices.unknown[key] = state[key] + } + } + + return slices +} + module.exports = (initialReducer = {}, ...args) => { let reducers - let combinedReducer let rootReducer - - if (typeof initialReducer !== "object" && typeof initialReducer !== "function") { - console.error({initialReducer, args}) - throw new Error("initialReducer should be a reducing function (\"uncombined\") or an object suitable to be passed to combineReducers") + + if (typeof initialReducer === "object") { + reducers = {...initialReducer, _stub_: (s) => s || 0} } else if (typeof initialReducer === "function") { - if (initialReducer.name === "combination") { - console.error({initialReducer, args}) - throw new Error("initialReducer should be a reducing function (\"uncombined\") or an object suitable to be passed to combineReducers") + reducers = {_stub_: (s) => s || 0} + if (initialReducer.name === 'combination') { + rootReducer = (state = {}, action) => { + const slices = getRootReducerSlices(state, reducers, initialReducer) + const intermediateState = combinedReducer(slices.known, action) + for (const key of Object.keys(intermediateState)) { + if (slices.unknown.hasOwnProperty(key)) { + slices.unknown[key] = intermediateState[key] + } + } + return {...intermediateState, ...initialReducer(slices.unknown, action)} + } } else { - reducers = {_stub_: (s) => s || 0} - rootReducer = (state, action) => { - const intermediateState = combinedReducer(state, action) - return initialReducer(intermediateState, action) + rootReducer = (state = {}, action) => { + const slices = getRootReducerSlices(state, reducers) + const intermediateState = combinedReducer(slices.known, action) + return initialReducer({...state, ...intermediateState}, action) } } } else { - reducers = {...initialReducer, _stub_: (s) => s || 0} + console.error({initialReducer, args}) + throw new Error("initialReducer should be an object suitable to be passed to combineReducers or a reducing function (\"uncombined\")") } - combinedReducer = combineReducers(reducers); - const store = reduxCreateStore(rootReducer || combinedReducer, ...args) - + let combinedReducer = combineReducers(reducers) + const store = reduxCreateStore(rootReducer || combinedReducer) store.injectReducer = (key, reducer) => { - if (reducers[key]) console.warn(`injectReducer: replacing reducer for key '${key}'`); + if (reducers[key]) console.warn(`injectReducer: replacing reducer for key '${key}'`) reducers[key] = reducer - combinedReducer = combineReducers(reducers); + combinedReducer = combineReducers(reducers) store.replaceReducer(rootReducer || combinedReducer) } diff --git a/src/tests/createStore.test.js b/src/tests/createStore.test.js index 8b9fff5..ebd8aef 100644 --- a/src/tests/createStore.test.js +++ b/src/tests/createStore.test.js @@ -1,9 +1,10 @@ import renderer from 'react-test-renderer'; +const { combineReducers } = require('redux') import { Provider, setStore, getStore, createStore, createReduxModule } from "../index"; describe("support default createStore API", () => { - const reducer = (state = { count: 0 }, action) => { + const reducer = (state, action) => { switch (action.type) { case 'INCREMENT_COUNT': return {...state, count: (state.count || 0) + 1} @@ -14,33 +15,85 @@ describe("support default createStore API", () => { const store = setStore(createStore(reducer)) - const [useCount, {incrementCount}] = createReduxModule('count', 0, { - incrementCount: (state) => state + 1, - }) + const [useCount, {increment, decrement}] = createReduxModule('count', 5, { + increment: (state) => state + 1, + decrement: (state) => state - 1, + }, store) const [useMessage, {setMessage}] = createReduxModule('message', 'Hello!', { setMessage: (state, message) => message, - }) + }, store) it("initialize state", () => { - expect(store.getState().count).toEqual(0); - expect(store.getState().message).toEqual('Hello!'); + expect(store.getState().count).toEqual(5) + expect(store.getState().message).toEqual('Hello!') + }) + + it("increment count with dispatch", () => { + renderer.act(() => {store.dispatch({type: 'INCREMENT_COUNT'})}) + expect(store.getState().count).toEqual(6); }) it("increment count with hook", () => { - renderer.act(() => {incrementCount()}) - expect(store.getState().count).toEqual(1); + renderer.act(() => {increment()}) + expect(store.getState().count).toEqual(7); + }) + + it("set message with hook", () => { + renderer.act(() => {setMessage('Goodbye!')}) + expect(store.getState().message).toEqual('Goodbye!'); + }) +}); + + +describe("support default createStore API with combined reducers", () => { + + const countReducer = (state = 0, action) => { + switch (action.type) { + case 'INCREMENT_COUNT': + return state + 1 + default: + return state + } + } + + const messageReducer = (state = 'Hello!', action) => { + switch (action.type) { + case 'SET_MESSAGE': + return state = action.payload + default: + return state + } + } + + const combinedReducer = combineReducers({count: countReducer, message: messageReducer}) + const store = createStore(combinedReducer) + + const [useCount, {increment, decrement}] = createReduxModule('count', 5, { + increment: (state) => state + 1, + decrement: (state) => state - 1, + }, store) + + it("initialize state", () => { + // Initial state set with createReduxModule is not applied if reducer already exists + expect(store.getState().count).toEqual(0) + expect(store.getState().message).toEqual('Hello!') }) it("increment count with dispatch", () => { renderer.act(() => {store.dispatch({type: 'INCREMENT_COUNT'})}) - expect(store.getState().count).toEqual(2); + expect(store.getState().count).toEqual(1); }) - it("set slice which is not part of initial state", () => { - renderer.act(() => {setMessage('Goodbye!')}) + it("set message with dispatch", () => { + renderer.act(() => {store.dispatch({type: 'SET_MESSAGE', payload: 'Goodbye!'})}) expect(store.getState().message).toEqual('Goodbye!'); }) + + it("increment count with hook", () => { + renderer.act(() => {increment()}) + expect(store.getState().count).toEqual(2); + }) }); it("injectReducer key must be unique", () => { From fd58384d56334265d4b01c480c46e3b1d279bea2 Mon Sep 17 00:00:00 2001 From: Matthias Courville Date: Tue, 22 Mar 2022 15:25:32 -0700 Subject: [PATCH 3/5] Added example for simple migration --- examples/migration/.gitignore | 2 + examples/migration/README.md | 3 + examples/migration/package-lock.json | 1667 ++++++++++++++++++++++++++ examples/migration/package.json | 13 + examples/migration/src/app.js | 52 + examples/migration/src/index.html | 20 + examples/migration/src/styles.css | 73 ++ src/tests/createStore.test.js | 2 +- 8 files changed, 1831 insertions(+), 1 deletion(-) create mode 100644 examples/migration/.gitignore create mode 100644 examples/migration/README.md create mode 100644 examples/migration/package-lock.json create mode 100644 examples/migration/package.json create mode 100644 examples/migration/src/app.js create mode 100644 examples/migration/src/index.html create mode 100644 examples/migration/src/styles.css diff --git a/examples/migration/.gitignore b/examples/migration/.gitignore new file mode 100644 index 0000000..509bb0b --- /dev/null +++ b/examples/migration/.gitignore @@ -0,0 +1,2 @@ +.parcel-cache/ +dist/ \ No newline at end of file diff --git a/examples/migration/README.md b/examples/migration/README.md new file mode 100644 index 0000000..ac910d8 --- /dev/null +++ b/examples/migration/README.md @@ -0,0 +1,3 @@ +# Migration example + +Example showing how to add H4R to an existing app \ No newline at end of file diff --git a/examples/migration/package-lock.json b/examples/migration/package-lock.json new file mode 100644 index 0000000..63f0994 --- /dev/null +++ b/examples/migration/package-lock.json @@ -0,0 +1,1667 @@ +{ + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/runtime": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz", + "integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@parcel/bundler-default": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.4.0.tgz", + "integrity": "sha512-RaXlxo0M51739Ko3bsOJpDBZlJ+cqkDoBTozNeSc65jS2TMBIBWLMapm8095qmty39OrgYNhzjgPiIlKDS/LWA==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.4.0.tgz", + "integrity": "sha512-oOudoAafrCAHQY0zkU7gVHG1pAGBUz9rht7Tx4WupTmAH0O0F5UnZs6XbjoBJaPHg+CYUXK7v9wQcrNA72E3GA==", + "dev": true, + "requires": { + "@parcel/fs": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/utils": "2.4.0", + "lmdb": "2.2.4" + } + }, + "@parcel/codeframe": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.4.0.tgz", + "integrity": "sha512-PJ3W9Z0sjoS2CANyo50c+LEr9IRZrtu0WsVPSYZ5ZYRuSXrSa/6PcAlnkyDk2+hi7Od8ncT2bmDexl0Oar3Jyg==", + "dev": true, + "requires": { + "chalk": "^4.1.0" + } + }, + "@parcel/compressor-raw": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.4.0.tgz", + "integrity": "sha512-ZErX14fTc0gKIgtnuqW7Clfln4dpXWfUaJQQIf5C3x/LkpUeEhdXeKntkvSxOddDk2JpIKDwqzAxEMZUnDo4Nw==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0" + } + }, + "@parcel/config-default": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.4.0.tgz", + "integrity": "sha512-pFOPBXPO6HGqNWTLkcK5i8haMOrRgUouUhcWPGWDpN9IPUYFK2E/O1E/uyMjIA1mSL3FnazI+jJwZ45NhKPpIA==", + "dev": true, + "requires": { + "@parcel/bundler-default": "2.4.0", + "@parcel/compressor-raw": "2.4.0", + "@parcel/namer-default": "2.4.0", + "@parcel/optimizer-css": "2.4.0", + "@parcel/optimizer-htmlnano": "2.4.0", + "@parcel/optimizer-image": "2.4.0", + "@parcel/optimizer-svgo": "2.4.0", + "@parcel/optimizer-terser": "2.4.0", + "@parcel/packager-css": "2.4.0", + "@parcel/packager-html": "2.4.0", + "@parcel/packager-js": "2.4.0", + "@parcel/packager-raw": "2.4.0", + "@parcel/packager-svg": "2.4.0", + "@parcel/reporter-dev-server": "2.4.0", + "@parcel/resolver-default": "2.4.0", + "@parcel/runtime-browser-hmr": "2.4.0", + "@parcel/runtime-js": "2.4.0", + "@parcel/runtime-react-refresh": "2.4.0", + "@parcel/runtime-service-worker": "2.4.0", + "@parcel/transformer-babel": "2.4.0", + "@parcel/transformer-css": "2.4.0", + "@parcel/transformer-html": "2.4.0", + "@parcel/transformer-image": "2.4.0", + "@parcel/transformer-js": "2.4.0", + "@parcel/transformer-json": "2.4.0", + "@parcel/transformer-postcss": "2.4.0", + "@parcel/transformer-posthtml": "2.4.0", + "@parcel/transformer-raw": "2.4.0", + "@parcel/transformer-react-refresh-wrap": "2.4.0", + "@parcel/transformer-svg": "2.4.0" + } + }, + "@parcel/core": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.4.0.tgz", + "integrity": "sha512-EWZ2UWtIuwDc3fgsKyyTLpNNPoG8Yk2L117ICWF/+cqY8z/wJHm2KwLbeplDeq524shav0GJ9O4CemP3JPx0Nw==", + "dev": true, + "requires": { + "@parcel/cache": "2.4.0", + "@parcel/diagnostic": "2.4.0", + "@parcel/events": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/graph": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/package-manager": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "@parcel/workers": "2.4.0", + "abortcontroller-polyfill": "^1.1.9", + "base-x": "^3.0.8", + "browserslist": "^4.6.6", + "clone": "^2.1.1", + "dotenv": "^7.0.0", + "dotenv-expand": "^5.1.0", + "json-source-map": "^0.6.1", + "json5": "^2.2.0", + "msgpackr": "^1.5.4", + "nullthrows": "^1.1.1", + "semver": "^5.7.1" + } + }, + "@parcel/css": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css/-/css-1.7.2.tgz", + "integrity": "sha512-OcdGio5QCvshOJGXaqICC93yMDCi1baZ3yK/xHbKmu9R4p3IBp9+/hmjg5ZkfmJLvqsrguZ1JJndoSXITxPxpg==", + "dev": true, + "requires": { + "@parcel/css-darwin-arm64": "1.7.2", + "@parcel/css-darwin-x64": "1.7.2", + "@parcel/css-linux-arm-gnueabihf": "1.7.2", + "@parcel/css-linux-arm64-gnu": "1.7.2", + "@parcel/css-linux-arm64-musl": "1.7.2", + "@parcel/css-linux-x64-gnu": "1.7.2", + "@parcel/css-linux-x64-musl": "1.7.2", + "@parcel/css-win32-x64-msvc": "1.7.2", + "detect-libc": "^1.0.3" + } + }, + "@parcel/css-darwin-arm64": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css-darwin-arm64/-/css-darwin-arm64-1.7.2.tgz", + "integrity": "sha512-i0b8n8FF+iSK8cLOQhzxXZbbWAGTRLYih4W7Jim4QOerTBvl0zmBajua0hst+phuDDgSO5GKm1/80X+7v8VW+g==", + "dev": true, + "optional": true + }, + "@parcel/css-darwin-x64": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css-darwin-x64/-/css-darwin-x64-1.7.2.tgz", + "integrity": "sha512-RsidKHrUhOp9wSlyBOxBTPcskh/QRtUV0uOVhHVLZtr7ebWT7L0T6wZJGX3vpTewgwIPB66IjJCE8ovdJLeMEg==", + "dev": true, + "optional": true + }, + "@parcel/css-linux-arm-gnueabihf": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css-linux-arm-gnueabihf/-/css-linux-arm-gnueabihf-1.7.2.tgz", + "integrity": "sha512-NF6lvp2PDWqwUB16z1XQECyIIjO9EB6J9tMleLo1l6Set9nIaLRl3Jl06f3lFSBhxWQBqZ3Gr9c/5gvLtNjRew==", + "dev": true, + "optional": true + }, + "@parcel/css-linux-arm64-gnu": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css-linux-arm64-gnu/-/css-linux-arm64-gnu-1.7.2.tgz", + "integrity": "sha512-sqSzj8eoTFJkajLIjCbb8qDXLwH+4CQU0c7598Dg8K/culVuGlGn5mwwgfSK/HIZq6Wt8SD5iG0HmtNAwrcpCw==", + "dev": true, + "optional": true + }, + "@parcel/css-linux-arm64-musl": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css-linux-arm64-musl/-/css-linux-arm64-musl-1.7.2.tgz", + "integrity": "sha512-XDnf5eY0O5exsMpv+hwtrxsi7vrm/kz2+JRar+7vNalxzFEc6xJhh/sRQw4XU7Qn9oCgJ/BDp58c6uDeQInEAQ==", + "dev": true, + "optional": true + }, + "@parcel/css-linux-x64-gnu": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css-linux-x64-gnu/-/css-linux-x64-gnu-1.7.2.tgz", + "integrity": "sha512-9c912OgRIR5i4Pffxh123fgcsGy0njcBD9di+ipb6RHi8ZQLhiUhbdMAXINHwJT/7pSds+RJGL6VNGP3KqSxCA==", + "dev": true, + "optional": true + }, + "@parcel/css-linux-x64-musl": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css-linux-x64-musl/-/css-linux-x64-musl-1.7.2.tgz", + "integrity": "sha512-D9ZEllB21G9PA9+f+jdOXh3qPeryg+6fGSe1dXfLvQ0yG41FeBQgbIpPabhLUCNEdHG11t43LkJT5RVuG/n6uw==", + "dev": true, + "optional": true + }, + "@parcel/css-win32-x64-msvc": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@parcel/css-win32-x64-msvc/-/css-win32-x64-msvc-1.7.2.tgz", + "integrity": "sha512-9j8fu0nSqVj2w1NusgLJX9/XP5ITQke5/eRn6/no9cx4GD2YDsuKchDIc2yVxxuGD0WrDECScEtuXEKEmmxjxw==", + "dev": true, + "optional": true + }, + "@parcel/diagnostic": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.4.0.tgz", + "integrity": "sha512-TjWO/b2zMFhub5ouwGjazMm7iAUvdmXBfWmjrg4TBhUbhoQwBnyWfvMDtAYo7PcvXfxVPgPZv86Nv6Ym5H6cHQ==", + "dev": true, + "requires": { + "json-source-map": "^0.6.1", + "nullthrows": "^1.1.1" + } + }, + "@parcel/events": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.4.0.tgz", + "integrity": "sha512-DEaEtFbhOhNAEmiXJ3MyF8Scq+sNDKiTyLax4lAC5/dpE5GvwfNnoD17C2+0gDuuDpdQkdHfXfvr50aYFt7jcw==", + "dev": true + }, + "@parcel/fs": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.4.0.tgz", + "integrity": "sha512-CnUlWGUJ52SJVQi8QnaAPPQZOADmHMV9D9aX9GLcDm5XLT3Em7vmesG4bNLdMLwzYuzAtenhcWmuRCACuYztHw==", + "dev": true, + "requires": { + "@parcel/fs-search": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "@parcel/watcher": "^2.0.0", + "@parcel/workers": "2.4.0" + } + }, + "@parcel/fs-search": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.4.0.tgz", + "integrity": "sha512-W/Vu6wbZk4wuB6AVdMkyymwh/S8Peed/PgJgSsApYD6lSTD315I6OuEdxZh3lWY+dqQdog/NJ7dvi/hdpH/Iqw==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3" + } + }, + "@parcel/graph": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.4.0.tgz", + "integrity": "sha512-5TZIAfDITkJCzgH4j4OQhnIvjV9IFwWqNBJanRl5QQTmKvdcODS3WbnK1SOJ+ZltcLVXMB+HNXmL0bX0tVolcw==", + "dev": true, + "requires": { + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/hash": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.4.0.tgz", + "integrity": "sha512-nB+wYNUhe6+G8M7vQhdeFXtpYJYwJgBHOPZ7Hd9O2jdlamWjDbw0t/u1dJbYvGJ8ZDtLDwiItawQVpuVdskQ9g==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3", + "xxhash-wasm": "^0.4.2" + } + }, + "@parcel/logger": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.4.0.tgz", + "integrity": "sha512-DqfU0Zcs/0a7VBk+MsjJ80C66w4kM9EbkO3G12NIyEjNeG50ayW2CE9rUuJ91JaM9j0NFM1P82eyLpQPFFaVPw==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/events": "2.4.0" + } + }, + "@parcel/markdown-ansi": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.4.0.tgz", + "integrity": "sha512-gPUP1xikxHiu2kFyPy35pfuVkFgAmcywO8YDQj7iYcB+k7l4QPpIYFYGXn2QADV4faf66ncMeTD4uYV8c0GqjQ==", + "dev": true, + "requires": { + "chalk": "^4.1.0" + } + }, + "@parcel/namer-default": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.4.0.tgz", + "integrity": "sha512-DfL+Gx0Tyoa0vsgRpNybXjuKbWNw8MTVpy7Dk7r0btfVsn1jy3SSwlxH4USf76gb00/pK6XBsMp9zn7Z8ePREQ==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/node-resolver-core": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.4.0.tgz", + "integrity": "sha512-qiN97XcfW2fYNoYuVEhNKuVPEJKj5ONQl0fqr/NEMmYvWz3bVKjgiXNJwW558elZvCI08gEbdxgyThpuFFQeKQ==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/optimizer-css": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.4.0.tgz", + "integrity": "sha512-LQmjjOGsHEHKTJqfHR2eJyhWhLXvHP0uOAU+qopBttYYlB2J/vMK9RYAye5cyAb8bQmV8wAdi2mq9rnt7FMSPw==", + "dev": true, + "requires": { + "@parcel/css": "^1.7.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/utils": "2.4.0", + "browserslist": "^4.6.6", + "nullthrows": "^1.1.1" + } + }, + "@parcel/optimizer-htmlnano": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.4.0.tgz", + "integrity": "sha512-02EbeElLgNOAYhGU7fFBahpoKrX5G/yzahpaoKB/ypScM4roSsAMBkGcluboR5L10YRsvfvJEpxvfGyDA3tPmw==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "htmlnano": "^2.0.0", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "svgo": "^2.4.0" + } + }, + "@parcel/optimizer-image": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.4.0.tgz", + "integrity": "sha512-Q4onaBMPkDyYxPzrb8ytBUftaQZFepj9dSUgq+ETuHDzkgia0tomDPfCqrw6ld0qvYyANzXTP5+LC4g0i5yh+A==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "@parcel/workers": "2.4.0", + "detect-libc": "^1.0.3" + } + }, + "@parcel/optimizer-svgo": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.4.0.tgz", + "integrity": "sha512-mwvGuCqVuNCAuMlp2maFE/Uz9ud1T1AuX0f6cCRczjFYiwZuIr/0iDdfFzSziOkVo1MRAGAZNa0dRR/UzCZtVg==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "svgo": "^2.4.0" + } + }, + "@parcel/optimizer-terser": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.4.0.tgz", + "integrity": "sha512-PdCgRgXNSY6R1HTV9VG2MHp1CgUbP5pslCyxvlbUmQAS6bvEpMOpn3qSd+U28o7mGE/qXIhvpDyi808sb+MEcg==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1", + "terser": "^5.2.0" + } + }, + "@parcel/package-manager": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.4.0.tgz", + "integrity": "sha512-21AEfAQnZbHRVViTn7QsPGe/CiGaFaDUH5f0m8qVC7fDjjhC8LM8blkqU72goaO9FbaLMadtEf2txhzly7h/bg==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "@parcel/workers": "2.4.0", + "semver": "^5.7.1" + } + }, + "@parcel/packager-css": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.4.0.tgz", + "integrity": "sha512-LmPDWzkXi60Oy3WrPF0jPKQxeTwW5hmNBgrcXJMHSu+VcXdaQZNzNxVzhnZkJUbDd2z9vAUrUGzdLh8TquC8iQ==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/packager-html": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.4.0.tgz", + "integrity": "sha512-OPMIQ1uHYQFpRPrsmm5BqONbAyzjlhVsPRAzHlcBrglG4BTUeOR2ow4MUKblHmVVqc3QHnfZG4nHHtFkeuNQ3A==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5" + } + }, + "@parcel/packager-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.4.0.tgz", + "integrity": "sha512-cfslIH43CJFgBS9PmdFaSnbInMCoejsFCnxtJa2GeUpjCXSfelPRp0OPx7m8n+fap4czftPhoxBALeDUElOZGQ==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/utils": "2.4.0", + "globals": "^13.2.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/packager-raw": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.4.0.tgz", + "integrity": "sha512-SFfw7chMFITj3J26ZVDJxbO6xwtPFcFBm1js8cwWMgzwuwS6CEc43k5+Abj+2/EqHU9kNJU9eWV5vT6lQwf3HA==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0" + } + }, + "@parcel/packager-svg": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.4.0.tgz", + "integrity": "sha512-DwkgrdLEQop+tu9Ocr1ZaadmpsbSgVruJPr80xq1LaB0Jiwrl9HjHStMNH1laNFueK1yydxhnj9C2JQfW28qag==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "posthtml": "^0.16.4" + } + }, + "@parcel/plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.4.0.tgz", + "integrity": "sha512-ehFUAL2+h27Lv+cYbbXA74UGy8C+eglUjcpvASOOjVRFuD6poMAMliKkKAXBhQaFx/Rvhz27A2PIPv9lL2i4UQ==", + "dev": true, + "requires": { + "@parcel/types": "2.4.0" + } + }, + "@parcel/reporter-cli": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.4.0.tgz", + "integrity": "sha512-Q9bIFMaGvQgypCDxdMEKOwrJzIHAXScKkuFsqTHnUL6mmH3Mo2CoEGAq/wpMXuPhXRn1dPJcHgTNDwZ2fSzz0A==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "chalk": "^4.1.0", + "term-size": "^2.2.1" + } + }, + "@parcel/reporter-dev-server": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.4.0.tgz", + "integrity": "sha512-24h++wevs7XYuX4dKa4PUfLSstvn3g7udajFv6CeQoME+dR25RL/wH/2LUbhV5ilgXXab76rWIndSqp78xHxPA==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0" + } + }, + "@parcel/resolver-default": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.4.0.tgz", + "integrity": "sha512-K7pIIFmGm1hjg/7Mzkg99i8tfCClKfBUTuc2R5j8cdr2n0mCAi4/f2mFf5svLrb5XZrnDgoQ05tHKklLEfUDUw==", + "dev": true, + "requires": { + "@parcel/node-resolver-core": "2.4.0", + "@parcel/plugin": "2.4.0" + } + }, + "@parcel/runtime-browser-hmr": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.4.0.tgz", + "integrity": "sha512-swPFtvxGoCA9LEjU/pHPNjxG1l0fte8447zXwRN/AaYrtjNu9Ww117OSKCyvCnE143E79jZOFStodTQGFuH+9A==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0" + } + }, + "@parcel/runtime-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.4.0.tgz", + "integrity": "sha512-67OOvmkDdtmgzZVP/EyAzoXhJ/Ug3LUVUt7idg9arun5rdJptqEb3Um3wmH0zjcNa9jMbJt7Kl5x1wA8dJgPYg==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/runtime-react-refresh": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.4.0.tgz", + "integrity": "sha512-flnr+bf06lMZPbXZZLLaFNrPHvYpfuXTVovEghyUW46qLVpaHj33dpsU/LqZplIuHgBp2ibgrKhr/hY9ell68w==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "react-refresh": "^0.9.0" + } + }, + "@parcel/runtime-service-worker": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.4.0.tgz", + "integrity": "sha512-RgM5QUqW22WzstW03CtV+Oih8VGVuwsf94Cc4hLouU2EAD0NUJgATWbFocZVTZIBTKELAWh2gjpSQDdnL4Ur+A==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/source-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.0.2.tgz", + "integrity": "sha512-NnUrPYLpYB6qyx2v6bcRPn/gVigmGG6M6xL8wIg/i0dP1GLkuY1nf+Hqdf63FzPTqqT7K3k6eE5yHPQVMO5jcA==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3" + } + }, + "@parcel/transformer-babel": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.4.0.tgz", + "integrity": "sha512-iWDa7KzJTMP3HNmrYxiYq/S6redk2qminx/9MwmKIN9jzm8mgts2Lj9lOg/t66YaDGky6JAvw4DhB2qW4ni6yQ==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/utils": "2.4.0", + "browserslist": "^4.6.6", + "json5": "^2.2.0", + "nullthrows": "^1.1.1", + "semver": "^5.7.0" + } + }, + "@parcel/transformer-css": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.4.0.tgz", + "integrity": "sha512-D2u48LuiQsQvbknABE0wVKFp9r6yCgWrHKEP1J6EJ31c49nXGXDHrpHJJwqq9BvAs/124eBI5mSsehTJyFEMwg==", + "dev": true, + "requires": { + "@parcel/css": "^1.7.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/utils": "2.4.0", + "browserslist": "^4.6.6", + "nullthrows": "^1.1.1" + } + }, + "@parcel/transformer-html": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.4.0.tgz", + "integrity": "sha512-2/8X/o5QaCNVPr4wkxLCUub7v/YVvVN2L5yCEcTatNeFhNg/2iz7P2ekfqOaoDCHWZEOBT1VTwPbdBt+TMM71Q==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/plugin": "2.4.0", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^5.7.1" + }, + "dependencies": { + "posthtml-parser": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz", + "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==", + "dev": true, + "requires": { + "htmlparser2": "^7.1.1" + } + } + } + }, + "@parcel/transformer-image": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.4.0.tgz", + "integrity": "sha512-JZkQvGGoGiD0AVKLIbAYYUWxepMmUaWZ4XXx71MmS/kA7cUDwTZ0CXq63YnSY1m+DX+ClTuTN8mBlwe2dkcGbA==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/workers": "2.4.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/transformer-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.4.0.tgz", + "integrity": "sha512-eeLHFwv3jT3GmIxpLC7B8EXExGK0MFaK91HXljOMh6l8a+GlQYw27MSFQVtoXr0Olx9Uq2uvjXP1+zSsq3LQUQ==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/utils": "2.4.0", + "@parcel/workers": "2.4.0", + "@swc/helpers": "^0.3.6", + "browserslist": "^4.6.6", + "detect-libc": "^1.0.3", + "nullthrows": "^1.1.1", + "regenerator-runtime": "^0.13.7", + "semver": "^5.7.1" + } + }, + "@parcel/transformer-json": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.4.0.tgz", + "integrity": "sha512-3nR+d39mbURoXIypDfVCaxpwL65qMV+h8SLD78up2uhaRGklHQfN7GuemR7L+mcVAgNrmwVvZHhyNjdgYwWqqg==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "json5": "^2.2.0" + } + }, + "@parcel/transformer-postcss": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.4.0.tgz", + "integrity": "sha512-ijIa2x+dbKnJhr7zO5WlXkvuj832fDoGksMBk2DX3u2WMrbh2rqVWPpGFsDhESx7EAy38nUoV/5KUdrNqUmCEA==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "clone": "^2.1.1", + "nullthrows": "^1.1.1", + "postcss-value-parser": "^4.2.0", + "semver": "^5.7.1" + } + }, + "@parcel/transformer-posthtml": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.4.0.tgz", + "integrity": "sha512-xoL3AzgtVeRRAo6bh0AHAYm9bt1jZ+HiH86/7oARj/uJs6Wd8kXK/DZf6fH+F87hj4e7bnjmDDc0GPVK0lPz1w==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^5.7.1" + }, + "dependencies": { + "posthtml-parser": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz", + "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==", + "dev": true, + "requires": { + "htmlparser2": "^7.1.1" + } + } + } + }, + "@parcel/transformer-raw": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.4.0.tgz", + "integrity": "sha512-fciFbNrzj0kLlDgr6OsI0PUv414rVygDWAsgbCCq4BexDkuemMs9f9FjMctx9B2VZlctE8dTT4RGkuQumTIpUg==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0" + } + }, + "@parcel/transformer-react-refresh-wrap": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.4.0.tgz", + "integrity": "sha512-9+f6sGOWkf0jyUQ1CuFWk+04Mq3KTOCU9kRiwCHX1YdUCv5uki6r9XUSpqiYodrV+L6w9CCwLvGMLCDHxtCxMg==", + "dev": true, + "requires": { + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "react-refresh": "^0.9.0" + } + }, + "@parcel/transformer-svg": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.4.0.tgz", + "integrity": "sha512-D+yzVtSxtQML3d26fd/g4E/xYW68+OMbMUVLXORtoYMU42fnXQkJP6jGOdqy8Td+WORNY7EwVtQnESLwhBmolw==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/plugin": "2.4.0", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^5.7.1" + }, + "dependencies": { + "posthtml-parser": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz", + "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==", + "dev": true, + "requires": { + "htmlparser2": "^7.1.1" + } + } + } + }, + "@parcel/types": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.4.0.tgz", + "integrity": "sha512-nysGIbBEnp+7R+tKTysdcTFOZDTCodsiXFeAhYQa5bhiOnG1l9gzhxQnE2OsdsgvMm40IOsgKprqvM/DbdLfnQ==", + "dev": true, + "requires": { + "@parcel/cache": "2.4.0", + "@parcel/diagnostic": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/package-manager": "2.4.0", + "@parcel/source-map": "^2.0.0", + "@parcel/workers": "2.4.0", + "utility-types": "^3.10.0" + } + }, + "@parcel/utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.4.0.tgz", + "integrity": "sha512-sdNo+mZqDZT8LJYB6WWRKa4wFVZcK6Zb5Jh6Du76QvXXwHbPIQNZgJBb6gd/Rbk4GLOp2tW7MnBfq6zP9E9E2g==", + "dev": true, + "requires": { + "@parcel/codeframe": "2.4.0", + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/markdown-ansi": "2.4.0", + "@parcel/source-map": "^2.0.0", + "chalk": "^4.1.0" + } + }, + "@parcel/watcher": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.5.tgz", + "integrity": "sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw==", + "dev": true, + "requires": { + "node-addon-api": "^3.2.1", + "node-gyp-build": "^4.3.0" + } + }, + "@parcel/workers": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.4.0.tgz", + "integrity": "sha512-eSFyvEoXXPgFzQfKIlpkUjpHfIbezUCRFTPKyJAKCxvU5DSXOpb1kz5vDESWQ4qTZXKnrKvxS1PPWN6bam9z0g==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "chrome-trace-event": "^1.0.2", + "nullthrows": "^1.1.1" + } + }, + "@swc/helpers": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.8.tgz", + "integrity": "sha512-aWItSZvJj4+GI6FWkjZR13xPNPctq2RRakzo+O6vN7bC2yjwdg5EFpgaSAUn95b7BGSgcflvzVDPoKmJv24IOg==", + "dev": true + }, + "@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "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==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + }, + "@types/react": { + "version": "17.0.41", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.41.tgz", + "integrity": "sha512-chYZ9ogWUodyC7VUTRBfblysKLjnohhFY9bGLwvnUFFy48+vB9DikmB3lW0qTFmBcKSzmdglcvkHK71IioOlDA==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-redux": { + "version": "7.1.23", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.23.tgz", + "integrity": "sha512-D02o3FPfqQlfu2WeEYwh3x2otYd2Dk1o8wAfsA0B1C2AJEFxE663Ozu7JzuWbznGgW248NaOF6wsqCGNq9d3qw==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "abortcontroller-polyfill": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz", + "integrity": "sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q==", + "dev": true + }, + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "browserslist": { + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001319", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001319.tgz", + "integrity": "sha512-xjlIAFHucBRSMUo1kb5D4LYgcN1M45qdKP++lhqowDpwJwGkpIRTt5qQqnhxjj1vHcI7nrJxWhCC1ATrCEBTcw==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "css-select": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", + "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "dev": true + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + } + }, + "csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "dotenv": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", + "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", + "dev": true + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.89", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.89.tgz", + "integrity": "sha512-z1Axg0Fu54fse8wN4fd+GAINdU5mJmLtcl6bqIcYyzNVGONcfHAeeJi88KYMQVKalhXlYuVPzKkFIU5VD0raUw==", + "dev": true + }, + "entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "get-port": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", + "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==", + "dev": true + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "hooks-for-redux": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hooks-for-redux/-/hooks-for-redux-2.0.3.tgz", + "integrity": "sha512-MRnlMcDGT+UBfFGPuu9FWTXfDV9mbbMw+TWBTjJbHFeqTJWnae7oqXJOJyZedAxV5hq6U/G0cO9BYys3Fi5juw==", + "requires": { + "@types/react-redux": "^7.1.5", + "react-redux": "^7.1.1", + "redux": "^4.0.4" + } + }, + "htmlnano": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.0.tgz", + "integrity": "sha512-thKQfhcp2xgtsWNE27A2bliEeqVL5xjAgGn0wajyttvFFsvFWWah1ntV9aEX61gz0T6MBQ5xK/1lXuEumhJTcg==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.1", + "posthtml": "^0.16.5", + "timsort": "^0.3.0" + } + }, + "htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-json": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz", + "integrity": "sha1-a+Fm0USCihMdaGiRuYPfYsOUkf8=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.6.1.tgz", + "integrity": "sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "lmdb": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.2.4.tgz", + "integrity": "sha512-gto+BB2uEob8qRiTlOq+R3uX0YNHsX9mjxj9Sbdue/LIKqu6IlZjrsjKeGyOMquc/474GEqFyX2pdytpydp0rQ==", + "dev": true, + "requires": { + "msgpackr": "^1.5.4", + "nan": "^2.14.2", + "node-gyp-build": "^4.2.3", + "ordered-binary": "^1.2.4", + "weak-lru-cache": "^1.2.2" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "msgpackr": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.5.5.tgz", + "integrity": "sha512-JG0V47xRIQ9pyUnx6Hb4+3TrQoia2nA3UIdmyTldhxaxtKFkekkKpUW/N6fwHwod9o4BGuJGtouxOk+yCP5PEA==", + "dev": true, + "requires": { + "msgpackr-extract": "^1.0.14" + } + }, + "msgpackr-extract": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-1.0.16.tgz", + "integrity": "sha512-fxdRfQUxPrL/TizyfYfMn09dK58e+d65bRD/fcaVH4052vj30QOzzqxcQIS7B0NsqlypEQ/6Du3QmP2DhWFfCA==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.14.2", + "node-gyp-build": "^4.2.3" + } + }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "dev": true + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true + }, + "node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "dev": true + }, + "node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "ordered-binary": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.2.4.tgz", + "integrity": "sha512-A/csN0d3n+igxBPfUrjbV5GC69LWj2pjZzAAeeHXLukQ4+fytfP4T1Lg0ju7MSPSwq7KtHkGaiwO8URZN5IpLg==", + "dev": true + }, + "parcel": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.4.0.tgz", + "integrity": "sha512-dPWpu4RnxG9HqiLvaF8COEWEnT/KrigrC6PyPaQ0zEgpBfp7/jzXZFBVaZk2N+lpvrbNEYMjN9bv5UQGJJszIw==", + "dev": true, + "requires": { + "@parcel/config-default": "2.4.0", + "@parcel/core": "2.4.0", + "@parcel/diagnostic": "2.4.0", + "@parcel/events": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/package-manager": "2.4.0", + "@parcel/reporter-cli": "2.4.0", + "@parcel/reporter-dev-server": "2.4.0", + "@parcel/utils": "2.4.0", + "chalk": "^4.1.0", + "commander": "^7.0.0", + "get-port": "^4.2.0", + "v8-compile-cache": "^2.0.0" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "posthtml": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", + "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", + "dev": true, + "requires": { + "posthtml-parser": "^0.11.0", + "posthtml-render": "^3.0.0" + } + }, + "posthtml-parser": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", + "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", + "dev": true, + "requires": { + "htmlparser2": "^7.1.1" + } + }, + "posthtml-render": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz", + "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==", + "dev": true, + "requires": { + "is-json": "^2.0.1" + } + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-redux": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", + "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", + "requires": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "dependencies": { + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + } + } + }, + "react-refresh": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", + "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", + "dev": true + }, + "redux": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "terser": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", + "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==", + "dev": true, + "requires": { + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true + }, + "xxhash-wasm": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz", + "integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + } + } +} diff --git a/examples/migration/package.json b/examples/migration/package.json new file mode 100644 index 0000000..f0bfd37 --- /dev/null +++ b/examples/migration/package.json @@ -0,0 +1,13 @@ +{ + "version": "1.0.0", + "private": true, + "scripts": { + "start": "parcel src/index.html" + }, + "devDependencies": { + "parcel": "^2.4.0" + }, + "dependencies": { + "hooks-for-redux": "^2.0.3" + } +} diff --git a/examples/migration/src/app.js b/examples/migration/src/app.js new file mode 100644 index 0000000..9ff5dd2 --- /dev/null +++ b/examples/migration/src/app.js @@ -0,0 +1,52 @@ +import {setStore, createStore, createReduxModule} from 'hooks-for-redux' + +// Current reducer used in your app +const reducers = (state, action) => { + switch (action.type) { + case 'INCREMENT_COUNT': + return {...state, count: (state.count || 42) + 1} + case 'DECREMENT_COUNT': + return {...state, count: (state.count || 42) - 1} + default: + return state + } +} + +// Set store with H4R +const store = setStore(createStore(reducers)) + +// Add existing state slice with H4R (slice will be changeable with dispatch and H4R hooks) +const [useCount, {increment, decrement}] = createReduxModule('count', 42, { + increment: (state) => state + 1, + decrement: (state) => state - 1, +}) + +// Add non-existing state slice with H4R (slice will be changeable with H4R hooks) +const [useName, {setName}] = createReduxModule('name', 'Marty', { + setName: (state, name) => name || 'Marty', +}) + +let render = () => { + console.log(store.getState()) + document.getElementById('count-state').innerHTML = store.getState().count + document.getElementById('name-state').innerHTML = store.getState().name +} + +store.subscribe(render) + +// Change count using dispatch +document + .getElementById('increment-dispatch') + .addEventListener('click', () => store.dispatch({type: 'INCREMENT_COUNT'})) + +// Change count using hook +document + .getElementById('decrement-hook') + .addEventListener('click', decrement) + +// Change name using hook +document + .getElementById('name-input') + .addEventListener('keyup', (e) => setName(e.target.value)) + +render() diff --git a/examples/migration/src/index.html b/examples/migration/src/index.html new file mode 100644 index 0000000..20fd309 --- /dev/null +++ b/examples/migration/src/index.html @@ -0,0 +1,20 @@ + + + + + + H4R Migration Example + + + + +
+

Hello , you are !

+
+ +
+ + +
+ + diff --git a/examples/migration/src/styles.css b/examples/migration/src/styles.css new file mode 100644 index 0000000..7b8d047 --- /dev/null +++ b/examples/migration/src/styles.css @@ -0,0 +1,73 @@ +html { + height: 100%; + padding: 0px; +} + +body { + display: flex; + height: 100%; + font-family: Verdana, sans-serif; + align-items: center; + justify-content: center; + background-color: #FAFAFA; +} + +button { + border: none; + margin: 0; + padding: 0; + width: auto; + overflow: visible; + background: transparent; + color: inherit; + font: inherit; + line-height: normal; + user-select: none; + -webkit-font-smoothing: inherit; + -moz-osx-font-smoothing: inherit; + -webkit-appearance: none; + + padding: 15px; + border-radius: 3px; + font-size: 12px; + text-transform: uppercase; + cursor: pointer; + transition: .3s; + background-color: #1B754D; + color: #FFFFFF; +} + +button:hover { + background: #1E8557; +} + +button::-moz-focus-inner { + border: 0; + padding: 0; +} + +hr { + margin: 20px 0; + border-top: 1px solid #D8D8D8; + border-bottom: none; +} + +#root { + padding: 50px; + border: 1px solid rgba(27,117,77,0.2); + border-radius: 5px; + background-color: #FFFFFF; +} + +input { + width: 100%; + padding: 15px; + border: 1px solid rgba(27,117,77,0.2); + box-sizing: border-box; + outline: none; + border-radius: 3px; +} + +input:focus { + border: 1px solid rgba(27,117,77,0.8); +} diff --git a/src/tests/createStore.test.js b/src/tests/createStore.test.js index ebd8aef..8c37f39 100644 --- a/src/tests/createStore.test.js +++ b/src/tests/createStore.test.js @@ -99,4 +99,4 @@ describe("support default createStore API with combined reducers", () => { it("injectReducer key must be unique", () => { getStore().injectReducer("myKey", () => 1); getStore().injectReducer("myKey", () => 2); // second call OK -}); \ No newline at end of file +}); From c72357925e483739d022af54489c3cfaa9f42648 Mon Sep 17 00:00:00 2001 From: Matthias Courville Date: Tue, 22 Mar 2022 15:32:07 -0700 Subject: [PATCH 4/5] Bumped version to 2.0.4 --- examples/migration/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/migration/package.json b/examples/migration/package.json index f0bfd37..c954d69 100644 --- a/examples/migration/package.json +++ b/examples/migration/package.json @@ -8,6 +8,6 @@ "parcel": "^2.4.0" }, "dependencies": { - "hooks-for-redux": "^2.0.3" + "hooks-for-redux": "^2.0.4" } } diff --git a/package.json b/package.json index c00b95b..6c4e4eb 100644 --- a/package.json +++ b/package.json @@ -32,5 +32,5 @@ "type": "git", "url": "https://github.com/generalui/hooks-for-redux.git" }, - "version": "2.0.3" + "version": "2.0.4" } From a938b238bee1a0a5597ec045bc679549602d79e0 Mon Sep 17 00:00:00 2001 From: Matthias Courville Date: Thu, 24 Mar 2022 07:40:24 -0700 Subject: [PATCH 5/5] Improved createStore performances --- src/createStore.js | 74 ++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/src/createStore.js b/src/createStore.js index ae1d5d9..faa780e 100644 --- a/src/createStore.js +++ b/src/createStore.js @@ -1,16 +1,10 @@ const { createStore: reduxCreateStore, combineReducers } = require('redux') -const getRootReducerSlices = (state, reducers, initialReducer) => { - const initialSlices = initialReducer ? initialReducer({}, '') : {} - const initialKeys = Object.keys(initialSlices) - const knownKeys = Object.keys(reducers) - const slices = { - known: {}, - unknown: {} - } +const getStateSlices = (state, reducerKeys, initialKeys = []) => { + const slices = { known: {}, unknown: {} } - for (const key of Object.keys(state)) { - if (knownKeys.includes(key)) { + Object.keys(state).forEach((key) => { + if (reducerKeys.includes(key)) { slices.known[key] = state[key] } else { slices.unknown[key] = state[key] @@ -19,50 +13,66 @@ const getRootReducerSlices = (state, reducers, initialReducer) => { if (initialKeys.includes(key)) { slices.unknown[key] = state[key] } - } + }) return slices } module.exports = (initialReducer = {}, ...args) => { + let store let reducers - let rootReducer + // Passing an object of reducers is preferable for performances if (typeof initialReducer === "object") { reducers = {...initialReducer, _stub_: (s) => s || 0} - } else if (typeof initialReducer === "function") { + store = reduxCreateStore(combineReducers(reducers)) + store.injectReducer = (key, reducer) => { + if (reducers[key]) console.warn(`injectReducer: replacing reducer for key '${key}'`) + reducers[key] = reducer + store.replaceReducer(combineReducers(reducers)) + } + } + // Support for default redux API (single or combined reducer) + else if (typeof initialReducer === "function") { + const initialKeys = Object.keys(initialReducer(undefined, '') || {}) reducers = {_stub_: (s) => s || 0} + let reducerKeys = Object.keys(reducers) + let combinedReducer = combineReducers(reducers) + let rootReducer + + // Combined reducer if (initialReducer.name === 'combination') { rootReducer = (state = {}, action) => { - const slices = getRootReducerSlices(state, reducers, initialReducer) - const intermediateState = combinedReducer(slices.known, action) - for (const key of Object.keys(intermediateState)) { + const slices = getStateSlices(state, reducerKeys, initialKeys) + const intermediate = combinedReducer(slices.known, action) + Object.keys(intermediate).forEach((key) => { if (slices.unknown.hasOwnProperty(key)) { - slices.unknown[key] = intermediateState[key] + slices.unknown[key] = intermediate[key] } - } - return {...intermediateState, ...initialReducer(slices.unknown, action)} + }) + return {intermediate, ...initialReducer(slices.unknown, action)} } - } else { + } + // Single reducer + else { rootReducer = (state = {}, action) => { - const slices = getRootReducerSlices(state, reducers) - const intermediateState = combinedReducer(slices.known, action) - return initialReducer({...state, ...intermediateState}, action) + const slices = getStateSlices(state, reducerKeys, initialKeys) + return initialReducer({...state, ...combinedReducer(slices.known, action)}, action) } } + + store = reduxCreateStore(rootReducer) + store.injectReducer = (key, reducer) => { + if (reducers[key]) console.warn(`injectReducer: replacing reducer for key '${key}'`) + reducers[key] = reducer + reducerKeys = Object.keys(reducers) + combinedReducer = combineReducers(reducers) + store.replaceReducer(rootReducer) + } } else { console.error({initialReducer, args}) throw new Error("initialReducer should be an object suitable to be passed to combineReducers or a reducing function (\"uncombined\")") } - let combinedReducer = combineReducers(reducers) - const store = reduxCreateStore(rootReducer || combinedReducer) - store.injectReducer = (key, reducer) => { - if (reducers[key]) console.warn(`injectReducer: replacing reducer for key '${key}'`) - reducers[key] = reducer - combinedReducer = combineReducers(reducers) - store.replaceReducer(rootReducer || combinedReducer) - } - return store }