diff --git a/assets/DataFlowDiagram.PNG b/assets/DataFlowDiagram.PNG new file mode 100644 index 000000000..8a50bbcfd Binary files /dev/null and b/assets/DataFlowDiagram.PNG differ diff --git a/assets/dataflow.jpg b/assets/oldDataflowDiagram.jpg similarity index 100% rename from assets/dataflow.jpg rename to assets/oldDataflowDiagram.jpg diff --git a/package.json b/package.json index 3448c7663..26354c15b 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "@types/chrome": "^0.0.119", "@types/d3-scale-chromatic": "^2.0.0", "@types/jest": "^26.0.4", + "@types/lodash.isequal": "^4.5.5", "@types/node": "^12.19.6", "@typescript-eslint/eslint-plugin": "^3.6.1", "@typescript-eslint/parser": "^3.6.1", @@ -162,6 +163,7 @@ "jest-runner": "^26.1.0", "jscharting": "^3.0.2", "jsondiffpatch": "^0.3.11", + "lodash": "^4.17.21", "prop-types": "^15.7.2", "rc-slider": "^8.7.1", "rc-tooltip": "^3.7.3", @@ -176,6 +178,7 @@ "react-spinners": "^0.11.0", "react-split": "^2.0.14", "recoil": "0.0.10", + "util": "^0.12.4", "web-vitals": "^1.1.0" } } diff --git a/src/README.md b/src/README.md index 676dbccde..de8c70917 100644 --- a/src/README.md +++ b/src/README.md @@ -8,7 +8,7 @@ Our mission at Reactime is to maintain and iterate constantly, but never at the ## File Structure -In the *src* folder, there are three directories we care about: *app*, *backend*, and *extension*. +In the *src* folder, there are three directories we care about: *app*, *backend*, and *extension*. ``` src/ ├── app/ # Frontend code @@ -19,7 +19,7 @@ src/ │   ├── containers/ # More React components │   ├── reducers/ # Redux mechanism for updating state │   ├── styles/ # -│   ├── index.tsx # Starting point for root App component +│   ├── index.tsx # Starting point for root App component │   ├── module.d.ts # │   └── store.tsx # │ @@ -27,10 +27,10 @@ src/ │   │ # Focus especially on linkFiber, timeJump, tree, and helpers │   ├── __tests__/ # │   ├── types/ # Typescript interfaces -│   ├── helpers.js # -│   ├── index.ts # Starting point for backend functionality -│   ├── index.d.ts # -│   ├── linkFiber.ts # +│   ├── helpers.js # +│   ├── index.ts # Starting point for backend functionality +│   ├── index.d.ts # +│   ├── linkFiber.ts # │   ├── masterState.js # Component action record interface │   ├── module.d.ts # │   ├── package.json # @@ -46,7 +46,7 @@ src/ └── ``` -1. The *app* folder is responsible for the Single Page Application that you see when you open the chrome dev tools under the Reactime tab. +1. The *app* folder is responsible for the Single Page Application that you see when you open the chrome dev tools under the Reactime tab. ![FRONTEND DATA FLOW](../assets/frontend.png) @@ -55,7 +55,7 @@ src/ ![BACKEND DATA FLOW](../assets/backend.png) -3. The *extension* folder is where the `contentScript.js` and `background.js` are located. +3. The *extension* folder is where the `contentScript.js` and `background.js` are located. - Like regular web apps, Chrome Extensions are event-based. The background script is where one typically monitors for browser triggers (e.g. events like closing a tab, for example). The content script is what allows us to read or write to our target web application, usually as a result of [messages passed](https://developer.chrome.com/extensions/messaging) from the background script. - These two files help us handle requests both from the web browser and from the Reactime extension itself @@ -66,7 +66,7 @@ All the diagrams of data flows are avaliable on [MIRO](https://miro.com/app/boar The general flow of data is described in the following steps: -![GENERAL DATA FLOW](../assets/dataflow.jpg) +![GENERAL DATA FLOW](../assets/DataFlowDiagram.PNG) 1. When the background bundle is loaded by the browser, it executes a script injection into the dom. (see section on *backend*). This script uses a technique called [throttle](https://medium.com/@bitupon.211/debounce-and-throttle-160affa5457b) to send state data from the app to the content script every specified milliseconds (in our case, this interval is 70ms). @@ -82,21 +82,21 @@ The general flow of data is described in the following steps: Navigation between different console.log panels can be confusing when running Reactime. We created a short instruction where you can find the results for your console.log ### /src/extension -Console.logs from the Extension folder you can find here: +Console.logs from the Extension folder you can find here: - Chrome Extension (Developer mode) -- Background page +- Background page -![extension](../assets/extension-console.gif) +![extension](../assets/extension-console.gif) ### /src/app -Console.logs from the App folder you can find here: +Console.logs from the App folder you can find here: - Chrome Browser - Inspect ![frontend](../assets/console.gif) ### /src/backend -Console.logs from the App folder you can find here: +Console.logs from the App folder you can find here: - Open the Reactime extension in Chrome - Click "Inspect" on Reactime @@ -105,15 +105,15 @@ Console.logs from the App folder you can find here: ## Chrome Developer Resources Still unsure about what content scripts and background scripts do for Reactime, or for a chrome extensions in general? - The implementation details [can be found](./extension/background.js) [in the source files](./extension/contentScript.ts) themselves. - - We also encourage you to dive into [the official Chrome Developer Docs](https://developer.chrome.com/home). - + - We also encourage you to dive into [the official Chrome Developer Docs](https://developer.chrome.com/home). + Some relevant sections are reproduced below: -> Content scripts are files that run in the context of web pages. +> Content scripts are files that run in the context of web pages. > > By using the standard Document Object Model (DOM), they are able to **read** details of the web pages the browser visits, **make changes** to them and **pass information back** to their parent extension. ([Source](https://developer.chrome.com/extensions/content_scripts)) -- One helpful way to remember a content script's role in the Chrome ecosystem is to think: a *content* script is used to read and modify a target web page's rendered *content*. +- One helpful way to remember a content script's role in the Chrome ecosystem is to think: a *content* script is used to read and modify a target web page's rendered *content*. >A background page is loaded when it is needed, and unloaded when it goes idle. > @@ -122,12 +122,12 @@ Still unsure about what content scripts and background scripts do for Reactime, >The background page was listening for an event, and the event is dispatched. >A content script or other extension sends a message. >Another view in the extension, such as a popup, calls `runtime.getBackgroundPage`. -> +> >Once it has been loaded, a background page will stay running as long as it is performing an action, such as calling a Chrome API or issuing a network request. > > Additionally, the background page will not unload until all visible views and all message ports are closed. Note that opening a view does not cause the event page to load, but only prevents it from closing once loaded. ([Source](https://developer.chrome.com/extensions/background_pages)) - You can think of background scripts serving a purpose analogous to that of a **server** in the client/server paradigm. Much like a server, our `background.js` listens constantly for messages (i.e. requests) from two main places: 1. The content script - 2. The chrome extension "front-end" **(*NOT* the interface of the browser, this is an important distinction.)** -- In other words, a background script works as a sort of middleman, directly maintaining connection with its parent extension, and acting as a proxy enabling communication between it and the content script. + 2. The chrome extension "front-end" **(*NOT* the interface of the browser, this is an important distinction.)** +- In other words, a background script works as a sort of middleman, directly maintaining connection with its parent extension, and acting as a proxy enabling communication between it and the content script. diff --git a/src/app/actions/actions.ts b/src/app/actions/actions.ts index 50dd63d68..3a589ec72 100644 --- a/src/app/actions/actions.ts +++ b/src/app/actions/actions.ts @@ -7,7 +7,7 @@ export const save = (tabsObj) => ({ }); export const deleteSeries = () => ({ type: types.DELETE_SERIES, -}) +}); export const toggleMode = (mode) => ({ type: types.TOGGLE_MODE, payload: mode, @@ -90,6 +90,11 @@ export const toggleSplit = () => ({ type: types.TOGGLE_SPLIT, }); +export const toggleExpanded = (node) => ({ + type: types.TOGGLE_EXPANDED, + payload: node, +}); + export const launchContentScript = (tab) => ({ type: types.LAUNCH_CONTENT, payload: tab, diff --git a/src/app/components/ComponentMap.tsx b/src/app/components/ComponentMap.tsx index 9256e758f..2219c6ebb 100644 --- a/src/app/components/ComponentMap.tsx +++ b/src/app/components/ComponentMap.tsx @@ -1,9 +1,11 @@ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable no-nested-ternary */ /* eslint-disable no-unused-expressions */ /* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable no-restricted-syntax */ /* eslint-disable guard-for-in */ // @ts-nocheck -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import { Group } from '@visx/group'; import { hierarchy, Tree } from '@visx/hierarchy'; import { LinearGradient } from '@visx/gradient'; @@ -15,12 +17,9 @@ import { TooltipWithBounds, defaultStyles, } from '@visx/tooltip'; -import { isAbsolute } from 'path'; -import { nest } from 'jscharting'; -import useForceUpdate from './useForceUpdate'; import LinkControls from './LinkControls'; import getLinkComponent from './getLinkComponent'; -import { onHover, onHoverExit } from '../actions/actions'; +import { toggleExpanded } from '../actions/actions'; import { useStoreContext } from '../store'; const exclude = ['childExpirationTime', 'staticContext', '_debugSource', 'actualDuration', 'actualStartTime', 'treeBaseDuration', '_debugID', '_debugIsCurrentlyTiming', 'selfBaseDuration', 'expirationTime', 'effectTag', 'alternate', '_owner', '_store', 'get key', 'ref', '_self', '_source', 'firstBaseUpdate', 'updateQueue', 'lastBaseUpdate', 'shared', 'responders', 'pending', 'lanes', 'childLanes', 'effects', 'memoizedState', 'pendingProps', 'lastEffect', 'firstEffect', 'tag', 'baseState', 'baseQueue', 'dependencies', 'Consumer', 'context', '_currentRenderer', '_currentRenderer2', 'mode', 'flags', 'nextEffect', 'sibling', 'create', 'deps', 'next', 'destroy', 'parentSub', 'child', 'key', 'return', 'children', '$$typeof', '_threadCount', '_calculateChangedBits', '_currentValue', '_currentValue2', 'Provider', '_context', 'stateNode', 'elementType', 'type']; @@ -56,7 +55,7 @@ export type LinkTypesProps = { width: number; height: number; margin?: { top: number; right: number; bottom: number; left: number }; - snapshots: []; + snapshots: Record; }; export default function ComponentMap({ @@ -64,24 +63,16 @@ export default function ComponentMap({ width: totalWidth, height: totalHeight, margin = defaultMargin, - snapshots, -}: LinkTypesProps) { - const [{ tabs, currentTab }, dispatch] = useStoreContext(); - // This is where we select the last object in the snapshots array from props to allow hierarchy to parse the data for render on the component map per hierarchy layout specifications. - const lastNode = snapshots.length - 1; - const data: {} = snapshots[lastNode]; - + currentSnapshot, +}: LinkTypesProps): JSX.Element { // importing custom hooks for the selection tabs. const [layout, setLayout] = useState('cartesian'); const [orientation, setOrientation] = useState('horizontal'); const [linkType, setLinkType] = useState('diagonal'); const [stepPercent, setStepPercent] = useState(10); const [tooltip, setTooltip] = useState(false); - // const [expanded, setExpanded] = useState(); const [selectedNode, setSelectedNode] = useState('root'); - - // Declared this variable and assigned it to the useForceUpdate function that forces a state to change causing that component to re-render and display on the map - const forceUpdate = useForceUpdate(); + const [{ tabs, currentTab }, dispatch] = useStoreContext(); // setting the margins for the Map to render in the tab window. const innerWidth = totalWidth - margin.left - margin.right; @@ -136,7 +127,7 @@ export default function ComponentMap({ lineHeight: '18px', fontFamily: 'Roboto', zIndex: 100, - 'pointer-events': 'all !important', + pointerEvents: 'all !important', }; const scrollStyle = { @@ -153,10 +144,7 @@ export default function ComponentMap({ return `${time} ms `; }; - // places all nodes into a flat array - const nodeList = []; - - const makePropsPretty = data => { + const formatProps = data => { const propsFormat = []; const nestedObj = []; for (const key in data) { @@ -165,7 +153,7 @@ export default function ComponentMap({ {`${key}: ${data[key]}`}

); } else if (data[key] !== 'reactFiber' && typeof data[key] === 'object' && exclude.includes(key) !== true) { - const result = makePropsPretty(data[key]); + const result = formatProps(data[key]); nestedObj.push(result); } } @@ -180,7 +168,6 @@ export default function ComponentMap({ if (state === 'stateless') return ['stateless']; const result = []; - const inner = arg => { if (Array.isArray(arg)) { result.push('['); @@ -198,13 +185,14 @@ export default function ComponentMap({ result.push(` ${arg}, `); } }; - - inner(state); - console.log(result); + return result; }; + // places all nodes into a flat array + const nodeList = []; + const collectNodes = node => { nodeList.splice(0, nodeList.length); nodeList.push(node); @@ -217,7 +205,7 @@ export default function ComponentMap({ } } }; - collectNodes(snapshots[lastNode]); + collectNodes(currentSnapshot); // find the node that has been selected and use it as the root const startNode = null; @@ -239,7 +227,7 @@ export default function ComponentMap({ orientation={orientation} linkType={linkType} stepPercent={stepPercent} - snapShots={snapshots[lastNode]} + snapShots={currentSnapshot} selectedNode={selectedNode} setLayout={setLayout} setOrientation={setOrientation} @@ -262,7 +250,7 @@ export default function ComponentMap({ /> (d.isExpanded ? null : d.children))} + root={hierarchy(startNode || data, d => (d.isExpanded ? d.children : null))} size={[sizeWidth, sizeHeight]} separation={(a, b) => (a.parent === b.parent ? 1 : 0.5) / a.depth} > @@ -305,17 +293,12 @@ export default function ComponentMap({ // mousing controls & Tooltip display logic const handleMouseAndClickOver = event => { - // looks like onHover isnt working? - // () => dispatch(onHover(node.data.rtid)); const coords = localPoint( event.target.ownerSVGElement, event, ); const tooltipObj = { ...node.data }; - // console.log(node.data); - // if (typeof tooltipObj.state === 'object') { - // tooltipObj.state = JSON.stringify(tooltipObj.state); - // } + showTooltip({ tooltipLeft: coords.x, tooltipTop: coords.y, @@ -331,8 +314,9 @@ export default function ComponentMap({ fill="url('#links-gradient')" stroke="#ff6569" onClick={() => { - node.data.isExpanded = !node.data.isExpanded; - forceUpdate(); + dispatch(toggleExpanded(node.data)); + hideTooltip(); + setTooltip(false); }} /> )} @@ -343,45 +327,27 @@ export default function ComponentMap({ width={width} y={-height / 2} x={-width / 2} - // node.children = if node has children fill={node.children ? '#161521' : '#62d6fb'} - // node.data.isExpanded = if node is collapsed - // stroke={(node.data.isExpanded && node.child) ? '#95fb62' : '#a69ff5'} => node.child is gone when clicked, even if it actually has children. Maybe better call node.children => node.leaf stroke={(node.data.isExpanded && node.data.children.length > 0) ? '#ff6569' : '#4D4D4D'} strokeWidth={1.5} - // strokeDasharray={node.children ? '0' : '2,2'} strokeOpacity="1" rx={node.children ? 4 : 10} - // double clicking the component expands or collapses the child components - // onDoubleClick={() => { - // node.data.isExpanded = !node.data.isExpanded; - // hideTooltip(); - // setTooltip(false); - // forceUpdate(); - // }} - // Tooltip event handlers - // test feature - // onClick = {handleMouseAndClickOver} + onClick={() => { - node.data.isExpanded = !node.data.isExpanded; + dispatch(toggleExpanded(node.data)); hideTooltip(); setTooltip(false); - forceUpdate(); }} onMouseOver={event => { setTooltip(true); handleMouseAndClickOver(event); }} - // paired with onmouseOver listener, this produces a hover over effect for the component Tooltip + // with onmouseOver, this produces a hover over effect for the Tooltip onMouseOut={() => { hideTooltip(); setTooltip(false); }} - - // onMouseEnter={() => dispatch(onHover(node.data.rtid))} - // onMouseLeave={() => dispatch(onHoverExit(node.data.rtid))} - // eslint-disable-next-line react/jsx-curly-newline /> )} {/* Display text inside of each component node */} @@ -439,12 +405,11 @@ export default function ComponentMap({
State: {formatState(tooltipData.state)} - {/* {tooltipData.state} */}
Props: - {makePropsPretty(tooltipData.componentData.props)} + {formatProps(tooltipData.componentData.props)}
diff --git a/src/app/components/StateRoute.tsx b/src/app/components/StateRoute.tsx index 8996ea26b..ae8f60eb7 100644 --- a/src/app/components/StateRoute.tsx +++ b/src/app/components/StateRoute.tsx @@ -51,20 +51,14 @@ const StateRoute = (props: StateRouteProps) => { const { hierarchy, sliderIndex, viewIndex } = tabs[currentTab]; const isRecoil = !!snapshot.atomsComponents; - const [noRenderData, setNoRenderData] = useState(false); - // component map zoom state - const [{ x, y, k }, setZoomState]: any = useState({ - x: 150, - y: 250, - k: 1, - }); // Map const renderComponentMap = () => { if (hierarchy) { return ( {({ width, height }) => ( - + // eslint-disable-next-line react/prop-types + )} ); diff --git a/src/app/constants/actionTypes.ts b/src/app/constants/actionTypes.ts index 3b5f62d8a..54115e053 100644 --- a/src/app/constants/actionTypes.ts +++ b/src/app/constants/actionTypes.ts @@ -14,6 +14,7 @@ export const SET_TAB = 'SET_TAB'; export const DELETE_TAB = 'DELETE_TAB'; export const NO_DEV = 'NO_DEV'; export const TOGGLE_SPLIT = 'TOGGLE_SPLIT'; +export const TOGGLE_EXPANDED = 'TOGGLE_EXPANDED'; export const LAUNCH_CONTENT = 'LAUNCH_CONTENT'; export const SLIDER_ZERO = 'SLIDER_ZERO'; export const ON_HOVER = 'ON_HOVER'; diff --git a/src/app/reducers/mainReducer.js b/src/app/reducers/mainReducer.js index da88b38f9..9cfc352bb 100644 --- a/src/app/reducers/mainReducer.js +++ b/src/app/reducers/mainReducer.js @@ -1,5 +1,5 @@ import { produce } from 'immer'; - +import _ from 'lodash'; import * as types from '../constants/actionTypes.ts'; export default (state, action) => produce(state, draft => { @@ -254,9 +254,19 @@ export default (state, action) => produce(state, draft => { if (!payload[tab]) { delete tabs[tab]; } else { + // maintain isExpaned prop from old stateSnapshot to preserve componentMap expansion + const persistIsExpanded = (newNode, oldNode) => { + newNode.isExpanded = oldNode ? oldNode.isExpanded : true; + if (newNode.children) { + newNode.children.forEach((child, i) => { + persistIsExpanded(child, oldNode?.children[i]); + }); + } + }; + persistIsExpanded(payload[tab].currLocation.stateSnapshot, tabs[tab].currLocation.stateSnapshot); + const { snapshots: newSnaps } = payload[tab]; tabs[tab] = { - ...tabs[tab], ...payload[tab], sliderIndex: newSnaps.length - 1, seriesSavedStatus: false, @@ -307,10 +317,34 @@ export default (state, action) => produce(state, draft => { draft.split = !draft.split; break; } + case types.TOGGLE_EXPANDED: { + // find correct node from currLocation and toggle isExpanded + const checkChildren = node => { + if (_.isEqual(node, action.payload)) { + node.isExpanded = !node.isExpanded; + return; + } + if (node.children) { + node.children.forEach(child => { + checkChildren(child); + }); + } + }; + checkChildren(tabs[currentTab].currLocation.stateSnapshot); + break; + } case types.SET_CURRENT_LOCATION: { const { payload } = action; - const { currLocation } = payload[currentTab]; - tabs[currentTab].currLocation = currLocation; + const persistIsExpanded = (newNode, oldNode) => { + newNode.isExpanded = oldNode ? oldNode.isExpanded : true; + if (newNode.children) { + newNode.children.forEach((child, i) => { + persistIsExpanded(child, oldNode?.children[i]); + }); + } + }; + persistIsExpanded(payload[currentTab].currLocation.stateSnapshot, tabs[currentTab].currLocation.stateSnapshot); + tabs[currentTab].currLocation = payload[currentTab].currLocation; break; } default: diff --git a/src/backend/linkFiber.ts b/src/backend/linkFiber.ts index 4ef30f096..00b47ed6d 100644 --- a/src/backend/linkFiber.ts +++ b/src/backend/linkFiber.ts @@ -106,6 +106,7 @@ function sendSnapshot(snap: Snapshot, mode: Mode): void { // this postMessage will be sending the most up-to-date snapshot of the current React Fiber Tree // the postMessage action will be received on the content script to later update the tabsObj // this will fire off everytime there is a change in test application + console.log('payload in backend', payload); window.postMessage( { action: 'recordSnap', diff --git a/src/backend/tree.ts b/src/backend/tree.ts index 89aa88e8b..4dc9604cb 100644 --- a/src/backend/tree.ts +++ b/src/backend/tree.ts @@ -44,12 +44,14 @@ class Tree { name: string; componentData: { - props:{} + props: {}, }; children: (Tree | string)[]; - parent: Tree + parent: Tree; + + isExpanded: boolean; atomsComponents: any; @@ -67,17 +69,13 @@ class Tree { // If not, create the new component and also a new key: value pair in 'componentNames' with the component's name as the key and 0 as its value // EXAMPLE OF COMPONENTNAMES OBJECT: {editableInput: 1, Provider: 0, etc} - // Empty names: - // If string, rtid without 'fromLinkFiber" - // If object - // If null - constructor(state: string | {}, name = 'nameless', componentData: {} = {}, rtid: any = null, recoilDomNode: any = null, string: any = null) { this.state = state === 'root' ? 'root' : serializeState(state); this.name = name; - this.componentData = componentData ? JSON.parse(JSON.stringify(componentData)) : {}; + this.componentData = componentData ? { ...JSON.parse(JSON.stringify(componentData)) } : { }; this.children = []; this.parent = null; // ref to parent so we can add siblings + this.isExpanded = true; this.rtid = rtid; this.recoilDomNode = recoilDomNode; } diff --git a/src/extension/background.js b/src/extension/background.js index 71d0a1085..53536ff69 100644 --- a/src/extension/background.js +++ b/src/extension/background.js @@ -251,7 +251,6 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { tabsObj[tabId] = createTabObj(tabTitle); } - const { persist, empty } = tabsObj[tabId].mode; switch (action) { case 'jumpToSnap': { changeCurrLocation(tabsObj[tabId], tabsObj[tabId].hierarchy, index, name); diff --git a/yarn.lock b/yarn.lock index be0a7b5b3..cfc32264a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1631,7 +1631,14 @@ "resolved" "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" "version" "0.0.29" -"@types/lodash@^4.14.146", "@types/lodash@^4.14.160": +"@types/lodash.isequal@^4.5.5": + "integrity" "sha512-4IKbinG7MGP131wRfceK6W4E/Qt3qssEFLF30LnJbjYiSfHGGRU/Io8YxXrZX109ir+iDETC8hw8QsDijukUVg==" + "resolved" "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.5.tgz" + "version" "4.5.5" + dependencies: + "@types/lodash" "*" + +"@types/lodash@*", "@types/lodash@^4.14.146", "@types/lodash@^4.14.160": "integrity" "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==" "resolved" "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz" "version" "4.14.168" @@ -2483,6 +2490,11 @@ "resolved" "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz" "version" "2.1.2" +"available-typed-arrays@^1.0.5": + "integrity" "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + "resolved" "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + "version" "1.0.5" + "aws-sign2@~0.7.0": "integrity" "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" "resolved" "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" @@ -4373,27 +4385,31 @@ dependencies: "is-arrayish" "^0.2.1" -"es-abstract@^1.17.0", "es-abstract@^1.17.0-next.1", "es-abstract@^1.17.4", "es-abstract@^1.17.5", "es-abstract@^1.18.0-next.2": - "integrity" "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==" - "resolved" "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz" - "version" "1.18.0" +"es-abstract@^1.17.0", "es-abstract@^1.17.0-next.1", "es-abstract@^1.17.4", "es-abstract@^1.17.5", "es-abstract@^1.18.0-next.2", "es-abstract@^1.18.5": + "integrity" "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==" + "resolved" "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz" + "version" "1.19.1" dependencies: "call-bind" "^1.0.2" "es-to-primitive" "^1.2.1" "function-bind" "^1.1.1" "get-intrinsic" "^1.1.1" + "get-symbol-description" "^1.0.0" "has" "^1.0.3" "has-symbols" "^1.0.2" - "is-callable" "^1.2.3" + "internal-slot" "^1.0.3" + "is-callable" "^1.2.4" "is-negative-zero" "^2.0.1" - "is-regex" "^1.1.2" - "is-string" "^1.0.5" - "object-inspect" "^1.9.0" + "is-regex" "^1.1.4" + "is-shared-array-buffer" "^1.0.1" + "is-string" "^1.0.7" + "is-weakref" "^1.0.1" + "object-inspect" "^1.11.0" "object-keys" "^1.1.1" "object.assign" "^4.1.2" "string.prototype.trimend" "^1.0.4" "string.prototype.trimstart" "^1.0.4" - "unbox-primitive" "^1.0.0" + "unbox-primitive" "^1.0.1" "es-to-primitive@^1.2.1": "integrity" "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==" @@ -5010,6 +5026,11 @@ "resolved" "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" "version" "1.0.2" +"foreach@^2.0.5": + "integrity" "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + "resolved" "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz" + "version" "2.0.5" + "forever-agent@~0.6.1": "integrity" "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" "resolved" "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" @@ -5118,7 +5139,7 @@ "resolved" "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz" "version" "2.0.0" -"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.1": +"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.0", "get-intrinsic@^1.1.1": "integrity" "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==" "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" "version" "1.1.1" @@ -5146,6 +5167,14 @@ dependencies: "pump" "^3.0.0" +"get-symbol-description@^1.0.0": + "integrity" "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==" + "resolved" "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "call-bind" "^1.0.2" + "get-intrinsic" "^1.1.1" + "get-value@^2.0.3", "get-value@^2.0.6": "integrity" "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" "resolved" "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz" @@ -5268,7 +5297,7 @@ "ajv" "^6.5.5" "har-schema" "^2.0.0" -"has-bigints@^1.0.0": +"has-bigints@^1.0.1": "integrity" "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" "resolved" "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz" "version" "1.0.1" @@ -5283,11 +5312,18 @@ "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" "version" "4.0.0" -"has-symbols@^1.0.0", "has-symbols@^1.0.1", "has-symbols@^1.0.2": +"has-symbols@^1.0.1", "has-symbols@^1.0.2": "integrity" "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz" "version" "1.0.2" +"has-tostringtag@^1.0.0": + "integrity" "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==" + "resolved" "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "has-symbols" "^1.0.2" + "has-value@^0.3.1": "integrity" "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=" "resolved" "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz" @@ -5602,14 +5638,14 @@ "strip-ansi" "^6.0.0" "through" "^2.3.6" -"internal-slot@^1.0.2": - "integrity" "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==" - "resolved" "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz" - "version" "1.0.2" +"internal-slot@^1.0.2", "internal-slot@^1.0.3": + "integrity" "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==" + "resolved" "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz" + "version" "1.0.3" dependencies: - "es-abstract" "^1.17.0-next.1" + "get-intrinsic" "^1.1.0" "has" "^1.0.3" - "side-channel" "^1.0.2" + "side-channel" "^1.0.4" "internmap@^1.0.0": "integrity" "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" @@ -5645,15 +5681,25 @@ dependencies: "kind-of" "^6.0.0" +"is-arguments@^1.0.4": + "integrity" "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==" + "resolved" "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "call-bind" "^1.0.2" + "has-tostringtag" "^1.0.0" + "is-arrayish@^0.2.1": "integrity" "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" "resolved" "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" "version" "0.2.1" "is-bigint@^1.0.1": - "integrity" "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==" - "resolved" "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz" - "version" "1.0.1" + "integrity" "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==" + "resolved" "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "has-bigints" "^1.0.1" "is-binary-path@^1.0.0": "integrity" "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=" @@ -5681,10 +5727,10 @@ "resolved" "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" "version" "1.1.6" -"is-callable@^1.1.4", "is-callable@^1.1.5", "is-callable@^1.2.3": - "integrity" "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" - "resolved" "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz" - "version" "1.2.3" +"is-callable@^1.1.4", "is-callable@^1.1.5", "is-callable@^1.2.4": + "integrity" "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + "resolved" "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz" + "version" "1.2.4" "is-ci@^2.0.0": "integrity" "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==" @@ -5779,6 +5825,13 @@ "resolved" "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" "version" "2.1.0" +"is-generator-function@^1.0.7": + "integrity" "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==" + "resolved" "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "has-tostringtag" "^1.0.0" + "is-glob@^3.1.0": "integrity" "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=" "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz" @@ -5832,13 +5885,18 @@ "resolved" "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz" "version" "1.0.0" -"is-regex@^1.0.5", "is-regex@^1.1.0", "is-regex@^1.1.2": - "integrity" "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==" - "resolved" "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz" - "version" "1.1.2" +"is-regex@^1.0.5", "is-regex@^1.1.0", "is-regex@^1.1.4": + "integrity" "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==" + "resolved" "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + "version" "1.1.4" dependencies: "call-bind" "^1.0.2" - "has-symbols" "^1.0.1" + "has-tostringtag" "^1.0.0" + +"is-shared-array-buffer@^1.0.1": + "integrity" "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + "resolved" "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz" + "version" "1.0.1" "is-stream@^1.1.0": "integrity" "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" @@ -5850,10 +5908,12 @@ "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz" "version" "2.0.0" -"is-string@^1.0.5": - "integrity" "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" - "resolved" "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz" - "version" "1.0.5" +"is-string@^1.0.5", "is-string@^1.0.7": + "integrity" "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==" + "resolved" "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + "version" "1.0.7" + dependencies: + "has-tostringtag" "^1.0.0" "is-subset@^0.1.1": "integrity" "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=" @@ -5867,11 +5927,29 @@ dependencies: "has-symbols" "^1.0.1" +"is-typed-array@^1.1.3", "is-typed-array@^1.1.7": + "integrity" "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==" + "resolved" "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz" + "version" "1.1.8" + dependencies: + "available-typed-arrays" "^1.0.5" + "call-bind" "^1.0.2" + "es-abstract" "^1.18.5" + "foreach" "^2.0.5" + "has-tostringtag" "^1.0.0" + "is-typedarray@^1.0.0", "is-typedarray@~1.0.0": "integrity" "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" "resolved" "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" "version" "1.0.0" +"is-weakref@^1.0.1": + "integrity" "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==" + "resolved" "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "call-bind" "^1.0.2" + "is-windows@^1.0.1": "integrity" "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" "resolved" "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" @@ -6776,7 +6854,7 @@ "resolved" "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz" "version" "4.0.1" -"lodash@^4.15.0", "lodash@^4.16.3", "lodash@^4.17.10", "lodash@^4.17.11", "lodash@^4.17.14", "lodash@^4.17.15", "lodash@^4.17.16", "lodash@^4.17.19", "lodash@^4.17.20", "lodash@^4.17.4", "lodash@4.x": +"lodash@^4.15.0", "lodash@^4.16.3", "lodash@^4.17.10", "lodash@^4.17.11", "lodash@^4.17.14", "lodash@^4.17.15", "lodash@^4.17.16", "lodash@^4.17.19", "lodash@^4.17.20", "lodash@^4.17.21", "lodash@^4.17.4", "lodash@4.x": "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" "version" "4.17.21" @@ -7287,10 +7365,10 @@ "define-property" "^0.2.5" "kind-of" "^3.0.3" -"object-inspect@^1.7.0", "object-inspect@^1.9.0": - "integrity" "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" - "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz" - "version" "1.9.0" +"object-inspect@^1.11.0", "object-inspect@^1.7.0", "object-inspect@^1.9.0": + "integrity" "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" + "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz" + "version" "1.12.0" "object-is@^1.0.2", "object-is@^1.1.2": "integrity" "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==" @@ -9036,13 +9114,14 @@ "resolved" "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz" "version" "0.1.1" -"side-channel@^1.0.2": - "integrity" "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==" - "resolved" "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz" - "version" "1.0.2" +"side-channel@^1.0.2", "side-channel@^1.0.4": + "integrity" "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==" + "resolved" "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + "version" "1.0.4" dependencies: - "es-abstract" "^1.17.0-next.1" - "object-inspect" "^1.7.0" + "call-bind" "^1.0.0" + "get-intrinsic" "^1.0.2" + "object-inspect" "^1.9.0" "signal-exit@^3.0.0", "signal-exit@^3.0.2": "integrity" "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" @@ -9912,15 +9991,15 @@ "resolved" "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.2.tgz" "version" "3.13.2" -"unbox-primitive@^1.0.0": - "integrity" "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==" - "resolved" "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz" - "version" "1.0.0" +"unbox-primitive@^1.0.1": + "integrity" "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==" + "resolved" "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz" + "version" "1.0.1" dependencies: "function-bind" "^1.1.1" - "has-bigints" "^1.0.0" - "has-symbols" "^1.0.0" - "which-boxed-primitive" "^1.0.1" + "has-bigints" "^1.0.1" + "has-symbols" "^1.0.2" + "which-boxed-primitive" "^1.0.2" "unbzip2-stream@^1.3.3": "integrity" "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==" @@ -10047,6 +10126,18 @@ dependencies: "inherits" "2.0.3" +"util@^0.12.4": + "integrity" "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==" + "resolved" "https://registry.npmjs.org/util/-/util-0.12.4.tgz" + "version" "0.12.4" + dependencies: + "inherits" "^2.0.3" + "is-arguments" "^1.0.4" + "is-generator-function" "^1.0.7" + "is-typed-array" "^1.1.3" + "safe-buffer" "^5.1.2" + "which-typed-array" "^1.1.2" + "util@0.10.3": "integrity" "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=" "resolved" "https://registry.npmjs.org/util/-/util-0.10.3.tgz" @@ -10262,7 +10353,7 @@ "tr46" "^2.0.2" "webidl-conversions" "^5.0.0" -"which-boxed-primitive@^1.0.1": +"which-boxed-primitive@^1.0.2": "integrity" "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==" "resolved" "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" "version" "1.0.2" @@ -10278,6 +10369,18 @@ "resolved" "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" "version" "2.0.0" +"which-typed-array@^1.1.2": + "integrity" "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==" + "resolved" "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz" + "version" "1.1.7" + dependencies: + "available-typed-arrays" "^1.0.5" + "call-bind" "^1.0.2" + "es-abstract" "^1.18.5" + "foreach" "^2.0.5" + "has-tostringtag" "^1.0.0" + "is-typed-array" "^1.1.7" + "which@^1.2.14", "which@^1.2.9", "which@^1.3.1": "integrity" "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==" "resolved" "https://registry.npmjs.org/which/-/which-1.3.1.tgz"