diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8e0438ad..04b35895 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -26,7 +26,7 @@ module.exports = { 'react/react-in-jsx-scope': 'off', 'react/jsx-uses-react': 'off', 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error' + 'simple-import-sort/exports': 'error', }, 'overrides': [ { @@ -55,5 +55,10 @@ module.exports = { ] } } - ] + ], + "settings": { + "react": { + "version": "detect" + } + } } diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 38a64a1b..bd2e2645 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,14 +12,15 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '22.x' - run: npm ci - run: npm run build env: BASE_URL: '/ePlant' + VITE_MAPS_API_KEY: ${{ secrets.VITE_MAPS_API_KEY }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b20b29cd..e3f79544 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -17,22 +17,21 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '22.x' - run: npm ci - run: npm run build env: BASE_URL: '/ePlant' VITE_MAPS_API_KEY: ${{ secrets.VITE_MAPS_API_KEY }} - VITE_MAPS_ID: ${{ secrets.VITE_MAPS_ID }} - run: mv dist _site - name: Upload artifact - uses: actions/upload-pages-artifact@v2 + uses: actions/upload-pages-artifact@v3 deploy: environment: name: github-pages @@ -42,4 +41,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index fcd47e47..03205100 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -10,10 +10,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '20.x' diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 5f953c25..4ca91dbb 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -20,9 +20,9 @@ jobs: # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'npm' diff --git a/.gitignore b/.gitignore index 621d181e..c5d8a1ee 100644 --- a/.gitignore +++ b/.gitignore @@ -106,4 +106,4 @@ dist # notes files *-notes.md -.DS_Store \ No newline at end of file +.DS_Store diff --git a/Eplant/config.ts b/Eplant/config.ts index e00ccb9f..88dc0419 100644 --- a/Eplant/config.ts +++ b/Eplant/config.ts @@ -7,6 +7,8 @@ import ExperimentEFP from './views/ExperimentEFP' import FallbackView from './views/FallbackView' import GeneInfoView from './views/GeneInfoView' import GetStartedView from './views/GetStartedView' +import InteractionsViewer from './views/InteractionsViewer' +import NavigatorView from './views/NavigatorViewer' import PlantEFP from './views/PlantEFP' import PublicationViewer from './views/PublicationViewer' import WorldEFP from './views/WorldEFP' @@ -35,6 +37,8 @@ const userViews = [ ExperimentEFP, WorldEFP, ChromosomeViewer, + InteractionsViewer, + NavigatorView, ] // List of views that are used to lookup a view by id diff --git a/Eplant/state/index.tsx b/Eplant/state/index.tsx index 5ee815e9..0214f51e 100644 --- a/Eplant/state/index.tsx +++ b/Eplant/state/index.tsx @@ -95,7 +95,7 @@ export function atomWithStorage( // TODO: This should probably be removed // Atom with storage that doesn't persist when persistAtom is set to false -function atomWithOptionalStorage( +export function atomWithOptionalStorage( key: string, initialValue: T, serialize: (value: T) => string = JSON.stringify, diff --git a/Eplant/tutorial.md b/Eplant/tutorial.md index 08e6abaa..7d7c5ac6 100644 --- a/Eplant/tutorial.md +++ b/Eplant/tutorial.md @@ -32,6 +32,10 @@ - [How to create a new `View`](#how-to-create-a-new-view) - [Steps to Update `config.ts`](#steps-to-update-configts) - [Example](#example) + - [View Switching Functionality](#view-switching-functionality) +- [Documentation and Commenting Style](#documentation-and-commenting-style) +- [Eslint Code Standards](#eslint-code-standards) +- [Local Testing Requirements](#local-testing-requirements) - [Eplant2](#eplant2) - [API](#api) @@ -366,6 +370,72 @@ const genericViews = [GetStartedView, FallbackView, NewView] const views = [...genericViews, ...userViews] ``` +#### View Switching Functionality + +If your new view has function to swap to a different view and/or gene available on ePlant, you may benefit from the generalized view switching component file (name tbd). + +To utilize the component: + +1. Import createViewSwitchProvider into your index file and export it: + +``` +export const ViewSwitchProvider = createViewSwitchProvider(); +``` + +2. Import your exported provider into your view's main component and wrap your component in the view's return statement: + +``` +const App = () => { + return ( + + + + ); +}; +``` + +3. Import and use useViewSwitch in your main component whenever you want to invoke the switching functionality. For example: `switchViewAndGene('Cell eFP', geneName);` + +There are 3 main swithing functions you can invoke based on needs. + +``` + /** Function to switch view only */ + switchViewOnly: (viewId: string) => Promise; + + /** Function to switch gene only */ + switchGeneOnly: (geneName: string, speciesUrl?: string) => Promise; + + /** Function to switch both view and gene */ + switchViewAndGene: (viewId: string, geneName: string, speciesUrl?: string) => Promise; +``` + +## Documentation and Commenting Style + +It is important to maintain a common standard for commenting code and documentation. If you want to make contributions to the project, we ask that you follow the TSdoc(typescript) commenting style. As an example this includes adding function/class headers and comments as seen below: + +``` +/** + * Extracts the primary gene identifier from the API URL + * + * @param url - The complete API URL containing query parameters + * @returns The primary gene identifier, or an empty string not found + * + * Uses regex to find the primaryGene parameter in the URL + */ +function extractPrimaryGene(url: string): string { + const match = url.match(/primaryGene=([^&]+)/); + return match ? match[1] : ""; +} +``` + +## ESlint Code Standards + +The codebase relies on ESlint to handle automatic checking for issues with the code. With ESlint, you will not need to manually parse all of your code for accurate documentation, imports order, etc. When running ePlant locally in a browser, if there are any outstanding issues, it will be made known to you automatically. A common way to fix any issues without much thought is to run `npx eslint . --fix`. The `.` can be replaced if you do not want to check and fix every file in your current working directory. Documentation issues are not as big of a concern as others and your local site may work as normal, but to keep in line with our standards, please resolve any issues and warnings before making a pull request. + +## Local Testing Requirements + +To allow ESlint to work, and to run the site locally you are required to install Node.js and NPM on your system. Once installed, you can activate a local connection to the site using `npm run dev` and connecting to the generated web access point. + ## Eplant2 https://bar.utoronto.ca/eplant/ diff --git a/Eplant/util/ErrorBoundary/index.tsx b/Eplant/util/ErrorBoundary/index.tsx index 4131e96b..5abd2230 100644 --- a/Eplant/util/ErrorBoundary/index.tsx +++ b/Eplant/util/ErrorBoundary/index.tsx @@ -8,6 +8,11 @@ export default class ErrorBoundary extends Component< this.state = { hasError: false } } componentDidCatch(error: Error, info: ErrorInfo) { + console.log( + 'Error caught by ErrorBoundary:', + error.message, + info.componentStack + ) this.setState({ hasError: true }) } render() { diff --git a/Eplant/views/ChromosomeViewer/Viewer/GeneInfoPopup.tsx b/Eplant/views/ChromosomeViewer/Viewer/GeneInfoPopup.tsx index a8b6d279..fc256b9c 100644 --- a/Eplant/views/ChromosomeViewer/Viewer/GeneInfoPopup.tsx +++ b/Eplant/views/ChromosomeViewer/Viewer/GeneInfoPopup.tsx @@ -43,7 +43,6 @@ const GeneInfoPopup: FC = (props) => { const geneticElements = useGeneticElements() const setGeneticElements = useSetGeneticElements() const theme = useTheme() - useEffect(() => { if (props.gene != gene) { setOpen(props.open) diff --git a/Eplant/views/InteractionsViewer/InteractionsView.tsx b/Eplant/views/InteractionsViewer/InteractionsView.tsx deleted file mode 100644 index 2e133847..00000000 --- a/Eplant/views/InteractionsViewer/InteractionsView.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react' - -import ThumbnailLight from '../../../thumbnails/plant-efp-light.png' -import { View } from '../../View' -import PublicationViewerIcon from '../PublicationViewer/icon' - -const InteractionsViewer: View = { - name: 'Interactions Viewer', - id: 'interactions-viewer', - component() { - return
This is not implemented yet!
- }, - icon: () => <>, - description: 'Interactions Viewer.', - citation() { - return
- }, - async getInitialData() { - return - }, -} diff --git a/Eplant/views/InteractionsViewer/components/GeneDialog.tsx b/Eplant/views/InteractionsViewer/components/GeneDialog.tsx new file mode 100644 index 00000000..5d395ff6 --- /dev/null +++ b/Eplant/views/InteractionsViewer/components/GeneDialog.tsx @@ -0,0 +1,77 @@ +import React, { FC, useEffect, useState } from 'react' + +import GeneticElement from '@eplant/GeneticElement' +import arabidopsis from '@eplant/Species/arabidopsis' +import { + useActiveGeneId, + useGeneticElements, + useSetGeneticElements, +} from '@eplant/state' +import Box from '@mui/material/Box' +import useTheme from '@mui/material/styles/useTheme' +import Table from '@mui/material/Table' +import TableBody from '@mui/material/TableBody' +import TableCell from '@mui/material/TableCell' +import TableRow from '@mui/material/TableRow' + +import { GeneItem } from '../../ChromosomeViewer/types' +interface GeneDialogProps { + gene: GeneItem +} +/** Gene dialog to show gene infomation when hovering over gene node. currently not implemented due to restrictions of cytoscape + * @param {GeneItem} gene GeneItem object to show in table format in the dialog + * */ +const GeneDialog: FC = ({ gene }) => { + // Global State + const [activeGeneId, setActiveGeneId] = useActiveGeneId() + const geneticElements = useGeneticElements() + const setGeneticElements = useSetGeneticElements() + const theme = useTheme() + + const handleLoadGeneClick = (event: React.MouseEvent) => { + if (gene != null) { + const geneticElement = new GeneticElement( + gene.id, + gene.annotation, + arabidopsis, + gene.aliases + ) + + setGeneticElements([...geneticElements[0], geneticElement]) + setActiveGeneId(gene.id) + } + } + + return ( +
+ {/* GENE INFO TABLE */} + + + + + + + + + + + + + +
Identifier{gene.id}
Aliases{gene.aliases.length > 0 ? gene.aliases : 'N/A'}
Annotation{gene.annotation != '' ? gene.annotation : 'N/A'}
+
+ ) +} + +export default GeneDialog diff --git a/Eplant/views/InteractionsViewer/components/NumberInput.tsx b/Eplant/views/InteractionsViewer/components/NumberInput.tsx new file mode 100644 index 00000000..302ffdf8 --- /dev/null +++ b/Eplant/views/InteractionsViewer/components/NumberInput.tsx @@ -0,0 +1,51 @@ +import { ChangeEvent } from 'react' + +import InputAdornment from '@mui/material/InputAdornment' +import TextField from '@mui/material/TextField' + +interface numberInputProps { + label: string + changeFunc: (event: ChangeEvent) => void + prefix?: string +} + +/** Number selector for filter dialog + * @param {string} label number selector label + * @param {func} changeFunc function to call on change + * @param {string} prefix prefix to prepend to number + */ +const NumberInput = (props: numberInputProps) => { + return ( + <> + { + props.changeFunc(event) + }} + inputProps={{ + defaultValue: 0, + step: 0.1, + min: -1, + max: 1, + }} + InputProps={ + props.prefix + ? { + startAdornment: ( + + {props.prefix} + + ), + } + : {} + } + /> + + ) +} +export default NumberInput diff --git a/Eplant/views/InteractionsViewer/components/Topbar.tsx b/Eplant/views/InteractionsViewer/components/Topbar.tsx new file mode 100644 index 00000000..d9ac3276 --- /dev/null +++ b/Eplant/views/InteractionsViewer/components/Topbar.tsx @@ -0,0 +1,401 @@ +import { ChangeEvent, FC, useRef, useState } from 'react' +import { Core } from 'cytoscape' + +import { FilterAlt, QuestionMark } from '@mui/icons-material' +import { Close } from '@mui/icons-material' +import AppBar from '@mui/material/AppBar' +import Box from '@mui/material/Box' +import Button from '@mui/material/Button' +import ButtonGroup from '@mui/material/ButtonGroup' +import Checkbox from '@mui/material/Checkbox' +import FormControlLabel from '@mui/material/FormControlLabel' +import FormGroup from '@mui/material/FormGroup' +import IconButton from '@mui/material/IconButton' +import Popover from '@mui/material/Popover' +import Toolbar from '@mui/material/Toolbar' +import Typography from '@mui/material/Typography' + +import { + applyFilter, + cleanCompoundNode, + cleanNodes, +} from '../scripts/filterLogic' + +import NumberInput from './NumberInput' + +interface TopbarProps { + cy: Core + gene: string +} +/** Interactions view toolbar, contains gene id header, legend and filter buttons + * @param {Core} cy cytoscape instance + * @param {string} gene current gene id + * */ +const Topbar: FC = ({ cy, gene }) => { + const [showLegend, setShowLegend] = useState(false) + const legendRef = useRef(null) + const [showFilters, setShowFilters] = useState(false) + const filterRef = useRef(null) + const [eppiSelected, setEppiSelected] = useState(false) + const [eppiCorrSelected, setEppiCorrSelected] = useState(false) + const [eppiCorrValue, setEppiCorrValue] = useState() + const [pppiSelected, setPppiSelected] = useState(false) + const [pppiCorrSelected, setPppiCorrSelected] = useState(false) + const [pppiCorrValue, setPppiCorrValue] = useState() + const [pppiConfSelected, setPppiConfSelected] = useState(false) + const [pppiConfValue, setPppiConfValue] = useState() + const [epdiSelected, setEpdiSelected] = useState(false) + const [ppdiSelected, setPpdiSelected] = useState(false) + const [ppdiConfSelected, setPpdiConfSelected] = useState(false) + const [ppdiConfValue, setPpdiConfValue] = useState() + + const selectors = { + EPPISelector: '[type = "PPI"][method = "E"]', // checkbox + corrSelector: '[correlation <= ', // eppi-correlation spinner + checkbox + PPPISelector: '[type = "PPI"][method = "P"]', // checkbox + interConfSelector: '[interolog_conf <=', // PPPI correlation + EPDISelector: '[type = "PDI"][method = "E"]', + PPDISelector: '[type = "PDI"][method = "P"]', + fimoConfSelector: '[fimo_conf >= ', + } + + const handleLegendClick = () => { + setShowLegend(!showLegend) + } + const handleFilterClick = () => { + setShowFilters(!showFilters) + } + const handleApplyFilters = () => { + const filterStatus = [ + eppiSelected, + eppiCorrSelected, + pppiSelected, + pppiCorrSelected, + pppiConfSelected, + epdiSelected, + ppdiSelected, + ppdiConfSelected, + ] + + // Create selectors + const eppiCorr = + selectors.EPPISelector + selectors.corrSelector + eppiCorrValue + ']' + const pppiCorr = + selectors.PPPISelector + selectors.corrSelector + pppiCorrValue + ']' + const pppiConf = + selectors.PPPISelector + selectors.interConfSelector + pppiConfValue + ']' + const ppdiConf = + selectors.PPDISelector + + selectors.fimoConfSelector + + '1e-' + + ppdiConfValue + + ']' + + const filters = [ + selectors.EPPISelector, + eppiCorr, + selectors.PPPISelector, + pppiCorr, + pppiConf, + selectors.EPDISelector, + selectors.PPDISelector, + ppdiConf, + ] + // @ts-expect-error error with show no fix, still works + cy.elements().show() + for (let i = 0; i < filterStatus.length; i++) { + console.log(i) + applyFilter(cy, filterStatus[i], filters[i]) + } + // Hide orphaned nodes + cleanNodes(cy) + // Hide parent nodes + cleanCompoundNode(cy, 'COMPOUND_DNA') + cleanCompoundNode(cy, 'COMPOUND_PROTEIN') + // close filter dialog + setShowFilters(false) + } + + return ( + + + {/* VIEW TITLE */} + + ID: {gene} + + + {/* LEGEND BUTTON */} + + {/* FILTER BUTTON */} + + + + {/* LEGEND WINDOW */} + { + setShowLegend(!showLegend) + }} + anchorOrigin={{ + vertical: 'bottom', + horizontal: 'left', + }} + transformOrigin={{ + vertical: 'top', + horizontal: 'right', + }} + anchorEl={legendRef.current} + > + + + + + + + + {/* FILTERS DIALOG WINDOW */} + { + setShowFilters(!showFilters) + }} + anchorEl={filterRef.current} + anchorOrigin={{ + vertical: 'bottom', + horizontal: 'right', + }} + transformOrigin={{ + vertical: 'top', + horizontal: 'right', + }} + > + ({ + maxWidth: 600, + padding: 4, + pt: 2, + bgcolor: theme.palette.background.transparentOverlay, + color: 'white', + })} + > + {/* TITLE BAR OF FILTER DIALOG */} + + Filter Interactions + + + + + {/* FORM OPTIONS FOR FILTER DIALOG */} + + {/* FILTER: EPPI - Experimentally Determined Protein-Protein Interactions */} + setEppiSelected(!eppiSelected)} + /> + } + label='Hide ALL experimentally determined Protein-Protein interactions' + /> + + {/* FILTER (Checkbox) - EPPI Correlation */} + setEppiCorrSelected(!eppiCorrSelected)} + /> + } + label='Hide only with correlation less than: ' + /> + {/* FILTER (Number Select) - EPPI Correlation*/} + {eppiCorrSelected && ( + { + const target = event.target as HTMLInputElement + let value = parseFloat(target.value) + if (value > 1) { + value = 1 + } else if (value < -1) { + value = -1 + } + setEppiCorrValue(value) + }} + /> + )} + + {/* FILTER: Predicted Protein-Protein Interactions */} + setPppiSelected(!pppiSelected)} + /> + } + label='Hide ALL predicted Protein-Protein interactions' + /> + + {/* FILTER (Checkbox) - PPPI Correlation*/} + setPppiCorrSelected(!pppiCorrSelected)} + /> + } + label='Hide only with correlation less than: ' + /> + {/* FILTER (Number Select) - PPPI Correlation*/} + {pppiCorrSelected && ( + { + const target = event.target as HTMLInputElement + let value = parseFloat(target.value) + if (value > 1) { + value = 1 + } else if (value < -1) { + value = -1 + } + setPppiCorrValue(value) + }} + /> + )} + + + {/* FILTER (Checkbox) - PPPI Confidence*/} + setPppiConfSelected(!pppiConfSelected)} + /> + } + label='Hide only with confidence less than: ' + /> + {/* FILTER (Number Select) - PPPI Confidence*/} + {pppiConfSelected && ( + { + const target = event.target as HTMLInputElement + let value = parseFloat(target.value) + if (value > 1) { + value = 1 + } else if (value < -1) { + value = -1 + } + setEppiCorrValue(value) + }} + /> + )} + + + {/* FILTER: Experimentally determined Protein-DNA Interactions */} + setEpdiSelected(!epdiSelected)} + /> + } + label='Hide ALL experimentally determined Protein-DNA interactions' + /> + {/* FILTER: Predicted Protien-DNA Interactions*/} + setPpdiSelected(!ppdiSelected)} + /> + } + label='Hide ALL predicted Protien-DNA interactions' + /> + + {/* FILTER (Checkbox) - PPDI Confidence*/} + setPpdiConfSelected(!ppdiConfSelected)} + /> + } + label='Hide only with confidence greater than' + /> + {/* FILTER (Number Select) - PPDI Confidence*/} + {ppdiConfSelected && ( + { + const target = event.target as HTMLInputElement + let value = parseFloat(target.value) + if (value > 1) { + value = 1 + } else if (value < -1) { + value = -1 + } + setPpdiConfValue(value) + }} + prefix='1e-' + /> + )} + + {/* APPLY FILTERS BUTTON */} + + + + + + ) +} + +export default Topbar diff --git a/Eplant/views/InteractionsViewer/cytoStyles.ts b/Eplant/views/InteractionsViewer/cytoStyles.ts new file mode 100644 index 00000000..ea6d9d5d --- /dev/null +++ b/Eplant/views/InteractionsViewer/cytoStyles.ts @@ -0,0 +1,164 @@ +const styles: any = [ + { + selector: 'node', + style: { + 'text-background-shape': 'roundrectangle', + 'text-background-color': 'white', + 'text-background-opacity': 0.9, + 'background-color': '#f4f4f4', + 'font-size': '11px', + //'font-weight': 'bold', + 'text-halign': 'center', + 'border-width': '0px', + //'width': 'auto', + 'text-background-padding': '2px', + }, + }, + { + selector: '.compound-top', + style: { + shape: 'roundrectangle', + 'background-color': '#F3F3F3', + 'text-background-color': 'white', + 'text-wrap': 'wrap', + width: '300px', + color: '#000', + 'font-size': '10px', + 'font-weight': 'bold', + 'text-outline-width': '0px', + 'text-valign': 'top', + }, + }, + { + selector: '#COMPOUND_DNA', + style: { + 'background-opacity': '0', + 'text-background-opacity': '1', + label: 'Protein-DNA\nInteractions', + }, + }, + { + selector: '#COMPOUND_PROTEIN', + style: { + 'background-opacity': '0', + 'text-background-opacity': '1', + label: 'Protein-Protein\nInteractions', + }, + }, + { + selector: '.protein-compound', + style: { + 'background-opacity': 0, + events: 'no', + }, + }, + { + selector: '.protein-back[borderWidth]', + style: { + height: 'data(height)', + width: 'data(width)', + 'pie-size': '100%', + 'pie-1-background-color': 'data(pie1Colour)', + 'pie-1-background-size': 'data(pie1Size)', + 'pie-1-background-opacity': 1, + 'pie-2-background-color': 'data(pie2Colour)', + 'pie-2-background-size': 'data(pie2Size)', + 'pie-2-background-opacity': 1, + 'pie-3-background-color': 'data(pie3Colour)', + 'pie-3-background-size': 'data(pie3Size)', + 'pie-3-background-opacity': 1, + 'pie-4-background-color': 'data(pie4Colour)', + 'pie-4-background-size': 'data(pie4Size)', + 'pie-4-background-opacity': 1, + 'border-width': 'data(borderWidth)', + 'border-color': '#99CC00', + events: 'no', + }, + }, + { + selector: '.protein-node', + style: { + height: '36px', + width: '36px', + padding: '3px 3px 3px 3px', + 'text-valign': 'center', + content: 'data(content)', + events: 'yes', + 'z-index': 10, + }, + }, + { + selector: '[id $= "QUERY_BACK"]', + style: { + height: '60px', + width: '60px', + }, + }, + { + selector: '[id $= "QUERY_NODE"]', + style: { + height: '48px', + width: '48px', + 'font-size': '11px', + 'z-index': 10000000, + }, + }, + { + selector: '.dna-node', + style: { + shape: 'square', + width: '34px', + height: '34px', + 'border-width': '4px', + padding: '3px 3px 3px 3px', + 'border-color': '#030303', + 'text-valign': 'center', + content: 'data(content)', + 'z-index': 10, + }, + }, + { + selector: 'edge', + style: { + width: 'data(size)', + 'line-style': 'data(lineStyle)', + 'line-color': 'data(lineColor)', + 'control-point-distance': '50px', + 'control-point-weight': '0.5', + }, + }, + { + selector: '.protein-edge', + style: { + 'curve-style': 'bezier', + 'mid-target-arrow-shape': 'none', + }, + }, + { + selector: '.dna-edge', + style: { + 'curve-style': 'unbundled-bezier', + 'mid-target-arrow-shape': 'triangle', + 'mid-target-arrow-color': 'data(lineColor)', + }, + }, + { + selector: '.chr-edge', + style: { + 'curve-style': 'unbundled-bezier', + 'mid-target-arrow-shape': 'triangle', + 'mid-target-arrow-color': 'data(arrowColor)', + 'control-point-distance': '50px', + 'control-point-weight': '0.5', + }, + }, + { + selector: '.loaded', + style: { + 'background-color': '#3C3C3C', + 'text-background-color': '#3C3C3C', + color: '#FFFFFF', + }, + }, +] +export default styles diff --git a/Eplant/views/InteractionsViewer/icon.tsx b/Eplant/views/InteractionsViewer/icon.tsx new file mode 100644 index 00000000..25b16927 --- /dev/null +++ b/Eplant/views/InteractionsViewer/icon.tsx @@ -0,0 +1,48 @@ +import { FC } from 'react' + +interface IconProps { + width?: number + height?: number + fill?: string + stroke?: string + strokeWidth?: number +} +/** Creates SVG element for interactions view icon + * @param {number} width icon width in px + * @param {number} height icon height in px + * @param {string} fill icon fill color + * @param {string} stroke icon stroke color + * @param {number} strokeWidth icon stroke width + * */ +export const InteractionsIcon: FC = ({ + width = 24, + height = 24, + fill = 'none', + stroke = 'currentColor', + strokeWidth = 2, +}) => { + return ( + // IconChartDots3 - Tabler Icons + + + + + + + + + + + ) +} diff --git a/Eplant/views/InteractionsViewer/index.tsx b/Eplant/views/InteractionsViewer/index.tsx new file mode 100644 index 00000000..9e8a6a9d --- /dev/null +++ b/Eplant/views/InteractionsViewer/index.tsx @@ -0,0 +1,259 @@ +import { useEffect, useRef, useState } from 'react' +import cytoscape, { Core } from 'cytoscape' +// @ts-expect-error addon typing error no fix, still works +import automove from 'cytoscape-automove' +// @ts-expect-error addon typing error no fix, still works +import coseBilkent from 'cytoscape-cose-bilkent' +import popper from 'cytoscape-popper' +import tippy, { + followCursor, + Instance as TippyInstance, + Props as TProps, + sticky, +} from 'tippy.js' + +import GeneticElement from '@eplant/GeneticElement' +import { ViewDataError } from '@eplant/View/viewData' +import Close from '@mui/icons-material/Close' +import { useTheme } from '@mui/material' +import Alert from '@mui/material/Alert' +import IconButton from '@mui/material/IconButton' +import Snackbar from '@mui/material/Snackbar' + +import { View, ViewProps } from '../../View' + +import Topbar from './components/Topbar' +import { addEdgeListener, addNodeListener } from './scripts/eventHandlers' +import setLayout from './scripts/layout' +import loadInteractions from './scripts/loadInteractions' +import cytoStyles from './cytoStyles' +import { InteractionsIcon } from './icon' +import { + Interaction, + InteractionsViewAction, + InteractionsViewData, + InteractionsViewState, + ViewData, +} from './types' + +/*-------------------- +CYTOSCAPE PLUGIN SETUP +---------------------- */ +declare module 'cytoscape-popper' { + interface PopperInstance extends TippyInstance {} +} + +/** + * Creates a Tippy.js tooltip instance. + * Note: tried to make a seperate type for content, but it was causing a bunch of errors so switched to any and added contnet object keys to jsdoc + * @param {Object} ref - Reference to the element for which the tooltip is created. + * @param {Function} ref.getBoundingClientRect - neccessary for proper typing + * @param {Object} content - Content and configuration for the tooltip. + * @param {string | HTMLElement} content.content - The content to display inside the tooltip. + * @param {boolean} content.arrow - Whether to display an arrow on the tooltip. + * @param {boolean} content.followCursor - Whether the tooltip should follow the cursor. + * @param {number | [number, number]} content.delay - Delay in showing and hiding the tooltip. + * @param {string} content.animation - The animation type for the tooltip. + * @param {number} content.duration - Duration of the tooltip animation. + * @param {boolean} content.interactive - Whether the tooltip is interactive. + * @param {number} content.interactiveBorder - The size of the border around the tooltip where interaction is allowed. + * @returns {Tooltip} Returns a tooltip instance. + */ +function createTooltip(ref: { getBoundingClientRect: any }, content: any) { + // Since tooltip constructor requires DOM element/elements, create a placeholder + const dummyDomElement = document.createElement('div') + console.log(content) + const config: Partial = { + getReferenceClientRect: ref.getBoundingClientRect, + // touch: add this later for touch screen capabilities + // DOM element inside the tooltip: + content: content.content, + // your own preferences: + arrow: content.arrow, + placement: 'top', + delay: [1000, 1000], + animation: 'fade', + followCursor: content.followCursor, + duration: content.duration, + sticky: false, + interactive: content.interactive, + interactiveBorder: 3, + appendTo: document.body, // or append dummyDomEle to document.body + plugins: [followCursor, sticky], + } + const tip = tippy(dummyDomElement, config) + return tip +} + +cytoscape.use(popper(createTooltip)) +cytoscape.use(automove) +cytoscape.use(coseBilkent) +/* -------------------------------- */ +declare module '@mui/material/IconButton' { + interface ButtonPropsColorOverrides { + custom: true + } +} +const InteractionsViewer: View = { + name: 'Interactions Viewer', + id: 'interactions-viewer', + + icon: () => , + description: 'Interactions Viewer.', + citation() { + return
+ }, + async getInitialData( + gene: GeneticElement | null, + loadEvent: (progress: number) => void + ) { + let data: ViewData = { + nodes: [], + edges: [], + loadFlags: { + empty: true, + existsPDI: false, + existsPPI: false, + recursive: false, + }, + } + + if (gene) { + let recursive: string, interactions: Array + const query = gene.id.toUpperCase() + const url = + 'https://bar.utoronto.ca/eplant/cgi-bin/get_interactions_dapseq.py?locus=' + + query + try { + // Fetch interaction data + const response = await fetch(url) + const json = await response.json() + const interactionsData = json[query] + + if (interactionsData === undefined) { + recursive = 'false' + interactions = [] + } else { + // recursive is always the last element in the array + recursive = interactionsData[interactionsData.length - 1] + // the interaction are everythign else + interactions = interactionsData.slice(0, interactionsData.length - 1) + } + // Load interactions + data = loadInteractions(gene, interactions, recursive) + } catch (error) { + throw ViewDataError.UNSUPPORTED_GENE + } + } + return { + activeView: InteractionsViewer.id, + viewData: data, + } + }, + component({ + activeData, + state, + dispatch, + geneticElement, + }: ViewProps< + InteractionsViewData, + InteractionsViewState, + InteractionsViewAction + >) { + const [cyto, setCyto] = useState(cytoscape()) + const cyRef = useRef(null) + const theme = useTheme() + const geneId = geneticElement?.id + const viewData = activeData?.viewData || { + nodes: [], + edges: [], + loadFlags: { + empty: true, + existsPDI: false, + existsPPI: false, + recursive: false, + }, + } + const elements: any = [...(viewData.nodes || []), ...(viewData.edges || [])] + + // Snackbar state + const [snackbarOpen, setSnackbarOpen] = useState(true) + + useEffect(() => { + const cy: Core = cytoscape({ + container: document.getElementById('cy'), // container to render in + elements: elements, + style: cytoStyles, + }) + + setCyto(cy) + + setLayout(cy, viewData.loadFlags) + // Listen for mouseover events on nodes + addNodeListener(cy) + // Listen for mouseover events on edges + addEdgeListener(cy) + }, []) + + /** + * Function to close the Snackbar */ + const handleCloseSnackbar = () => { + setSnackbarOpen(false) + } + return ( +
+ {/* TOPBAR - contains legend and filter buttons */} + + {/* CYTOSCAPE - container to render cytoscape */} +
+ {/* SNACKBAR - alerts user what to do if protein localization colours are not visible*/} + + ({ + '& .MuiAlert-icon': { + color: theme.palette.primary.main, // Change the icon color if needed + marginTop: '5px', + }, + width: '300px', + fontSize: '0.875rem', + padding: '8px 16px', + maxHeight: '100px', // Limit height + overflow: 'auto', // Add scroll if content overflows + })} + action={ + + + + } + > + Are protein localization colours not visible? Interact with the view + to fix + + +
+ ) + }, +} +export default InteractionsViewer diff --git a/Eplant/views/InteractionsViewer/scripts/eventHandlers.ts b/Eplant/views/InteractionsViewer/scripts/eventHandlers.ts new file mode 100644 index 00000000..c74c2e22 --- /dev/null +++ b/Eplant/views/InteractionsViewer/scripts/eventHandlers.ts @@ -0,0 +1,286 @@ +import { Core, EventObject } from 'cytoscape' +import { PopperInstance } from 'cytoscape-popper' + +// Global +let cy: Core + +// -------------- +// Event Listeners +// -------------- +/** + * Add event listener for nodes + * @param {Core} cyto cytoscape instance + * @returns {None} + **/ +export const addNodeListener = (cyto: Core) => { + cy = cyto + cy.on('mouseover', 'node', (event: EventObject) => { + const nodeId = event.target.data('id') + // Check that the node is not a compound node + if (nodeId !== 'COMPOUND_DNA' && nodeId !== 'COMPOUND_PROTEIN') { + if (nodeId.substring(0, 3) === 'chr') { + handleChrNodeHover(event) + } else { + handleNodeHover(event) + } + } + }) +} + +/** + * Add event listener for edges connecting nodes\ + * @param {Core} cy + * @returns {None} + **/ +export const addEdgeListener = (cy: Core) => { + // Listen for pointer events on edges + cy.on('mouseover', 'edge', (event: EventObject) => { + // No tooltip on chr edges + if (event.target._private.classes.values().next().value == 'chr-edge') { + return false + } + handleEdgeHover(event) + }) +} + +// -------------- +// Event Handlers +// -------------- +/** + * Handle hover over edge node and create appropriate tooltip + * @param {EventObject} event the current event object + * @returns {void} + **/ +const handleNodeHover = (event: EventObject) => { + const node = event.target + const id = node._private.data.content + fetch( + 'https://bar.utoronto.ca/eplant/cgi-bin/querygene.cgi?species=Arabidopsis_thaliana&term=' + + id + ) + .then((response) => response.json()) + .then((gene) => { + const tip: PopperInstance = node.popper({ + content: () => { + const content = document.createElement('div') + + content.innerHTML = ` + +
+ + + + + + + + + + + + + + + +
${gene.id}
+ ${ + gene.aliases.length > 0 ? gene.aliases.slice(0, 3) : 'N/A' + } +
+ ${gene.annotation != '' ? gene.annotation : 'N/A'} +
+
+
` + const props = { + content: content, + duration: 200, + arrow: false, + followCursor: false, + interactive: true, + } + return props + }, + }) + + tip.show() + addMouseOutListener(cy, tip) + }) +} + +/** + * Handle hover over edge connecting nodes and create appropriate tooltip + * @param {EventObject} event the current event object + * @returns {void} + **/ +const handleEdgeHover = (event: EventObject) => { + const edge = event.target + const data = edge._private.data + const references = + data.reference != 'None' + ? generateLinks(data.reference).map( + (link, i) => `${link}\n` + ) + : 'N/A' + + const tip = edge.popper({ + content: () => { + const content = document.createElement('div') + + content.innerHTML = ` + +
+

${data.tooltip}

+

Reference: \n${references}

+
` + const props = { + content: content, + duration: 1000, + arrow: true, + followCursor: true, + interactive: false, + } + return props + }, + }) + tip.show() + addMouseOutListener(cy, tip) +} + +/** + * Handle hover over chromosome node and create appropriate tooltip + * @param {EventObject} event the current event object + * @returns {void} + **/ +const handleChrNodeHover = (event: EventObject) => { + const node = event.target + const chrNum = node._private.data.id.substring(3, 4) + const genes = node._private.data.genes + const tip: PopperInstance = node.popper({ + content: () => { + const content = document.createElement('div') + + content.innerHTML = ` + +
+ + + + + + + + + +
${genes.length} Protein-DNA Interactions.
${genes.join(', ')}
+
+ ` + const props = { + content: content, + duration: 200, + arrow: false, + followCursor: false, + interactive: true, + } + return props + }, + }) + tip.show() + addMouseOutListener(cy, tip) +} + +/** + * Destroys tooltip on mouse out + * @param {Core} cyto cytoscape instance + * @param {PopperInstance} tip the tooltip to destroy + * @returns {void} + **/ +const addMouseOutListener = (cyto: Core, tip: PopperInstance) => { + // add handler to node for mouse leave + cy.on('mouseout', 'node', (event) => { + const nodeID = event.target.data('id') + if (nodeID !== 'COMPOUND_DNA' && nodeID !== 'COMPOUND_PROTEIN') { + tip.destroy() + } + }) + // destroy tooltip on edge mouse out + cy.on('mouseout', 'edge', (event) => { + tip.destroy() + }) +} + +// --------------- +// Helper Functions +// ---------------- +/** + * Generate sanitized links from reference string + * @param {string} reference unsanitized reference string + * @returns {string[]} array of links + **/ +const generateLinks = (reference: string): string[] => { + const AL1_HYPERLINK = 'http://interactome.dfci.harvard.edu/A_thaliana/' + + // Sanitize the reference + const sanitizedReference = reference.split('\n') + const hyperlinks = [] + + for (let i = 0; i < sanitizedReference.length; i = i + 1) { + // Processes links by reference type + if (sanitizedReference[i].search('PubMed') !== -1) { + // Append PubMed link to array + const subReference = sanitizedReference[i].replace('PubMed', '') + hyperlinks.push('http://www.ncbi.nlm.nih.gov/pubmed/' + subReference) + } else if (sanitizedReference[i].search('doi:') !== -1) { + // Append doi link to array + const subReference = sanitizedReference[i].replace('doi:', '') + hyperlinks.push('http://dx.doi.org/' + subReference) + } else if (sanitizedReference[i].search('AI-1') !== -1) { + // Append static AL1 link to array + hyperlinks.push(AL1_HYPERLINK) + } + } + return hyperlinks +} diff --git a/Eplant/views/InteractionsViewer/scripts/filterLogic.ts b/Eplant/views/InteractionsViewer/scripts/filterLogic.ts new file mode 100644 index 00000000..55549c93 --- /dev/null +++ b/Eplant/views/InteractionsViewer/scripts/filterLogic.ts @@ -0,0 +1,54 @@ +import { Core } from 'cytoscape' + +/** + * Applies filter to edges matching selector\ + * @param {Core} cy cytoscape instance + * @param {boolean} status The related filterStatus index + * @param {String} selector The selector by which to filter edges + * @returns {void} + **/ +export const applyFilter = (cy: Core, status: boolean, selector: string) => { + if (status) { + const edges = cy.edges(selector) + // @ts-expect-error hide should exists? + edges.hide() + } +} + +/** + * Hide all layers of node matching id] + * @param {Core} cy cytoscape instance + * @param {string} id id of the node to hide + * @returns {void} + **/ +export const cleanCompoundNode = (cy: Core, id: string) => { + if (cy.nodes('[parent = "' + id + '"]:visible').length === 0) { + // @ts-expect-error hide should exists? + cy.nodes('#' + id).hide() + } +} + +/** + * Clears interaction view of nodes without associated edges + * @param {Core} cy cytoscape instance + * @returns {void} + */ +export const cleanNodes = (cy: Core) => { + // Get all nodes in interaction view + const nodes = cy.nodes() + for (let n = 0; n < nodes.length; n = n + 1) { + const node = nodes[n] + const type = node.data('id').substring(9) + + // Remove nodes with no connecting interactions + const isOrphaned = node.connectedEdges(':visible').length === 0 + + if (type === 'DNA_NODE' && isOrphaned) { + // @ts-expect-error hide should exists? + node.hide() + } else if (type === 'PROTEIN_NODE' && isOrphaned) { + // @ts-expect-error hide should exists? + node.parent.hide() + } + } +} diff --git a/Eplant/views/InteractionsViewer/scripts/layout.ts b/Eplant/views/InteractionsViewer/scripts/layout.ts new file mode 100644 index 00000000..82961ec5 --- /dev/null +++ b/Eplant/views/InteractionsViewer/scripts/layout.ts @@ -0,0 +1,292 @@ +/** @format */ + +import { Core, NodeCollection, NodeSingular } from 'cytoscape' + +import { LoadFlags, Node } from '../types' + +let cy: Core +let loadFlags: LoadFlags + +/** + * Used to lay out nodes. DNA nodes are positioned in alignment, while + * protein nodes are positioned by layout. + * @returns {void} + */ +const setLayout = (cytoscape: Core, flags: LoadFlags) => { + cy = cytoscape + loadFlags = flags + if (!loadFlags.empty && cy != null) { + if (cy.nodes('[id $= "PROTEIN_NODE"]').length > 0) { + positionProtein() + } //else {cb();} ?? dont know what this does + if (loadFlags.existsPDI) { + //this.positionDNA(); + positionChr() + } + } + // Use Cytoscape Automove to make protein compounds move in sync + // @ts-expect-error addon typing error no fix, still works + cy.automove({ + nodesMatching: (node: Node) => { + const type = node._private.data.id.substring(9) + return type === 'PROTEIN_NODE' || type === 'QUERY_NODE' + }, + reposition: (node: Node) => { + const pos = node.position() + // Set the back node to have the same position + const backNode = node.siblings() + backNode.positions(pos) + return pos + }, + when: 'matching', + }) + cy.$('node[id $= "QUERY_NODE"]').position({ x: -30, y: 20 }) + cy.minZoom(0.2) + cy.fit() +} +export default setLayout + +/** + * Calls layout on protein nodes. + * @returns {void} + */ +const positionProtein = () => { + // get nodes + const proteinNodes = cy.nodes('[id $= "PROTEIN_NODE"]') + if (loadFlags.existsPDI || proteinNodes.length < 100) { + // Layout proteins for PDI + const layout = proteinNodes + .layout({ + name: 'cose-bilkent', + // Whether to fit the network view after when done + // @ts-expect-error error with fit, even when documentation says it should work + fit: false, + // Node repulsion (non overlapping) multiplier + nodeRepulsion: 5000, + // Maximum number of iterations to perform + numIter: 7500, + // For enabling tiling (Must be false, or error occurs) + tile: false, + // Type of layout animation. The option set is {'during', 'end', false} + animate: false, + randomize: true, + // Stop callback + stop: function () { + transformAverage(proteinNodes, loadFlags.existsPDI) + positionProteinBack(proteinNodes) + // cb(); ?? + }, + }) + .run() + } else { + const layout = proteinNodes + .layout({ + name: 'cose-bilkent', + // @ts-expect-error error with fit, even when documentation says it should work + fit: true, + randomize: true, + stop: function () { + transformAverage(proteinNodes, false) + positionProteinBack(proteinNodes) + // cb() ?? + }, + }) + .run() + } +} + +/** + * Updates the position of protein back nodes to be the same as protein node bodies. + * @param {Collection} nodes The collection of node bodies + * @return {void} + */ +const positionProteinBack = (nodes: NodeCollection) => { + for (let i = 0; i < nodes.length; i++) { + // @ts-expect-error typing error with _private, if removed breaks functionality + const position = nodes[i]._private.position + // @ts-expect-error typing error with _private, if removed breaks functionality + const id = nodes[i]._private.data.id.substring(0, 9) + console.log(`Updating position of ${id}PROTEIN_BACK to`, position) + cy.$('#' + id + 'PROTEIN_BACK').position(position) + } +} + +/** + * Positions Chr nodes + * @return {void} + */ +const positionChr = () => { + // Get DNA nodes + const chrNodes = cy.$('[id ^= "chr"]') + // Get DNA node positions + const chrPositions = positionDNALinear(chrNodes.length) + // Update position + for (let i = 0; i < chrNodes.length; i++) { + const x = chrPositions[i][0] + const y = chrPositions[i][1] + const id = '#' + chrNodes[i].data('id') + cy.$(id).position({ x: x, y: y }) + } +} + +// ---------------- +// Helper functions +// ---------------- +/** + * Transform the collection of protein nodes to an area to the average right of the query node. + * + * @param {Array} nodes The array of nodes to transform + * @param {Boolean} offset Controls whether nodes are offset off query x position + * @return {void} + */ +const transformAverage = (nodes: NodeCollection, offset: boolean) => { + let minX = 10000 + let maxY = -10000 + let minY = 10000 + + let avgX = 0 + let avgY = 0 + + // Get range and average of values + for (let n = 0; n < nodes.length; n++) { + const posX = nodes[n].position('x') + const posY = nodes[n].position('y') + minX = posX < minX ? posX : minX + minY = posY < minY ? posY : minY + maxY = posY > maxY ? posY : maxY + + avgX += posX + avgY += posY + } + + const shiftX = 100 > minX ? 100 - minX : 0 + avgX = offset ? shiftX : avgX / nodes.length + avgY = avgY / nodes.length + + // Transform positions + nodes.positions((node: NodeSingular, i: number) => { + const curX = node.position('x') + const curY = node.position('y') + return { + x: offset ? curX + avgX : curX - avgX, + y: curY - avgY, + } + }) +} +/** + * Determines Y coordinate for individual nodes with even spacing + * + * @param {Number} numNodes The amount of nodes to be positioned + * @return {List} coordinates The calculated (x, y) coordinates + */ +const positionDNALinear = (numNodes: number) => { + const x = -350 + const midpoint = 0 + let coordinates: Array> = [] + const increment = 100 + // Assign values to coordinates + if (numNodes <= 0) { + // Return empty coords + coordinates = [] + } else if (numNodes === 1) { + // Return midpoint + coordinates.push([x, midpoint]) + } else if (numNodes % 2 === 0) { + // Adds coordinates symmetrically from the midpoint. + // The midpoint is placed between the two middle coordinates. + for (let n = 0; n < numNodes / 2; n++) { + coordinates.push([x, 50 + n * increment]) + coordinates.unshift([x, -50 - n * increment]) + } + } else { + // Add aligned center node + coordinates.push([x, midpoint]) + // Adds coordinates symmetrically from the midpoint. + for (let k = 1; k <= Math.floor(numNodes / 2); k++) { + coordinates.push([x, midpoint + k * increment]) + coordinates.unshift([x, midpoint - k * increment]) + } + } + return coordinates +} + +/** + * Generates the coordinates to lay out DNA nodes in a semicircle + * @param {Number} numNodes The number of nodes to lay out + * @returns {Array} The computed coordinate array [(x,y)..] in a semi-circle + */ +const positionDNACircular = (numNodes: number) => { + // Set bounds for semi-circle (in radians) + let topLimit + let bottomLimit + if (numNodes > 80) { + // Increase arc size past vertical if many nodes + topLimit = Math.PI / 2 - Math.PI / 8 + bottomLimit = Math.PI * 1.5 + Math.PI / 8 + } else { + topLimit = Math.PI / 2 + bottomLimit = Math.PI * 1.5 + } + + // Angle in radians between nodes + const increment = (bottomLimit - topLimit) / numNodes + + // Rows of nodes to stagger + let rows = 2 + if (numNodes > 75) { + rows += 1 + Math.floor(numNodes / 80) + } + // Counter to track current row + let j = 1 + + // Final array of x,y coordinates of nodes + const coordArray: Array> = [] + + for (let i = topLimit; i < bottomLimit; i += increment) { + // Determine radius and distance between nodes + let radius + let separationWeight + if (numNodes > 400) { + radius = (10 - rows) * numNodes + separationWeight = 1 + rows * 0.1 + } else if (numNodes > 100) { + radius = (10 - 1.1 * rows) * numNodes + separationWeight = 1 + rows * 0.1 + } else { + radius = 7.5 * numNodes + separationWeight = 1 + rows * 0.3 + } + // Stagger rows, weight radius by number of nodes + // NOTE: can possibly implement switch case here + if (j % rows === 7) { + radius += separationWeight * 315 + } else if (j % rows === 6) { + radius += separationWeight * 270 + } else if (j % rows === 5) { + radius += separationWeight * 225 + } else if (j % rows === 4) { + radius += separationWeight * 180 + } else if (j % rows === 3) { + radius += separationWeight * 135 + } else if (j % rows === 2) { + radius += separationWeight * 90 + } else if (j % rows === 1) { + radius += separationWeight * 45 + } + j++ + coordArray.unshift(trigCalculator(radius, i)) + } + return coordArray +} + +/** + * Generates the x-y coordinates of nodes using trigonometry + * @param {Number} radius The radius of the interaction edge + * @param {Number} angle The angle of the interaction edge in radians + * @returns {Tuple} Returns a tuple of (x, y) + */ +const trigCalculator = (radius: number, angle: number) => { + const xCoord = radius * Math.cos(angle) + const yCoord = radius * Math.sin(angle) + return [xCoord, yCoord] +} diff --git a/Eplant/views/InteractionsViewer/scripts/loadInteractions.ts b/Eplant/views/InteractionsViewer/scripts/loadInteractions.ts new file mode 100644 index 00000000..df00ad1d --- /dev/null +++ b/Eplant/views/InteractionsViewer/scripts/loadInteractions.ts @@ -0,0 +1,757 @@ +/** @format */ + +import GeneticElement from '@eplant/GeneticElement' + +import { Interaction, LoadFlags, RawEdge, RawNode } from '../types' + +import loadSublocalizations from './loadSublocalizations' + +let query = '' +let geneticElement: GeneticElement +let loadFlags: LoadFlags = { + empty: true, + existsPDI: false, + existsPPI: false, + recursive: false, +} +let nodes: RawNode[] +let edges: RawEdge[] + +/** Main function to get the cytoscape flags, create nodes from interactions, and then add subloc info to the nodes + * @param {GeneticElement} gene + * @param {Interaction[]} data array of interactions returned from webservice + * @param {string} recursive whether the interactions are recursive + * @returns + */ +const loadViewData = ( + gene: GeneticElement, + data: Interaction[], + recursive: string +) => { + nodes = [] + edges = [] + query = gene.id.toUpperCase() + geneticElement = gene + getLoadFlags(data, recursive) + loadInteractions(data) + nodes = loadSublocalizations(nodes) + return { + nodes: nodes, + edges: edges, + loadFlags: loadFlags, + } +} +export default loadViewData + +// ================= +// Handler functions +// ================= +/** + * Get flags used in futher loading + * * empty{boolean}: Whether interactions exist in data + * * existsPDI{boolean}: Whether protein-dna interactions exist in data + * * existsPPI{boolean}: Whether protein-protein interactions exist in data + * * recursive{boolean}: Whether data includes recursive interactions + * @param {Object} data JSON format interaction data + * @return {Object} flags + * + */ +const getLoadFlags = (data: Interaction[], recursive: string) => { + const flags = { + empty: checkEmpty(data), + existsPDI: checkExistsPDI(data), + existsPPI: checkExistsPPI(data), + recursive: checkRecursive(data, recursive), + } + loadFlags = flags +} +/** + * Convert interactions from JSON to cytoscape node/edges without PDIs + * @param {Object} data Interaction data from JSON + * @return {void} + */ +const loadInteractions = (data: Interaction[]) => { + if (!loadFlags.empty) { + // Create top level compound nodes + if (loadFlags.existsPDI) { + createCompoundDNA() + if (loadFlags.existsPPI) { + createCompoundProtein() + } + } + + // Load interactions + if (loadFlags.existsPDI) { + loadInteractionsChr(data) + } else { + loadInteractionsNoDNA(data) + } + } else { + createQueryNode(query) + } +} + +/** + * Generate chromosome-node interactions + * @return {void} + */ +const loadInteractionsChr = (data: Interaction[]) => { + createQueryNode(query) + createChromosomes(data) + const createFunctions = [createSelfQPI, createQPI, createPPI, createChr] + createInteractions(createFunctions, data) +} + +/** + * Convert interactions from JSON to cytoscape node/edges without PDIs + * @return {void} + */ +const loadInteractionsNoDNA = (data: Interaction[]) => { + createQueryNode(query) + const createFunctions = [createSelfQPI, createQPI, createPPI] + createInteractions(createFunctions, data) +} + +// ============================ +// Cytoscape creation Functions +// ============================ +/** + * Creates interactions using creation functions + * @param {Array} funcArr Array of functions which to call to construct graph + * @return {void} + */ +const createInteractions = ( + funcArray: Array<(data: Interaction) => boolean>, + data: Interaction[] +) => { + data = data.slice() + for (let n = 0; n < funcArray.length; n++) { + const addedIndices = [] + for (let i = 0; i < data.length - 1; i++) { + const re = /^At[\dCM]g\d{5}$/i + if ( + re.test(data[i].source) && + re.test(data[i].target) && + funcArray[n](data[i]) + ) { + addedIndices.unshift(i) + } + } + + for (let k = 0; k < addedIndices.length; k++) { + data.splice(addedIndices[k], 1) + } + } + + if (data.length > 1) { + console.log(data) + console.error('Error: ' + data.length + ' interactions not processed.') + } +} +/** + * Create nodes for chromosomal nodes + * @return {void} + */ +const createChromosomes = (data: Interaction[]) => { + const chrs: string[] = [] + const chrNums: Record = { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + } + const methods: Record = { + '1': 'P', + '2': 'P', + '3': 'P', + '4': 'P', + '5': 'P', + C: 'P', + M: 'P', + } + for (let k = 0; k < data.length - 1; k++) { + const chr = data[k].target.substring(2, 3) + if (data[k].index === '2') { + chrNums[chr]++ + if (!chrs.includes(chr)) { + chrs.push(chr) + } + } + // Method + if (data[k].index === '2' && data[k].published == true) { + methods[chr] = 'E' + } + } + for (const chr in chrNums) { + if (chrNums[chr] === 0) delete chrNums[chr] + } + + let i = 0 + for (const c in chrNums) { + createChromosomeNode(chrs[i], chrNums[c]) + createChromosomeEdge(chrs[i], methods[c]) + i++ + } +} + +// ============= +// Node creators +// ============= +/** + * Creates top level dna compound node + * @return {void} + */ +const createCompoundDNA = () => { + const dnaCompound = { + group: 'nodes', + data: { + id: 'COMPOUND_DNA', + }, + classes: 'compound-top', + } + nodes.push(dnaCompound) +} + +/** + * Creates top level protein compound node + * @return {void} + */ +const createCompoundProtein = () => { + const proteinCompound = { + group: 'nodes', + data: { + id: 'COMPOUND_PROTEIN', + }, + classes: 'compound-top', + } + nodes.push(proteinCompound) +} + +/** + * Create the query node; the one which user has entered + * @param {String} query ID of query gene + * @return {void} + */ +const createQueryNode = (query: string) => { + const compound = { + group: 'nodes', + data: { + id: query + 'QUERY_COMPOUND', + }, + classes: 'protein-compound', + } + + const border = { + group: 'nodes', + data: { + id: query + 'QUERY_BACK', + parent: query + 'QUERY_COMPOUND', + }, + classes: 'protein-back', + } + + const node = { + group: 'nodes', + data: { + id: query + 'QUERY_NODE', + content: query, + geneticElement: geneticElement, + parent: query + 'QUERY_COMPOUND', + }, + classes: 'protein-node loaded', + } + nodes.push(compound, border, node) +} +/** + * Create Protein Nodes. Consists of three nodes: regular protein body, a pie node for border, + * and a compound container to keep nodes together. + * @param {String} id ID of gene to represent + * @return {Object} Node object + */ +const createProteinNode = (id: string) => { + id = id.toUpperCase() + const newGeneticElement = geneticElement + // let newGeneticElement = geneticElement.species.api.searchGene(id) + const compound = { + group: 'nodes', + data: { + id: id + 'PROTEIN_COMPOUND', + parent: '', + }, + classes: 'protein-compound', + } + + const border = { + group: 'nodes', + data: { + id: id + 'PROTEIN_BACK', + parent: id + 'PROTEIN_COMPOUND', + }, + classes: 'protein-back', + } + + const node = { + group: 'nodes', + data: { + id: id + 'PROTEIN_NODE', + content: id, + geneticElement: newGeneticElement, + parent: id + 'PROTEIN_COMPOUND', + }, + classes: 'protein-node', + } + + if (loadFlags.existsPDI) { + compound.data.parent = 'COMPOUND_PROTEIN' + } + nodes.push(compound, border, node) + return { compound: compound, border: border, node: node } +} + +/** + * Create no interactions node + * @return {void} Node object + */ +const createNoInteractionNode = () => { + const noInteractionNode = { + group: 'nodes', + data: { + id: 'noInteractionLabel', + }, + position: { + x: 0, + y: 0, + }, + } + nodes.push(noInteractionNode) +} + +/** + * Create chromosomal node + * @param {Number} id Chromosomal number + * @param {Number} n Protein DNA interactions number + * @return {Object} Node object + */ +const createChromosomeNode = (id: string, n: number) => { + const node = { + data: { + id: 'chr' + id, + content: 'Chr ' + id + ': ' + n + ' PDIs', + parent: 'COMPOUND_DNA', + genes: [], + }, + classes: 'dna-node', + } + nodes.push(node) + return { node: node } +} + +// ================================== +// Edge Creators and Helper Functions +// ================================== +// -------- +// Creators +// -------- +/** + * Create edges representing PPIs + * @param {Object} data JSON interaction data + * @return {void} + */ +const createProteinEdge = (data: Interaction) => { + // Gets method used to determine interaction + const method = data.reference === 'None' ? 'P' : 'E' + + let source = data.source.toUpperCase() + let target = data.target.toUpperCase() + + source = source === query ? source + 'QUERY_NODE' : source + 'PROTEIN_NODE' + target = target === query ? target + 'QUERY_NODE' : target + 'PROTEIN_NODE' + + let edge = { + data: { + source: source, + target: target, + tooltip: '', + type: 'PPI', + method: method, + correlation: data.correlation_coefficient, + interolog_conf: 0.0, + reference: 'None', + // css styles + size: 0, + lineStyle: '', + lineColor: '', + }, + classes: 'protein-edge', + } + + if (method === 'P') { + edge.data.interolog_conf = data.interolog_confidence + } + + if (data.reference !== 'None') { + edge.data.reference = data.reference + } + + // @ts-expect-error unknown type errror + edge = setProteinEdgeStyles(edge) + edge.data.tooltip = setEdgeTooltipContent(edge) + // edgesPush(edge) + edges.push(edge) +} + +/** + * Create interaction to chromosomal node + * Asher: Old function not used anymore + * @param {Number} id Chromosomal number + * @param {String} method 'P' | 'E' -> method used to determine interaction + * @return {void} + */ +const createChromosomeEdge = (id: string, method: string) => { + let source = geneticElement.id.toUpperCase() + source = source === query ? source + 'QUERY_NODE' : source + 'PROTEIN_NODE' + let edge: RawEdge = { + data: { + source: source, + target: 'chr' + id, + tooltip: '', + type: 'PDI', + method: method, + // css styles + size: 0, + lineStyle: '', + lineColor: '', + arrowColor: '', + }, + classes: 'chr-edge', + } + edge = setDNAEdgeStyles(edge) + edge.data.tooltip = setEdgeTooltipContent(edge) + edges.push(edge) +} +// ------- +// Helpers +// ------- +/** + * Sets edge styles for protein edges + * @param {Object} edge The edge object with completed data entry + * @return {Object} Edge object with styles + */ +const setProteinEdgeStyles = (edge: RawEdge): RawEdge => { + // Set edge style and size based on confidence + edge.data.lineStyle = 'solid' + if (edge.data.method === 'E') { + edge.data.size = 6 + // @ts-expect-error occurs because protein edge and chromsoome edge must me lumped into the same type (RawEdge) + } else if (edge.data.interolog_conf > 10) { + edge.data.size = 6 + // @ts-expect-error occurs because protein edge and chromsoome edge must me lumped into the same type (RawEdge) + } else if (edge.data.interolog_conf > 5) { + edge.data.size = 4 + // @ts-expect-error occurs because protein edge and chromsoome edge must me lumped into the same type (RawEdge) + } else if (edge.data.interolog_conf > 2) { + edge.data.size = 1 + } else { + edge.data.lineStyle = 'dashed' + edge.data.size = 1 + } + + if (edge.data.method === 'E') { + edge.data.lineColor = '#99CC00' + // @ts-expect-error occurs because protein edge and chromsoome edge must me lumped into the same type (RawEdge) + } else if (edge.data.correlation > 0.8) { + edge.data.lineColor = '#B1171D' + // @ts-expect-error occurs because protein edge and chromsoome edge must me lumped into the same type (RawEdge) + } else if (edge.data.correlation > 0.7) { + edge.data.lineColor = '#D32E09' + // @ts-expect-error occurs because protein edge and chromsoome edge must me lumped into the same type (RawEdge) + } else if (edge.data.correlation > 0.6) { + edge.data.lineColor = '#E97911' + // @ts-expect-error occurs because protein edge and chromsoome edge must me lumped into the same type (RawEdge) + } else if (edge.data.correlation > 0.5) { + edge.data.lineColor = '#EEB807' + } else { + edge.data.lineColor = '#A0A0A0' + } + + return edge +} + +/** + * Sets edge styles for DNA edges (Chromosome Edges) + * @param {Object} edge The edge object with completed data entry + * @return {Object} Edge object with styles + */ +const setDNAEdgeStyles = (edge: RawEdge) => { + // Set edge defaults + if (edge.data.method == 'E') { + edge.data.lineStyle = 'solid' + edge.data.size = 6 + edge.data.lineColor = '#669900' // Green + edge.data.arrowColor = '#669900' + } else { + edge.data.lineStyle = 'dashed' + edge.data.size = 1 + edge.data.lineColor = '#A0A0A0' // Grey + edge.data.arrowColor = '#A0A0A0' + } + + return edge +} +/** + * Generate the tooltip associated with an edge from interaction data + * @param {Object} edge The cyConf edge object + * @return {void} + */ +const setEdgeTooltipContent = (edge: RawEdge) => { + // First line declaring type + const typeString = edge.data.type === 'PDI' ? 'DNA' : 'Protein' + let firstLine = 'Protein-' + typeString + ' Interaction' + // Add method of determination + if (edge.data.method === 'E') { + firstLine += ' (E)' + } else { + firstLine += ' (P)' + } + // Remaining lines containing data + let dataLines = '' + if (edge.data.type !== 'PDI') { + if (edge.data.method === 'P') { + dataLines += 'Confidence(Interolog): ' + edge.data.interolog_conf + '
' + } + dataLines += 'Co-expression coefficient: ' + edge.data.correlation + '
' + } + + const final = firstLine + '
' + dataLines + return final +} +// ---------------- +// Create Functions +// ---------------- +/** + * Check if a node already exists in the collection of all nodes + * @param {String} searchID The ID of the element to be compared against the collection + * @return {Boolean} Returns true if a node with the same id already exists + */ +const checkNodeExists = (searchID: string) => { + // Checks if current interaction source exists as a node + for (let n = 0; n < nodes.length; n++) { + // Compares interaction with existing node elements + if (nodes[n].data.id.toUpperCase() === searchID) { + return true + } + } + return false +} +/** + * Create interaction from query node to itself. + * @param {Object} data Object containing interaction data + * @return {Boolean} Whether an interaction was created + */ +const createSelfQPI = (data: Interaction) => { + // Verify that the inputted index is correct + const index = Number(data.index) + const sourceID = data.source.toUpperCase() + const targetID = data.target.toUpperCase() + + // Check if the source and target nodes are the query node + const isQuerySource = sourceID === query + const isQueryTarget = targetID === query + if (index < 2 && isQuerySource && isQueryTarget) { + createProteinEdge(data) + return true + } + return false +} + +/** + * Create interactions from Query to Proteins. + * + * @param {Object} data The object which contains data for this interaction + * @return {Boolean} Whether a QPI was created + */ +const createQPI = (data: Interaction) => { + const index = Number(data.index) + // Store interaction data + const sourceID = data.source.toUpperCase() + const targetID = data.target.toUpperCase() + + // Checks if the source node is the query node + const isQuerySource = sourceID === query + // Checks if the target node is the query node + const isQueryTarget = targetID === query + + // Create interaction if above conditions are met. Interaction must be PPI, and source and + // target must be different, as self interctions should not be handled. + if (index < 2 && sourceID !== targetID && (isQuerySource || isQueryTarget)) { + // Add appropriate identifier tag to source + let existsSource + let existsTarget + if (isQuerySource) { + existsSource = true + existsTarget = checkNodeExists(data.target + 'PROTEIN_NODE') + } else { + existsSource = checkNodeExists(data.source + 'PROTEIN_NODE') + existsTarget = true + } + + // Create source node if not pre-existing + if (!existsSource) { + createProteinNode(data.source.toUpperCase()) + } + + // Create target node if not pre-existing + if (!existsTarget) { + createProteinNode(data.target.toUpperCase()) + } + + // Create an interaction if not pre-existing + if (!existsTarget || !existsSource) { + createProteinEdge(data) + return true + } + } + return false +} + +/** + * Creates protein-protein interactions which do not include the query node. + * Must be executed after the createQPI method has run. + * This ensures that all PPIs will have an origin from a query node rooted protein. + * This method will include the creation of self PPIs. + * + * @param {Object} data Object containing interaction data + * @return {Boolean} Whether an interaction was created + */ +const createPPI = (data: Interaction) => { + const index = Number(data.index) + // Store interaction data + const sourceID = data.source.toUpperCase() + const targetID = data.target.toUpperCase() + + // Checks that both the source and target nodes are pre-existing + const existsProteinSource = checkNodeExists(sourceID + 'PROTEIN_NODE') + const existsProteinTarget = checkNodeExists(targetID + 'PROTEIN_NODE') + + // Check that source and target nodes are not the query node + const existsQuerySource = checkNodeExists(sourceID + 'QUERY_NODE') + const existsQueryTarget = checkNodeExists(targetID + 'QUERY_NODE') + + const existsQuery = existsQuerySource || existsQueryTarget + + if ( + index < 2 && + (existsProteinSource || existsProteinTarget) && + !existsQuery + ) { + // Create source node if not pre-existing + if (!existsProteinSource) { + createProteinNode(data.source.toUpperCase()) + } + + // Create target node if not pre-existing + if (!existsProteinTarget) { + // Create target node + createProteinNode(data.target.toUpperCase()) + } + + createProteinEdge(data) + + return true + } + return false +} + +/** + * Creates DNA interactions assigned to chromosomal nodes + * @param {Object} JSON data object + * @return Whether an interaction was created + */ +const createChr = (data: Interaction) => { + if (data.index !== '2') { + return false + } + const chr = data.target.substring(2, 3) + const chrNode = nodes.filter(function (item) { + return item.data.id === 'chr' + chr + })[0] + + // Predicted DNA + // Asher + if (data.published == false && data.index === '2') { + chrNode.data.genes?.push( + '' + data.target + '' + ) + } else { + chrNode.data.genes?.push( + '' + data.target + '' + ) + } + return true +} + +// =================================== +// Helper functions for getLoadFlags() +// =================================== +/** + * Returns if protein-dna interactions exists in data + * @param {Object} data JSON format interaction data + * @return {Boolean} Whether PDIs exist in data + */ +const checkExistsPDI = (data: Interaction[]) => { + if (typeof data == 'undefined') { + return false + } + for (let n = 0; n < data.length - 1; n++) { + // Checks for PDI interactions, which have an index > 1 + if (Number(data[n].index) > 1) { + return true + } + } + return false +} + +/** + * Returns if protein-protein interactions exists in data + * @param {Object} data JSON format interaction data + * @return {Boolean} Whether PDIs exist in data + */ +const checkExistsPPI = (data: Interaction[]) => { + if (typeof data == 'undefined') { + return false + } + for (let n = 0; n < data.length - 1; n++) { + // Checks for PPI interactions, which have an index < 1 + if (Number(data[n].index) < 2) { + return true + } + } + return false +} + +/** + * Check if JSON data includes recursive interactions + * @param {Array} data Last object contains recursive data + * @param {string} recursive 'yes' or 'no' is data recursive + * @return {Boolean} Whether data includes recursive interactions + */ +const checkRecursive = (data: string | any[], recursive: string) => { + if (typeof data == 'undefined') { + return false + } + return recursive === 'true' +} + +/** + * Checks if any interactions exist in data + * @param {Object} data JSON format interaction data + * @return {Boolean} Whether interactions exist + */ +const checkEmpty = (data: Interaction[]) => { + // check for undefined + if (data.length === 0) { + return true + } + return data.length < 2 +} diff --git a/Eplant/views/InteractionsViewer/scripts/loadSublocalizations.ts b/Eplant/views/InteractionsViewer/scripts/loadSublocalizations.ts new file mode 100644 index 00000000..7e99693d --- /dev/null +++ b/Eplant/views/InteractionsViewer/scripts/loadSublocalizations.ts @@ -0,0 +1,322 @@ +/** @format */ + +import { RawNode, Sublocalization } from '../types' + +let nodes: RawNode[] = [] + +/** Main function to call loadData and then assign the sublocalization colors to the proper nodes + * + * @param {RawNode[]} cynodes array of nodes with missing sublocalization data + * @returns {RawNode[]} array of nodes with proper sublocalization data + */ +const loadSublocalizations = (cynodes: RawNode[]): RawNode[] => { + nodes = cynodes + loadData().then((data) => { + nodes = setSublocalizations(data) + }) + return nodes +} +export default loadSublocalizations + +/** Extract protein IDs from nodes + * @returns {string[]} array of protein ids + */ +const getProteinIds = (): string[] => { + const ids: string[] = [] + for (let n = 0; n < nodes.length; n++) { + const id = nodes[n].data.id.substring(0, 9) + const type = nodes[n].data.id.substring(9) + + if (type === 'PROTEIN_NODE' || type === 'QUERY_NODE') { + ids.push(id) + } + } + return ids +} +/** Get IDs of genes without experimental data + * @param {Sublocalization[]} data array of objects containing gene id and sublocalization data + * @returns {string[]} the predicted gene ids + */ +const getPredictedIds = (data: Sublocalization[]): string[] => { + return data + .filter((subLoc) => subLoc.includes_experimental === 'no') + .map((subLoc) => subLoc.id) +} + +/** Get IDs of genes without experimental data + * @param {Sublocalization[]} expData array of experimental gene ids and corrosponding sublocalization data + * @param {Sublocalization[]} predictedData array of predicted gene ids and corrosponding sublocalization data + * @returns {Sublocalization[]} merged experimental and predicted gene ids and corrosponding sublocalization data + */ +const mergeData = ( + expData: Sublocalization[], + predictedData: Sublocalization[] +): Sublocalization[] => { + for (let k = 0; k < expData.length; k++) { + const subLoc = expData[k] + if (subLoc.includes_experimental === 'no') { + const predicted = predictedData.find((item) => item.id === subLoc.id) + if (predicted) { + subLoc.data = predicted.data + subLoc.includes_predicted = 'yes' + } + } + } + return expData +} +/** Load sublocalization data from webservice + * @returns {Promise} Promise containing sublocalization array + */ +const loadData = async (): Promise => { + const ids = getProteinIds() + const urlSUBA = 'https://bar.utoronto.ca/eplant/cgi-bin/groupsuba4.php' + + try { + // Fetch experimental data + const response = await fetch(urlSUBA, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + AGI_IDs: ids, + include_predicted: false, + }), + }) + const expData: Sublocalization[] = await response.json() + + // Get predicted IDs + const predIds = getPredictedIds(expData) + + if (predIds.length === 0) { + return expData // No predicted data to fetch + } + + // Fetch predicted data + const predictedResponse = await fetch(urlSUBA, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + AGI_IDs: predIds, + include_predicted: true, + }), + }) + const predictedData: Sublocalization[] = await predictedResponse.json() + + // Merge experimental and predicted data + return mergeData(expData, predictedData) + } catch (error) { + console.error('Error loading data:', error) + throw error // Re-throw the error to handle it elsewhere + } +} + +/** + * Set the sublocalization for each pie node + * @param {Sublocalization[]} data JSON sublocalization object from webservice + * @return {void} + */ +const setSublocalizations = (data: Sublocalization[]) => { + const newNodes = [] + const backNodes = [] + for (let i = 0; i < nodes.length; i++) { + if (nodes[i].data.id.includes('BACK')) { + backNodes.push(nodes[i]) + } else { + newNodes.push(nodes[i]) + } + } + + for (let n = 0; n < backNodes.length; n++) { + const id = backNodes[n].data.id.substring(0, 9) + const sublocData = data.filter((item) => { + return item.id === id + })[0] + const topLocals = sublocData ? getTopSublocals(sublocData) : [] // get top 4 sublocalizations + const predicted = sublocData ? sublocData.includes_predicted : 'no' // whether gene has predicted data + const node = setSublocalizationStyle( + topLocals, + predicted === 'yes', + backNodes[n] + ) + newNodes.push(node) + } + + return newNodes +} + +/** + * Return the top 4 sublocalizations of each node + * @param {Sublocalization} subLoc The sublocalization data for one gene + * @return {Array} Array of sublocalizations and score + */ +const getTopSublocals = (subLoc: Sublocalization) => { + const locals = subLoc.data + // Get the score of sublocalizations + const arrayLocalization = [] + for (const local in locals) { + arrayLocalization.push([local, locals[local]]) + } + + // Return top sublocalizations, up to 4 + if (arrayLocalization.length < 5) { + return arrayLocalization + } + // Sort to get largest 4th keys + arrayLocalization.sort((a, b) => { + return a[1] - b[1] + }) + return arrayLocalization.slice(-4) +} + +/** + * Set the cytoscape styles for pie nodes + * @param {Array} sublocalizations Array of top 4 sublocalizations and score + * @param {boolean} predicted Whether sublocalizations are predicted + * @param {RawNode} node Pie protein node + * @return {Object} The update pie node + */ +const setSublocalizationStyle = ( + sublocalizations: any[][], + predicted: boolean, + node: RawNode +) => { + // Calculate total sum of scores + let total = 0 + for (let n = 0; n < sublocalizations.length; n++) { + total += sublocalizations[n][1] + } + // Calculate pie size and colours + const percentages = [100, 0, 0, 0] + const colour = ['#787878', '#787878', '#787878', '#787878'] + for (let i = 0; i < sublocalizations.length; i++) { + percentages[i] = (sublocalizations[i][1] * 100) / total + colour[i] = getColour(sublocalizations[i][0]) + } + + // Set styles + node.data.pie1Size = percentages[0] + node.data.pie2Size = percentages[1] + node.data.pie3Size = percentages[2] + node.data.pie4Size = percentages[3] + node.data.pie1Colour = colour[0] + node.data.pie2Colour = colour[1] + node.data.pie3Colour = colour[2] + node.data.pie4Colour = colour[3] + node.data.height = predicted ? '46px' : '50px' + node.data.width = predicted ? '46px' : '50px' + node.data.borderWidth = 0 + + return node +} + +/** + * (NOT IN USE) create SVG donut string which will be set as the background image for the node + * @param {Array} sublocalizations Array of top 4 sublocalizations and score + * @param {boolean} predicted Whether sublocalizations are predicted + * @param {RawNode} node Pie protein node + * @return {Object} The update pie node + */ +const createSVGPieDonutStr = ( + sublocalizations: any[][], + predicted: boolean, + node: RawNode +) => { + const cyNodeSize = 50 + const SVGwidthheight = cyNodeSize + 10 + const donutCxCy = SVGwidthheight / 2 + const strokeWidth = cyNodeSize / 3 + const radius = strokeWidth + let SVGstr = '' + SVGstr += `` + SVGstr += `` + + //The below donut segment will appear for genes without SUBA data... it will be all grey + SVGstr += `` + + // Figure out which 'PCT' properties are greater than zero and then programatically add them + // as donut-segments. Note that some calculations are involved based + // on the set node size (the example given on the tutorial is based on a 100px C and 15.91 radius) + const scaling = radius / 15.91549430918952 + + // Calculate total sum of scores + let total = 0 + for (let n = 0; n < sublocalizations.length; n++) { + total += sublocalizations[n][1] + } + // Calculate pie size and colours + const pctAndColorArray = [ + { pct: 100, color: '#787878' }, + { pct: 0, color: '#787878' }, + { pct: 0, color: '#787878' }, + { pct: 0, color: '#787878' }, + ] + for (let i = 0; i < sublocalizations.length; i++) { + pctAndColorArray[i].pct = (sublocalizations[i][1] * 100) / total + pctAndColorArray[i].color = getColour(sublocalizations[i][0]) + } + + // Now have pre-sorted pctAndColorArray based on the value of the 'pct' property, order greatest to least + // Result: Show pie chart values from greatest to least starting from 12 oclock + let initialOffset = 25 * scaling // Bypass default donut parts start at 3 o'clock instead of 12 + let allSegsLength = 0 + + // Based on the sorted array we created above, let's add some 'donut segments' to the SVG string + pctAndColorArray.forEach((pctAndColor) => { + SVGstr += `` + + allSegsLength += pctAndColor.pct + + // (Circumference − All preceding segments’ total length + First segment’s offset = Current segment offset ) * scaling factor + initialOffset = (100 - allSegsLength + 25) * scaling // increase offset as we have just added a slice + }) + + SVGstr += '' + SVGstr = 'data:image/svg+xml;utf8,' + encodeURIComponent(SVGstr) // Modify for CSS via cytoscape + node.data.svgDonut = SVGstr // Last, properly mutate the node with our made SVG string + node.data.height = predicted ? '46px' : '50px' + node.data.width = predicted ? '46px' : '50px' + node.data.borderWidth = predicted ? 0 : 4 + console.log(SVGstr) + return node +} + +/** + * Return a hex colour code representing a compartment + * @param {String} compartment The compartment to represent + * @return {String} The hex colour code + */ +const getColour = (compartment: string): string => { + // Define color map + const map: Record = { + cytoskeleton: '#FF2200', + cytosol: '#E04889', + 'endoplasmic reticulum': '#D0101A', + extracellular: '#6D3F1F', + golgi: '#A5A417', + mitochondrion: '#41ABF9', + nucleus: '#0032FF', + peroxisome: '#660066', + 'plasma membrane': '#ECA926', + plastid: '#179718', + vacuole: '#F6EE3C', + } + + // Get color + let color = map[compartment] + if (!color) { + color = '#787878' + } + + // Return color + return color +} diff --git a/Eplant/views/InteractionsViewer/types.ts b/Eplant/views/InteractionsViewer/types.ts new file mode 100644 index 00000000..fd55e638 --- /dev/null +++ b/Eplant/views/InteractionsViewer/types.ts @@ -0,0 +1,114 @@ +import { EdgeSingular, NodeSingular } from 'cytoscape' + +import GeneticElement from '@eplant/GeneticElement' +/* Level 1 - API results */ +export interface Interaction { + source: string + target: string + index: string + interolog_confidence: number + correlation_coefficient: number + published: boolean + reference: string + recursive?: string +} +export interface SublocalizationData { + unclear?: number + cytosol?: number + mitochondrion?: number + plastid?: number + vacuole?: number + nucleus?: number + 'endoplasmic reticulum'?: number + extracellular?: number + golgi?: number + 'plasma membrane'?: number + peroxisome?: number +} +export interface Sublocalization { + id: string + includes_predicted: string + includes_experimental: string + data?: any +} + +/* Level 2 - Nodes and Edges - Unformatted */ +export interface RawNode { + data: NodeData + group?: string + classes?: string + position?: { + x: number + y: number + } +} +export interface RawEdge { + data: EdgeData + classes: string +} +export interface NodeData { + id: string + parent?: string + content?: string + geneticElement?: GeneticElement + genes?: string[] + svgDonut?: string + pie1Size?: number + pie2Size?: number + pie3Size?: number + pie4Size?: number + pie1Colour?: string + pie2Colour?: string + pie3Colour?: string + pie4Colour?: string + height?: string + width?: string + borderWidth?: number +} +export interface EdgeData { + source: string + target: string + tooltip: string + type: string + method: string + correlation?: number + interolog_conf?: number + reference?: string + size?: number + lineStyle?: string + lineColor?: string + arrowColor?: string +} + +/* Cytoscape */ +export interface ViewData { + nodes: RawNode[] + edges: RawEdge[] + loadFlags: LoadFlags +} +export type CyInteraction = RawNode | RawEdge +export interface LoadFlags { + empty: boolean + existsPDI: boolean + existsPPI: boolean + recursive: boolean +} +export interface Node extends NodeSingular { + _private: { + data: NodeData + } +} +export interface Edge extends EdgeSingular { + _private: { + data: EdgeData + } +} +export type NodeCollection = Node[] +export type EdgeCollection = Edge[] + +// InteractionsViewer component +export type InteractionsViewData = { + viewData: ViewData +} +export type InteractionsViewState = null +export type InteractionsViewAction = null diff --git a/Eplant/views/NavigatorViewer/Icons/Nav_CellEFPIcon.tsx b/Eplant/views/NavigatorViewer/Icons/Nav_CellEFPIcon.tsx new file mode 100644 index 00000000..1fb0b5f8 --- /dev/null +++ b/Eplant/views/NavigatorViewer/Icons/Nav_CellEFPIcon.tsx @@ -0,0 +1,17 @@ +import { styled } from '@mui/material' + +export default styled((props) => { + return ( + + + + ) +})(({ theme }) => ({ + fill: theme.palette.text.primary, +})) diff --git a/Eplant/views/NavigatorViewer/Icons/Nav_GeneInfoViewerIcon.tsx b/Eplant/views/NavigatorViewer/Icons/Nav_GeneInfoViewerIcon.tsx new file mode 100644 index 00000000..3c01273b --- /dev/null +++ b/Eplant/views/NavigatorViewer/Icons/Nav_GeneInfoViewerIcon.tsx @@ -0,0 +1,17 @@ +import { styled } from '@mui/material' + +export default styled((props) => ( + + + + + +))(({ theme }) => ({ + fill: theme.palette.text.primary, +})) diff --git a/Eplant/views/NavigatorViewer/Icons/Nav_PlantEFPIcon.tsx b/Eplant/views/NavigatorViewer/Icons/Nav_PlantEFPIcon.tsx new file mode 100644 index 00000000..116bb481 --- /dev/null +++ b/Eplant/views/NavigatorViewer/Icons/Nav_PlantEFPIcon.tsx @@ -0,0 +1,18 @@ +import { styled } from '@mui/material' +export default styled((props) => { + return ( + + + + ) +})(({ theme }) => ({ + fill: theme.palette.text.primary, +})) + +// This icon is used in the dropdown view selection menu diff --git a/Eplant/views/NavigatorViewer/Icons/NavigatorViewIcon.tsx b/Eplant/views/NavigatorViewer/Icons/NavigatorViewIcon.tsx new file mode 100644 index 00000000..5b32d643 --- /dev/null +++ b/Eplant/views/NavigatorViewer/Icons/NavigatorViewIcon.tsx @@ -0,0 +1,15 @@ +import { styled } from '@mui/material' + +export default styled((props) => ( + + + +))(({ theme }) => ({ + fill: theme.palette.text.primary, +})) diff --git a/Eplant/views/NavigatorViewer/NavigatorView.tsx b/Eplant/views/NavigatorViewer/NavigatorView.tsx new file mode 100644 index 00000000..b7e002ea --- /dev/null +++ b/Eplant/views/NavigatorViewer/NavigatorView.tsx @@ -0,0 +1,1544 @@ +/** + * Title: Navigator View + * Author: Kobi Schmalenberg with reference to ePlant2 + * Description: + * The navigator viewer works by fetching data from an API source, which includes information on phylogeny, sequence/expression similarity, etc, + * and converting it into formats usable by the external package D3. D3 contains a suite of functions/tools that streamline the process of + * visualizing a phylogeny tree. SVG elements surround the D3 phylogeny tree object to showcase various relevant information to the user. + */ + +import { useContext, useEffect, useMemo, useRef, useState } from 'react' +import * as d3 from 'd3' + +import { useConfig } from '@eplant/config' +import { useActiveGeneId } from '@eplant/state' +import { useTheme } from '@mui/material/styles' + +import { LoadingImage } from '../../UI/Layout/ViewContainer/LoadingPage' +import { useViewSwitch } from '../ViewGeneSwitching' + +import Nav_CellEFPIcon from './Icons/Nav_CellEFPIcon' +import Nav_GeneInfoViewIcon from './Icons/Nav_GeneInfoViewerIcon' /** Placeholder icon for those that are not yet implemented in ePlant3 */ +import Nav_PlantEFPIcon from './Icons/Nav_PlantEFPIcon' +import * as constants from './constants' +import { NavigatorContext, ViewSwitchProvider } from './index' + +/** Static declaration of genome label colors */ +const genomeColors: { [key: string]: string } = { + SOYBEAN: '#0876FC' /** Light blue */, + TOMATO: '#FFA500' /** Orange */, + POTATO: '#808000' /** Olive green */, + GRAPE: '#808080' /** Grey */, + MAIZE: '#00FFFF' /** Cyan */, + BARLEY: '#FFDC00' /** Yellow */, + RICE: '#008000' /** Green */, + 'M. TRUNCATULA': '#B03060' /** Violet Red */, + POPLAR: '#20B2AA' /** Sea Green */, + default: '#000000' /** Default color: black */, +} + +/** + * Retrieves the color associated with a specific genome type from the predefined color palette + * @param genomeType - The name of the genome/species to retrieve a color for + * @returns A color hex code corresponding to the genome type. + * If the genome type is not found in the color palette, returns the default color. + */ +const getGenomeColor = (genomeType: string): string => { + return genomeType && genomeColors[genomeType] + ? genomeColors[genomeType] + : genomeColors['default'] +} + +/** Static declaration of Gramene links for different species */ +const grameneLinks: { [key: string]: string } = { + POPLAR: + 'https://ensembl.gramene.org/Populus_trichocarpa/Search/Results?species=Populus_trichocarpa;idx=;q={geneName}', + SOYBEAN: 'https://ensembl.gramene.org/Glycine_max/Gene/Summary?g={geneName}', + 'M. TRUNCATULA': + 'https://ensembl.gramene.org/Medicago_truncatula/Gene/Summary?g={geneName}', + TOMATO: + 'https://ensembl.gramene.org/Solanum_lycopersicum/Search/Results?species=Solanum_lycopersicum;idx=;q={geneName}', + POTATO: '', // Placeholder for N/A + GRAPE: + 'https://ensembl.gramene.org/Vitis_vinifera/Search/Results?species=Vitis_vinifera;idx=;q={geneName}', + RICE: 'https://ensembl.gramene.org/Oryza_indica/Search/Results?species=Oryza_indica;idx=;q={geneName}', + MAIZE: + 'https://ensembl.gramene.org/Zea_mays/Search/Results?species=Zea_mays;idx=;q={geneName}', + BARLEY: + 'https://ensembl.gramene.org/Hordeum_vulgare/Search/Results?species=Hordeum_vulgare;idx=;q={geneName}', + default: + 'https://ensembl.gramene.org/Arabidopsis_thaliana/Gene/Summary?g={geneName}', +} + +/** + * Static declaration of other ePlant site links for non-Arabidopsis species + */ +const ePlantLinks: { [key: string]: string } = { + POPLAR: 'https://bar.utoronto.ca/eplant_poplar/', + SOYBEAN: 'https://bar.utoronto.ca/eplant_soybean/', + 'M. TRUNCATULA': 'https://bar.utoronto.ca/eplant_medicago/', + TOMATO: 'https://bar.utoronto.ca/eplant_tomato/', + POTATO: 'https://bar.utoronto.ca/eplant_potato/', + GRAPE: '', + RICE: 'https://bar.utoronto.ca/eplant_rice/', + MAIZE: 'https://bar.utoronto.ca/eplant_maize/', + BARLEY: 'https://bar.utoronto.ca/eplant_barley/', +} + +/** + * Generate Gramene link based on species and gene name + * @param species - The species name + * @param geneName - The gene name + * @returns Formatted Gramene link or empty string if no link available + */ +const getGrameneLink = ( + species: string | undefined, + geneName: string +): string => { + /** Handle undefined species */ + if (!species) { + return grameneLinks['default'].replace('{geneName}', geneName) + } + + /** Normalize species name to uppercase */ + const normalizedSpecies = species.toUpperCase() + + /** Get the link template, fallback to default if not found */ + const linkTemplate = + grameneLinks[normalizedSpecies] || grameneLinks['default'] + + /** Special case handling for specific species */ + let processedGeneName = geneName + /** SOYBEAN: Replace period with underscore */ + if (normalizedSpecies === 'SOYBEAN') { + processedGeneName = geneName.replace(/\./g, '_') + } + /** RICE: Remove underscore */ + if (normalizedSpecies === 'RICE') { + processedGeneName = geneName.replace(/_/g, '') + } + /** MAIZE: Remove everything after underscore */ + if (normalizedSpecies === 'MAIZE') { + processedGeneName = geneName.split('_')[0] + } + /** BARLEY: Only works for MLOC genes */ + if (normalizedSpecies === 'BARLEY' && !geneName.startsWith('MLOC')) { + return '' + } + /** Replace geneName in the template */ + return linkTemplate.replace('{geneName}', processedGeneName) +} + +/** + * Extracts the species name from the API URL + * + * @param url - The complete API URL containing query parameters + * @returns The species name, or an empty string if not found + * + * Uses regex to find the species parameter in the URL + */ +function extractSpecies(url: string): string { + const match = url.match(/species=([^&]+)/) + return match ? match[1] : '' +} + +/** + * Interface representing the tree data structure received from the API + * + * @param tree - Newick format string representing the phylogenetic tree + * @param efp_links - Map of gene identifiers to their expression profile URLs + * @param genomes - Map of gene identifiers to their genome information + * @param SCC_values - Map of gene identifiers to their expression correlation values + * @param sequence_similarity - Map of gene identifiers to their sequence similarity scores + * @param maximum_values - Map of gene identifiers to their maximum normalized values + */ +interface TreeData { + tree: string + efp_links: Record + genomes: Record + SCC_values: Record + sequence_similarity: Record + maximum_values: Record +} + +/** + * Interface representing a node in the D3 hierarchy structure + * + * @param name - Node identifier or name + * @param value - Optional numerical value representing branch length + * @param children - Optional array of child nodes in the tree + * @param metadata - Optional metadata associated with the node + */ +interface D3Node { + name: string + value: number + children?: D3Node[] + metadata?: { + genome?: string + scc_value?: number + sequence_similarity?: number + efp_link?: string + } +} + +/** + * Interface representing a cached data entry + * + * @param data - The cached data object of type T + * @param timestamp - Timestamp of when the data was cached (in milliseconds since epoch) + */ +interface CacheEntry { + data: T + timestamp: number +} + +/** + * Converts a Newick format tree string to D3 hierarchy compatible format + * + * @param newickString - Tree structure in Newick format (e.g., "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5);") + * @param metadata - Additional tree metadata including expression data + * @param primaryGene - Identifier of the primary gene being analyzed + * @param species - Species name for the primary gene + * @returns A D3-compatible tree structure + * @throws Error If the Newick string format is invalid + * + * Example: + * newickToD3("(A:0.1,B:0.2):0.3;", { + * efp_links: { A: "linkA", B: "linkB" }, + * genomes: { A: "SOYBEAN", B: "RICE" }, + * SCC_values: { A: 0.9, B: -0.2 }, + * sequence_similarity: { A: 95, B: 88 }, + * maximum_values: { A: 1.0, B: 1.0 }, + * tree: "(A:0.1,B:0.2):0.3;" + * }, "A", "SOYBEAN") + * + * Returns: + * { + * name: 'internal', + * value: 0.3, + * children: [ + * { + * name: 'A', + * value: 0.1, + * metadata: { + * genome: 'SOYBEAN', + * efp_link: 'linkA', + * scc_value: 0.9, + * sequence_similarity: 95 + * } + * }, + * { + * name: 'B', + * value: 0.2, + * metadata: { + * genome: 'RICE', + * efp_link: 'linkB', + * scc_value: -0.2, + * sequence_similarity: 88 + * } + * } + * ] + * } + */ +function newickToD3( + newickString: string, + metadata: TreeData, + primaryGene: string, + species: string +): D3Node { + /** Remove trailing semicolon and whitespace */ + const cleaned = newickString.trim().replace(/;$/, '') + + /** + * Recursively parses a Newick node string into a D3Node structure + * + * @param str - Node string to parse (e.g., "A:0.1" or "(A:0.1,B:0.2)") + * @returns Parsed D3Node object + * @throws Error If the node string format is invalid + */ + function parseNode(str: string): D3Node { + /** Handle leaf nodes (no children) */ + if (!str.includes('(')) { + const [name, lengthStr] = str.split(':') + const cleanName = name.trim() + const upperName = cleanName.toUpperCase() + const isPrimaryGene = upperName === primaryGene.toUpperCase() + + return { + name: cleanName, + value: parseFloat(lengthStr), + metadata: { + genome: (() => { + const genomeValue = isPrimaryGene + ? species + : metadata.genomes[upperName] + return genomeValue?.toUpperCase() === 'ATHL' + ? 'ARABIDOPSIS' + : genomeValue + })(), + scc_value: metadata.SCC_values[upperName], + sequence_similarity: metadata.sequence_similarity[upperName], + efp_link: metadata.efp_links[upperName], + }, + } + } + + /** Handle internal nodes with children */ + const matches = str.match(/\((.*)\)(.*)/) + if (!matches) throw new Error('Invalid Newick format') + + const [_, childrenStr, remainingStr] = matches + const children: D3Node[] = [] + let buffer = '' /** Buffer string until comma at root level is found */ + let parenthesesCount = 0 /** Maintin nested level */ + + /** Parse child nodes while handling nested parentheses */ + for (const char of childrenStr) { + if (char === '(') parenthesesCount++ + if (char === ')') parenthesesCount-- + if (char === ',' && parenthesesCount === 0) { + children.push(parseNode(buffer.trim())) + buffer = '' + } else { + buffer += char + } + } + if (buffer.trim()) children.push(parseNode(buffer.trim())) + + /** Parse node name and branch length */ + const [name, lengthStr] = remainingStr.split(':') + + return { + name: name || 'internal', + value: parseFloat(lengthStr), + children, + } + } + + return parseNode(cleaned) +} + +/** + * Props interface for the MetadataVisualizations component + * + * @param x - X coordinate for rendering the visualization + * @param y - Y coordinate for rendering the visualization + * @param metadata - Metadata associated with the node + * @param isPrimaryGene - Whether this node represents the primary gene being analyzed + * @param themeColors - colouring for the metadata to match ePlant + * @param isHighestNode - have we hit the node with the highest Y coordinate + */ +interface MetadataVisualizationsProps { + x: number + y: number + metadata: D3Node['metadata'] + isPrimaryGene: boolean + isHighestNode: boolean + themeColors: { + nodeColor: string + leafNodeColor: string + rootNodeColor: string + edgeColor: string + textColor: string + metadataBar: { + background: string + stroke: string + indicator: string + centerLine: string + } + } +} + +/** + * Calculates dimensions for rendering the tree based on the number of leaf nodes. + * Ensures the height stays within defined min and max bounds. + * + * @param leafCount - Number of leaf nodes in the tree (default is 0) + * @returns An object with calculated width, height, and drawable bounds + */ +const calculateDimensions = (leafCount: number = 0) => { + /** If no leafCount provided, use MIN_HEIGHT as default */ + const requiredHeight = + leafCount === 0 + ? constants.MIN_HEIGHT + : Math.max( + constants.MIN_HEIGHT, + Math.min(constants.MAX_HEIGHT, leafCount * constants.HEIGHT_PER_NODE) + ) + + return { + width: constants.DEFAULT_WIDTH, + height: requiredHeight, + boundsWidth: + constants.DEFAULT_WIDTH - constants.MARGIN.left - constants.MARGIN.right, + boundsHeight: + requiredHeight - constants.MARGIN.top - constants.MARGIN.bottom, + } +} + +/** + * Component for rendering metadata visualizations next to tree nodes + * Displays expression similarity and sequence similarity using color-coded bars + * + * @param MetadataVisualizationsProps - Follows the structure of the MetadataVisualizationsProps interface defined in this file + * @param MetadataVisualizationsProps.x - X coordinate for rendering the visualization + * @param MetadataVisualizationsProps.y - Y coordinate for rendering the visualization + * @param MetadataVisualizationsProps.metadata - Metadata associated with the node + * @param MetadataVisualizationsProps.isPrimaryGene - Whether this node represents the primary gene being analyzed + * @param MetadataVisualizationsProps.themeColors - colouring for the metadata to match ePlant + * @param MetadataVisualizationsProps.isHighestNode - have we hit the node with the highest Y coordinate + * @returns JSX element containing metadata visualizations + */ +const MetadataVisualizations = ({ + x, + y, + metadata, + isPrimaryGene, + themeColors, + isHighestNode, +}: MetadataVisualizationsProps) => { + const expressionBarRef = useRef(null) + const sequenceBarRef = useRef(null) + + if (!metadata) return null + + /** Normalize values to 0-1 range, with primary gene always at 1 */ + const sequenceSimilarity = Math.min( + isPrimaryGene ? 100 : metadata.sequence_similarity || 0 + ) + const expressionSimilarity = Math.min( + isPrimaryGene ? 1 : metadata.scc_value || 0, + 1 + ) + + /** Clamp expression similarity between -1 and 1 */ + const clampedExpression = Math.max( + Math.min(isPrimaryGene ? 1 : expressionSimilarity || 0, 1), + -1 + ) + + /** Calculate the width and position of the indicator bar + * As the code draws expression bar from left -> right, an indicatorX value is used to determine the start point for drawing. + * If a positive value, indicatorX will be the position of the center(halfWidth). + * If negative, we offset from the center by the width of the actual expression data(indicatorWidth) and draw towards the center. + */ + const halfWidth = constants.BAR_WIDTH / 2 + const indicatorWidth = Math.abs(clampedExpression) * halfWidth + const indicatorX = + clampedExpression >= 0 + ? halfWidth /** Start from center for positive values */ + : halfWidth - indicatorWidth /** Offset left for negative values */ + + return ( + + {/* Expression similarity bar with tooltip */} + + {/* Conditionally render title and labels only for the highest positioned node */} + {isHighestNode && ( + <> + + Expression Similarity + + {/* Expression similarity scale labels */} + + -1 + + + 0 + + + 1 + + + )} + {/* Background bar */} + + {/* Expression similarity indicator */} + { + if (clampedExpression < 0) { + const ratio = (clampedExpression + 1) / 1 + return `rgb(${255 * ratio}, ${255 * ratio}, ${ + 255 * (1 - ratio) + })` /** Increase blue, decrease red and yellow */ + } else { + const ratio = clampedExpression + return `rgb(255, ${ + 255 * (1 - ratio) + }, 0)` /** Static red and blue, decrease yellow */ + } + })()} + /> + {/* Center line separator */} + + {/* Tooltip bar */} + { + const clampedExpression = Math.max( + Math.min(isPrimaryGene ? 1 : metadata?.scc_value || 0, 1), + -1 + ) + d3.select('.d3-tooltip') + .style('visibility', 'visible') + .html( + ` +
+
Expression Similarity
+
Value: ${clampedExpression.toFixed(2)}
+
+ Indicates correlation of expression patterns with the primary gene +
+
+ ` + ) + .style('left', `${event.pageX + 10}px`) + .style('top', `${event.pageY - 10}px`) + }} + onMouseMove={(event) => { + d3.select('.d3-tooltip') + .style('left', `${event.pageX + 10}px`) + .style('top', `${event.pageY - 10}px`) + }} + onMouseOut={() => { + d3.select('.d3-tooltip').style('visibility', 'hidden') + }} + /> +
+ + {/* Sequence Similarity bar with tooltip */} + + {/* Conditionally render title and labels only for the highest positioned node */} + {isHighestNode && ( + <> + + Sequence Similarity + + {/* Sequence similarity scale labels */} + + 0% + + + 50% + + + 100% + + + )} + {/* Background bar */} + + {/* Sequence similarity indicator */} + + {/* Tooltip bar */} + { + const sequenceSimilarity = Math.min( + isPrimaryGene ? 100 : metadata?.sequence_similarity || 0 + ) + d3.select('.d3-tooltip') + .style('visibility', 'visible') + .html( + ` +
+
Sequence Similarity
+
Value: ${sequenceSimilarity.toFixed(1)}%
+
+ Percentage of sequence similarity with the primary gene +
+
+ ` + ) + .style('left', `${event.pageX + 10}px`) + .style('top', `${event.pageY - 10}px`) + }} + onMouseMove={(event) => { + d3.select('.d3-tooltip') + .style('left', `${event.pageX + 10}px`) + .style('top', `${event.pageY - 10}px`) + }} + onMouseOut={() => { + d3.select('.d3-tooltip').style('visibility', 'hidden') + }} + /> +
+
+ ) +} + +const geneDataCache: Record> = {} + +/** + * Fetches data from a given Url and determines if the data already exists in memory + * Updates the cache if the data is unique and/or the cache timer has expired + * + * @param apiUrl - The Url used to access the necessary phylogeny data of a specific gene + * @returns A json formatted object of the data for use in downstream functions + */ +const fetchGeneData = async (apiUrl: string): Promise => { + /** Check if data exists in cache and is still valid */ + const cachedEntry = geneDataCache[apiUrl] + const currentTime = Date.now() + + if ( + cachedEntry && + currentTime - cachedEntry.timestamp < constants.CACHE_DURATION + ) { + return cachedEntry.data + } + + /** Fetch new data if not in cache or cache has expired */ + const response = await fetch(apiUrl) + if (!response.ok) { + throw new Error('Network response was not ok') + } + const data = await response.json() + + if (data.status !== 'success') { + throw new Error('Failed to load tree data') + } + + /** Store in cache */ + geneDataCache[apiUrl] = { + data, + timestamp: currentTime, + } + + return data +} + +/** + * Custom hook for gene data fetching with basic caching + * + * @param apiUrl - The Url used to access the necessary phylogeny data of a specific gene + * @returns Loading, error, and Tree data states + */ +const useGeneData = (apiUrl: string) => { + const [data, setData] = useState(null) + const [error, setError] = useState(null) + const [isLoading, setIsLoading] = useState(true) + + useEffect(() => { + const loadData = async () => { + try { + setIsLoading(true) + const fetchedData = await fetchGeneData(apiUrl) + setData(fetchedData) + setError(null) + } catch (err) { + setError( + err instanceof Error ? err : new Error('An unknown error occurred') + ) + setData(null) + } finally { + setIsLoading(false) + } + } + + loadData() + }, [apiUrl]) + + return { data, error, isLoading } +} + +/** + * Main component for rendering the phylogenetic tree navigator + * Handles data fetching, tree layout, and interactive visualization + * + * @returns JSX element containing the complete tree visualization + */ +export const NavigatorViewObject = () => { + /** Refs for DOM elements and D3 manipulation */ + const containerRef = useRef(null) + const svgRef = useRef(null) + const gRef = useRef(null) + const theme = useTheme() + const { switchViewAndGene } = useViewSwitch() + const { userViews } = useConfig() + + /** Initialize dimensions with default calculation */ + const [dimensions, setDimensions] = useState(calculateDimensions()) + + /** Configuration of Colours for Light and Dark Mode */ + const themeColors = useMemo( + () => ({ + nodeColor: + theme.palette.mode === 'dark' + ? theme.palette.common.white + : theme.palette.common.black, + leafNodeColor: + theme.palette.mode === 'dark' + ? theme.palette.primary.light + : theme.palette.primary.light /** Same green color currently */, + rootNodeColor: theme.palette.mode === 'dark' ? '#EE4B2B' : '#EE4B2B', + edgeColor: + theme.palette.mode === 'dark' + ? theme.palette.grey[500] + : theme.palette.grey[800], + textColor: theme.palette.text.primary, + genomeColors: + theme.palette.mode === 'dark' + ? (genomeColors.default = '#FFFFFF') + : (genomeColors.default = '#000000'), + metadataBar: { + background: + theme.palette.mode === 'dark' + ? theme.palette.grey[800] + : theme.palette.grey[400], + stroke: + theme.palette.mode === 'dark' + ? theme.palette.grey[600] + : theme.palette.grey[400], + indicator: + theme.palette.mode === 'dark' + ? theme.palette.common.white + : theme.palette.common.black, + centerLine: theme.palette.error.main, + }, + }), + [theme.palette.mode] + ) + + /** State management */ + const { apiUrl } = useContext(NavigatorContext) + const [activeGeneId, setActiveGeneId] = useActiveGeneId() + const [species, setSpecies] = useState(extractSpecies(apiUrl)) + const [transform, setTransform] = useState(d3.zoomIdentity) + + /** Keep track of current gene to detect changes */ + const prevGeneRef = useRef(activeGeneId) + + /** Use the custom hook for data fetching */ + const { data: treeData, error, isLoading } = useGeneData(apiUrl) + + /** Reset state when API URL changes */ + useEffect(() => { + const newGene = activeGeneId + const newSpecies = extractSpecies(apiUrl) + + /** Add more robust validation */ + if ( + newGene && + newSpecies && + (newGene !== prevGeneRef.current || newSpecies !== species) + ) { + /** Ensure data is valid before updating */ + if (treeData && treeData.tree) { + setActiveGeneId(newGene) + setSpecies(newSpecies) + setTransform(d3.zoomIdentity) + + prevGeneRef.current = newGene + } + } + }, [activeGeneId, species, treeData]) + + /** Create D3 hierarchy from tree data + * D3 hierarchy encompasses a number of object types such as Tree, Cluster, Treemap, etc. + * Using Tree does not yield what is required(leaf nodes aligned vertically). + * Therefore, this view relies on the Cluster object. + * Citation: https://d3js.org/d3-hierarchy/cluster + */ + const hierarchy = useMemo(() => { + if (!treeData) return null + + try { + const d3Data = newickToD3(treeData.tree, treeData, activeGeneId, species) + const newHierarchy = d3.hierarchy(d3Data) + + /** Clear any cached properties - used for when switching between genes*/ + newHierarchy.descendants().forEach((node) => { + delete (node as any).x0 + delete (node as any).y0 + delete (node as any).parentY + delete (node as any).previousX + delete (node as any).previousY + }) + + return newHierarchy + } catch (error) { + console.error('Error parsing Newick string:', error) + return null + } + }, [treeData, activeGeneId, species]) + + /** Update dimensions when hierarchy object changes */ + useEffect(() => { + if (!isLoading && treeData && hierarchy) { + try { + const leafCount = hierarchy.leaves().length + const newDimensions = calculateDimensions(leafCount) + setDimensions(newDimensions) + + if (containerRef.current) { + containerRef.current.style.height = `${newDimensions.height}px` + } + } catch (error) { + console.error('Error updating dimensions:', error) + } + } + }, [hierarchy, isLoading, treeData]) + + /** Generate tree layout using D3's cluster layout */ + const navigator = useMemo(() => { + if (!dimensions.boundsHeight || !dimensions.boundsWidth || !hierarchy) + return null + + /** Clear any existing layout data */ + hierarchy.descendants().forEach((node) => { + delete (node as any).x + delete (node as any).y + delete (node as any).parentY + }) + + /** Essentially assigns coordinates for each node. + * Create the cluster object, sets max size of the object to take 90% of available height and 20% width. + */ + const navigatorGenerator = d3 + .cluster() + .size([dimensions.boundsHeight * 0.9, dimensions.boundsWidth * 0.2]) + .separation((a, b) => + a.parent === b.parent ? 1.5 : 2.5 + ) /** If two nodes share a parent, they are spaced closer together */ + + /** Applies the cluster layout to our hierarchy object */ + const processedNavigator = navigatorGenerator(hierarchy) + + /** Calculates how much space is actually used by the nodes of a given tree for use in scaling + * Does this by finding the max x and y values of all the nodes(the extent). + * Helpful in determining the space needed by the nodes. + */ + const xExtent = d3.extent(processedNavigator.descendants(), (d) => d.x) as [ + number, + number, + ] + const yExtent = d3.extent(processedNavigator.descendants(), (d) => d.y) as [ + number, + number, + ] + + /** Converts raw coordinates into pixel values for placement on the screen + * Scales based on calculated extents within an output range. + */ + const xScale = d3 + .scaleLinear() + .domain(xExtent) + .range([0, dimensions.boundsHeight * 0.9]) + + const yScale = d3 + .scaleLinear() + .domain(yExtent) + .range([0, dimensions.boundsWidth * 0.2]) + + /** Process nodes with fresh coordinates and aligns by leaf node vertically + * Applies scaling functions onto each node with special leaf node handling. + * Forced alignment may be redundant here upon further review. (April 4th 2025) + */ + processedNavigator.descendants().forEach((node) => { + node.x = xScale(node.x) + node.y = yScale(node.y) + + if (!node.children) { + node.y = yScale(yExtent[1]) + } else if (node.children) { + node.children.forEach((child) => { + ;(child as any).parentY = node.y + }) + } + }) + + return processedNavigator + }, [hierarchy, dimensions.boundsWidth, dimensions.boundsHeight]) + + /** Create a single tooltip instance */ + const tooltip = d3 + .select('body') + .selectAll('.d3-tooltip') + .data([null]) + .join('div') + .attr('class', 'd3-tooltip') + .style('position', 'absolute') + .style('visibility', 'hidden') + .style('background', theme.palette.primary.light) + .style('color', 'white') + .style('padding', '6px') + .style('border-radius', '0px') /** Sharp edges */ + .style('pointer-events', 'none') + .style('backdrop-filter', 'blur(7px)') + + /** Add tooltip to elements */ + const addTooltip = ( + element: d3.Selection, + text: string + ) => { + let isHidden = false + element + .on('mouseover', (event: MouseEvent) => { + if (!isHidden) { + tooltip + .style('visibility', 'visible') + .html(text) + .style('left', `${event.pageX + 10}px`) + .style('top', `${event.pageY - 10}px`) + } + }) + .on('mousemove', (event: MouseEvent) => { + if (!isHidden) { + tooltip + .style('left', `${event.pageX + 10}px`) + .style('top', `${event.pageY - 10}px`) + } + }) + .on('mouseout', () => { + tooltip.style('visibility', 'hidden') + }) + + /** Reactivate the tooltip on hover */ + tooltip.on('mouseover', () => { + isHidden = false /** Reset the hidden state */ + }) + } + + /** Generate node elements for rendering */ + const allNodes = navigator?.descendants().map((node, index: number) => { + const isPrimaryGene = + node.data.name.toUpperCase() === activeGeneId.toUpperCase() + let displayName = node.data.name + const isHighestNode = + node.x === Math.min(...navigator.descendants().map((d) => d.y)) + + /** Add genome information to leaf node labels */ + if (!node.children && node.data.metadata?.genome) { + displayName = `${node.data.name}` + } + const uniqueKey = `${node.data.name}-${index}` + + return ( + + {/* Node circle: only draw for leaf and root nodes*/} + {(!node.children || node === navigator) && ( + + )} + {/* Label and metadata for leaf nodes */} + {!node.children && ( + <> + {/* Node label with optional genome information */} + + {displayName.toUpperCase()} + + {/* Genome label aligned in its own column */} + {!node.children && node.data.metadata?.genome && ( + + {node.data.metadata.genome.toUpperCase()} + + )} + + {/* Metadata visualization component for expression and similarity data */} + + + {/* Placeholder World Icon Group */} + { + if (el) { + addTooltip(d3.select(el), 'World') + } + }} + onClick={(event) => { + /** Extract the geneName */ + const geneName = displayName + /** Get species from node data or props - default to Arabidopsis */ + const species = node.data.metadata?.genome + + /** Validate view and gene */ + const isValidView = userViews.some( + (view) => view.id === 'world' + ) + + if (isValidView) { + /** Call switch view function with species information */ + if (!species || !(species in ePlantLinks)) { + /** Call switch view function to swap the view using designated view id and gene name */ + switchViewAndGene('world', geneName) + } else { + /** Handle external species navigation */ + switchViewAndGene('world', geneName, ePlantLinks[species]) + } + } + }} + style={{ + cursor: userViews.some((view) => view.id === 'world') + ? 'pointer' + : 'not-allowed', + }} + > + + view.id === 'world') + ? 1 + : 0.5, + }} + > + + + + + {/* Plant EFP Icon Group */} + { + if (el) { + addTooltip(d3.select(el), 'Plant') + } + }} + onClick={async (event) => { + /** Extract the geneName */ + const geneName = displayName + /** Get species from node data or props - default to Arabidopsis */ + const species = node.data.metadata?.genome + + /** Validate view and gene */ + const isValidView = userViews.some( + (view) => view.id === 'plant' + ) + + if (isValidView) { + /** Call switch view function with species information */ + if (!species || !(species in ePlantLinks)) { + /** Call switch view function to swap the view using designated view id and gene name */ + switchViewAndGene('plant', geneName) + } else { + /** Handle external species navigation */ + switchViewAndGene('plant', geneName, ePlantLinks[species]) + } + } + }} + style={{ + cursor: userViews.some((view) => view.id === 'plant') + ? 'pointer' + : 'not-allowed', + }} + > + + view.id === 'plant') + ? 1 + : 0.5, + }} + > + + + + + {/* Cell EFP Icon Group */} + { + if (el) { + addTooltip(d3.select(el), 'Cell') + } + }} + onClick={(event) => { + /** Extract the geneName */ + const geneName = displayName + /** Get species from node data or props - default to Arabidopsis */ + const species = node.data.metadata?.genome + + /** Validate view and gene */ + const isValidView = userViews.some( + (view) => view.id === 'Cell eFP' + ) + + if (isValidView) { + /** Call switch view function with species information */ + if (!species || !(species in ePlantLinks)) { + /** Call switch view function to swap the view using designated view id and gene name */ + switchViewAndGene('Cell eFP', geneName) + } else { + /** Handle external species navigation */ + switchViewAndGene( + 'Cell eFP', + geneName, + ePlantLinks[species] + ) + } + } + }} + style={{ + cursor: userViews.some((view) => view.id === 'Cell eFP') + ? 'pointer' + : 'not-allowed', + }} + > + + view.id === 'Cell eFP') + ? 1 + : 0.5, + }} + > + + + + + {/* Placeholder Molecule Icon Group */} + { + if (el) { + addTooltip(d3.select(el), 'Molecule') + } + }} + onClick={(event) => { + /** Extract the geneName */ + const geneName = displayName + /** Get species from node data or props - default to Arabidopsis */ + const species = node.data.metadata?.genome + + /** Validate view and gene */ + const isValidView = userViews.some( + (view) => view.id === 'Molecule' + ) + + if (isValidView) { + /** Call switch view function with species information */ + if (!species || !(species in ePlantLinks)) { + /** Call switch view function to swap the view using designated view id and gene name */ + switchViewAndGene('Molecule', geneName) + } else { + /** Handle external species navigation */ + switchViewAndGene( + 'Molecule', + geneName, + ePlantLinks[species] + ) + } + } + }} + > + + view.id === 'Molecule') + ? 1 + : 0.5, + }} + > + + + + + {/* Placeholder Interactions Icon Group */} + { + if (el) { + addTooltip(d3.select(el), 'Interactions') + } + }} + onClick={(event) => { + /** Extract the geneName */ + const geneName = displayName + /** Get species from node data or props - default to Arabidopsis */ + const species = node.data.metadata?.genome + + /** Validate view and gene */ + const isValidView = userViews.some( + (view) => view.id === 'Interactions' + ) + + if (isValidView) { + /** Call switch view function with species information */ + if (!species || !(species in ePlantLinks)) { + /** Call switch view function to swap the view using designated view id and gene name */ + switchViewAndGene('Interactions', geneName) + } else { + /** Handle external species navigation */ + switchViewAndGene( + 'Interactions', + geneName, + ePlantLinks[species] + ) + } + } + }} + > + + view.id === 'Interactions') + ? 1 + : 0.5, + }} + > + + + + + {/* CoGE */} + { + if (el) { + addTooltip(d3.select(el), 'Open gene page on CoGE') + } + }} + onClick={() => { + const url = `https://genomevolution.org/CoGe/` + window.open(url, '_blank') + }} + > + + CoGE + + + + {/* Gramene */} + { + if (el) { + addTooltip(d3.select(el), 'Open gene page on Gramene') + } + }} + onClick={() => { + const url = getGrameneLink( + node.data.metadata?.genome, + node.data.name + ) + window.open(url, '_blank') + }} + > + + Gramene + + + + )} + + ) + }) + + /** Generate edge elements for rendering */ + const allEdges = navigator?.links().map((link, index: number) => { + /** Create an elbow-shaped path for each edge using SVG path commands: + * M: Move to starting point (source node, the midpoint of both leaf nodes) + * H: Draw horizontal line to parent's x-coordinate(the code shows y-coordinate as they are flipped) + * V: Draw vertical line to target's y-coordinate(the code shows x-coordinate as they are flipped) + * H: Draw horizontal line to target node + */ + const sourceX = link.source.x + const sourceY = link.source.y + const targetX = link.target.x + const targetY = link.target.y + const parentY = (link as any).target.parentY ?? link.source.y + const path = ` + M${sourceY},${sourceX} + H${parentY} + V${targetX} + H${targetY} + ` + + const uniqueKey = `${link.source.data.name}-${link.target.data.name}-${index}` + + return ( + + ) + }) + + /** Render the complete tree visualization */ + return ( +
+ {!isLoading && ( +
+

+ Navigator View: {activeGeneId} +

+
+ )} +
+ {/* Conditional loading animation */} + {isLoading && ( +
+ +
+ )} + + {/* Error message when no data is available */} + {!isLoading && + (!allEdges || allEdges.length === 0) && + (!allNodes || allNodes.length === 0) && ( +
+

No data available for the selected gene.

+
+ )} + + {/* Main SVG container for the tree visualization */} + + {/* Group element for tree content with transformation support + 1. Translate to account for margins + 2. Scale by zoom factor (transform.k) + 3. Translate by pan offset (transform.x, transform.y)*/} + + {/* Render tree edges first so they appear behind nodes */} + {allEdges} + {/* Render tree nodes and their labels on top */} + {allNodes} + + +
+
+ ) +} + +const WrappedNavigatorViewObject = () => { + return ( + + + + ) +} + +export default WrappedNavigatorViewObject diff --git a/Eplant/views/NavigatorViewer/constants.tsx b/Eplant/views/NavigatorViewer/constants.tsx new file mode 100644 index 00000000..c9f4157c --- /dev/null +++ b/Eplant/views/NavigatorViewer/constants.tsx @@ -0,0 +1,38 @@ +/** How long to keep data cached while on the site */ +export const CACHE_DURATION = 1000 * 60 * 60 /** 1 hour in milliseconds */ + +/** Margin configuration for the SVG container */ +export const MARGIN = { top: 50, right: 600, bottom: 50, left: 10 } + +/** Default width of the visualization container in pixels */ +export const DEFAULT_WIDTH = 1200 + +/** Minimum height of the visualization */ +export const MIN_HEIGHT = 600 + +/** Maximum height of the visualization to prevent excessive scaling */ +export const MAX_HEIGHT = 2000 + +/** Minimum vertical space between nodes */ +export const HEIGHT_PER_NODE = 30 + +/** Width of metadata visualization bars in pixels */ +export const BAR_WIDTH = 100 + +/** Height of metadata visualization bars in pixels */ +export const BAR_HEIGHT = 12 + +/** Vertical spacing between bars in pixels */ +export const BAR_SPACING = 2 + +/** Horizontal offset for text labels from nodes in pixels */ +export const LABEL_OFFSET = 10 + +/** Radius of tree nodes in pixels */ +export const NODE_RADIUS = 3 + +/** Minimum zoom constraint*/ +export const MIN_ZOOM = 0.5 + +/** Maximum zoom constraint*/ +export const MAX_ZOOM = 3 diff --git a/Eplant/views/NavigatorViewer/index.tsx b/Eplant/views/NavigatorViewer/index.tsx new file mode 100644 index 00000000..967b52ed --- /dev/null +++ b/Eplant/views/NavigatorViewer/index.tsx @@ -0,0 +1,97 @@ +import React from 'react' + +import GeneticElement from '@eplant/GeneticElement' +import { getCitation } from '@eplant/util/citations' +import { View } from '@eplant/View' + +import { createViewSwitchProvider } from '../ViewGeneSwitching' + +import NavigatorIcon from './Icons/NavigatorViewIcon' +import NavigatorViewObject from './NavigatorView' + +/** Use the provider from helper function */ +export const ViewSwitchProvider = createViewSwitchProvider() + +/** Create navigator view context */ +export const NavigatorContext = React.createContext<{ apiUrl: string }>({ + apiUrl: + 'https://bar.utoronto.ca/webservices/eplant_navigator/cgi-bin/eplant_navigator_service.cgi?primaryGene=AT3G24650&species=Arabidopsis&dataset=Developmental&checkedspecies=arabidopsis_poplar_medicago_soybean_rice_barley_maize_potato_tomato_grape', +}) + +/** Define navigator view configuration */ +const NavigatorView: View = { + name: 'Navigator View', + component: ({ geneticElement }) => { + const baseUrl = + 'https://bar.utoronto.ca/webservices/eplant_navigator/cgi-bin/eplant_navigator_service.cgi' + const gene = geneticElement?.id || '' + const species = geneticElement?.species?.name || '' + + const apiUrl = `${baseUrl}?primaryGene=${encodeURIComponent( + gene + )}&species=${encodeURIComponent( + species + )}&dataset=Developmental&checkedspecies=arabidopsis_poplar_medicago_soybean_rice_barley_maize_potato_tomato_grape` + + return ( + + + + ) + }, + async getInitialData( + gene: GeneticElement | null, + loadEvent: (progress: number) => void + ) { + loadEvent(1) + return null + }, + async getInitialState() { + return { + transform: { + dx: 0, + dy: 0, + }, + } + }, + id: 'navigator-view', + icon: () => , + + citation({ gene }) { + const citation = getCitation('Navigator viewer') as { + [key: string]: string + } + + return ( +
+ {citation.source &&

{citation.source}

} + {/* Waese et al. 2017 + Creative Commons License */} +

+ This image was generated with the Navigator viewer at{' '} + + bar.utoronto.ca/eplant + {' '} + by Waese et al. 2017. +

+ + + Creative Commons License + +
+ ) + }, +} + +export default NavigatorView diff --git a/Eplant/views/ViewGeneSwitching.tsx b/Eplant/views/ViewGeneSwitching.tsx new file mode 100644 index 00000000..0428f17b --- /dev/null +++ b/Eplant/views/ViewGeneSwitching.tsx @@ -0,0 +1,216 @@ +import { createContext, useContext, useEffect, useState } from 'react' +import _ from 'lodash' + +import { useConfig } from '@eplant/config' +import GeneticElement from '@eplant/GeneticElement' +import { + useGeneticElements, + useSetActiveGeneId, + useSetActiveViewId, + useSpecies, +} from '@eplant/state' +import { View } from '@eplant/View' + +/** + * Interface defining the shape of the ViewSwitch context + */ +interface ViewSwitchContextType { + /** Currently active view */ + activeView: View | null + /** Currently active genetic element */ + activeGene: GeneticElement | null + /** Function to switch view only */ + switchViewOnly: (viewId: string) => Promise + /** Function to switch gene only */ + switchGeneOnly: (geneName: string) => Promise + /** Function to switch both view and gene */ + switchViewAndGene: ( + viewId: string, + geneName: string, + species?: string + ) => Promise +} + +/** Default context value */ +const ViewSwitchContext = createContext({ + activeView: null, + activeGene: null, + switchViewOnly: async () => {}, + switchGeneOnly: async () => {}, + switchViewAndGene: async () => {}, +}) + +/** Hook to access the ViewSwitch context */ +export const useViewSwitch = () => useContext(ViewSwitchContext) + +/** + * Creates a ViewSwitch provider component + * @returns A React component that provides view switching functionality + */ +export const createViewSwitchProvider = () => { + /** + * ViewSwitch Provider Component + * @param props - Component props + */ + const ViewSwitchProvider = ({ children }: { children: React.ReactNode }) => { + const [activeView, setActiveView] = useState(null) + const [activeGene, setActiveGene] = useState(null) + const [geneticElements, setGeneticElements] = useGeneticElements() + + const { userViews } = useConfig() + const setActiveViewId = useSetActiveViewId() + const setActiveGeneId = useSetActiveGeneId() + const [speciesList] = useSpecies() + const species = speciesList.length ? speciesList[0] : undefined + + /** + * Adds genetic elements to the state, ensuring uniqueness + * @param genes - Array of genetic elements to add + */ + const addGeneticElements = (genes: GeneticElement[]) => { + setGeneticElements((prev) => { + const updatedGenes = _.uniqBy([...prev, ...genes], (gene) => gene.id) + return updatedGenes + }) + + if (genes.length > 0) { + setActiveGeneId(genes[0].id) + } + } + + // Ensure genetic elements remain unique + useEffect(() => { + const uniqueGenes = _.uniqBy(geneticElements, (gene) => gene.id) + if (uniqueGenes.length !== geneticElements.length) { + setGeneticElements(uniqueGenes) + } + }, [geneticElements, setGeneticElements]) + + /** + * Validates and retrieves a view by ID + * @param viewId - The ID of the view to validate + * @returns The validated view or null + */ + const validateView = (viewId: string): View | null => { + const targetView = userViews.find((view) => view.id === viewId) + if (!targetView) { + console.warn(`View with ID ${viewId} not found`) + return null + } + return targetView + } + + /** + * Loads a gene by name + * @param geneName - The name of the gene to load + * @returns The loaded genetic element or null + */ + const loadGene = async ( + geneName: string + ): Promise => { + if (!species) { + console.error('Species configuration is missing.') + return null + } + + try { + const loadedGene = await species.api.searchGene(geneName) + return loadedGene as GeneticElement + } catch (error) { + console.error(`Error loading gene ${geneName}:`, error) + return null + } + } + + /** + * Handles navigation to external species links + * @param speciesUrl - The URL to navigate to + * @param geneName - The gene identifier + */ + const handleExternalSpecies = ( + speciesUrl: string, + geneName: string + ): void => { + /** const fullUrl = `${speciesUrl}${geneName}`; */ + const fullUrl = `${speciesUrl}` + window.open(fullUrl, '_blank') + } + + /** + * Switches only the view, keeping the current gene + * @param viewId - ID of the view to switch to + */ + const switchViewOnly = async (viewId: string): Promise => { + const targetView = validateView(viewId) + + if (targetView) { + setActiveViewId(targetView.id) + setActiveView(targetView) + } + } + + /** + * Switches only the gene, keeping the current view + * @param geneName - Name of the gene to switch to + */ + const switchGeneOnly = async ( + geneName: string, + speciesUrl?: string + ): Promise => { + if (speciesUrl) { + handleExternalSpecies(speciesUrl, geneName) + } + + const geneticElement = await loadGene(geneName) + + if (geneticElement) { + addGeneticElements([geneticElement]) + setActiveGeneId(geneticElement.id) + setActiveGene(geneticElement) + } + } + + /** + * Switches both view and gene + * @param viewId - ID of the view to switch to + * @param geneName - Name of the gene to switch to + */ + const switchViewAndGene = async ( + viewId: string, + geneName: string, + speciesUrl?: string + ): Promise => { + if (speciesUrl) { + handleExternalSpecies(speciesUrl, geneName) + } + + const targetView = validateView(viewId) + const geneticElement = await loadGene(geneName) + + if (targetView && geneticElement) { + addGeneticElements([geneticElement]) + setActiveViewId(targetView.id) + setActiveView(targetView) + setActiveGeneId(geneticElement.id) + setActiveGene(geneticElement) + } + } + + return ( + + {children} + + ) + } + + ViewSwitchProvider.displayName = 'ViewSwitchProvider' + return ViewSwitchProvider +} diff --git a/package-lock.json b/package-lock.json index 671acbea..8082e290 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,31 +22,46 @@ "@mui/x-data-grid": "^6.15.0", "@mui/x-tree-view": "^7.5.1", "@popperjs/core": "^2.11.8", + "@types/cytoscape": "^3.21.5", + "@types/d3-hierarchy": "^3.1.7", + "@types/d3-scale": "^4.0.8", + "@types/d3-selection": "^3.0.11", "@types/react-router-dom": "^5.3.3", - "@vis.gl/react-google-maps": "^1.0.1", + "@vis.gl/react-google-maps": "^1.5.1", + "@visx/visx": "^3.11.0", "axios": "^1.5.1", "color2k": "^2.0.2", + "cytoscape": "^3.30.1", + "cytoscape-automove": "^1.10.3", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-navigator": "^2.0.2", + "cytoscape-popper": "^4.0.0", + "d3": "^7.9.0", "dompurify": "^3.0.6", "flexlayout-react": "^0.7.11", "idb": "^7.1.1", "jotai": "^2.4.3", "lodash": "^4.17.21", - "react": "^18.2.0", + "newick": "^2.0.0", + "newick-js": "^1.2.1", + "react": "^18.3.1", "react-dom": "^18.2.0", "react-router-dom": "^6.16.0", - "react-window": "^1.8.9" + "react-window": "^1.8.9", + "tippy.js": "^6.3.7" }, "devDependencies": { "@eslint/js": "^9.3.0", "@testing-library/jest-dom": "^6.1.3", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.1", + "@types/d3": "^7.4.3", "@types/dompurify": "^3.0.3", "@types/google-map-react": "^2.1.10", "@types/jest": "^29.5.5", "@types/lodash": "^4.14.199", - "@types/react": "^18.2.23", - "@types/react-dom": "^18.2.8", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@types/react-window": "^1.8.6", "@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/parser": "^6.0.0", @@ -60,11 +75,12 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-tsdoc": "^0.4.0", "globals": "^15.2.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "jotai-devtools": "^0.7.0", - "msw": "^1.3.1", + "msw": "^2.6.5", "prettier": "3.1.0", "react-draggable": "^4.4.6", "react-transition-group": "^4.4.5", @@ -632,6 +648,37 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@bundled-es-modules/cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cookie": "^0.7.2" + } + }, + "node_modules/@bundled-es-modules/statuses": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", + "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", + "dev": true, + "license": "ISC", + "dependencies": { + "statuses": "^2.0.1" + } + }, + "node_modules/@bundled-es-modules/tough-cookie": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", + "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + } + }, "node_modules/@dnd-kit/accessibility": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz", @@ -832,54 +879,6 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" }, - "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-arm64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", @@ -896,294 +895,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -1411,14 +1122,105 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@inquirer/confirm": { + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.12.tgz", + "integrity": "sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==", "dev": true, + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", + "@inquirer/core": "^10.1.13", + "@inquirer/type": "^3.0.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.13", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.13.tgz", + "integrity": "sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", + "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.7.tgz", + "integrity": "sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" @@ -2326,45 +2128,66 @@ "react": ">=16.8.0" } }, - "node_modules/@mswjs/cookies": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", - "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", + "node_modules/@microsoft/tsdoc": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz", + "integrity": "sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.1.tgz", + "integrity": "sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/set-cookie-parser": "^2.4.0", - "set-cookie-parser": "^2.4.6" - }, - "engines": { - "node": ">=14" + "@microsoft/tsdoc": "0.15.1", + "ajv": "~8.12.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" } }, - "node_modules/@mswjs/interceptors": { - "version": "0.17.10", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.10.tgz", - "integrity": "sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==", + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, + "license": "MIT", "dependencies": { - "@open-draft/until": "^1.0.3", - "@types/debug": "^4.1.7", - "@xmldom/xmldom": "^0.8.3", - "debug": "^4.3.3", - "headers-polyfill": "3.2.5", - "outvariant": "^1.2.1", - "strict-event-emitter": "^0.2.4", - "web-encoding": "^1.1.5" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=14" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@mswjs/interceptors/node_modules/strict-event-emitter": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz", - "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==", + "node_modules/@microsoft/tsdoc-config/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mswjs/interceptors": { + "version": "0.38.7", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.38.7.tgz", + "integrity": "sha512-Jkb27iSn7JPdkqlTqKfhncFfnEZsIJVYxsFbUSWEkxdIPdsyngrhoDBk0/BGD2FQcRH99vlRrkHpNTyKqI+0/w==", "dev": true, + "license": "MIT", "dependencies": { - "events": "^3.3.0" + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" } }, "node_modules/@mui/base": { @@ -2741,11 +2564,30 @@ "node": ">= 8" } }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, "node_modules/@open-draft/until": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", - "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true, + "license": "MIT" }, "node_modules/@popperjs/core": { "version": "2.11.8", @@ -2898,6 +2740,84 @@ "react": "^16.8 || ^17.0 || ^18.0" } }, + "node_modules/@react-spring/animated": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", + "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", + "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", + "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", + "license": "MIT", + "peer": true + }, + "node_modules/@react-spring/shared": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", + "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-spring/rafz": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", + "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", + "license": "MIT", + "peer": true + }, + "node_modules/@react-spring/web": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", + "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@redux-devtools/extension": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@redux-devtools/extension/-/extension-3.3.0.tgz", @@ -3257,18 +3177,339 @@ "dev": true }, "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cytoscape": { + "version": "3.21.5", + "resolved": "https://registry.npmjs.org/@types/cytoscape/-/cytoscape-3.21.5.tgz", + "integrity": "sha512-fzYT3vqY5J4gxVXDOsCgDpm0ZdU8bQq+wCv0ucS0MSTtvQdjs3lcb2VetJiUSAd4WBgouqizI+JT1f8Yc6eY7Q==" + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-cloud": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/d3-cloud/-/d3-cloud-1.2.5.tgz", + "integrity": "sha512-vEIER9DsEBUOdpRiwCh3n1qE+cV6h4e1LhxhY2sLt+m8LPNAIkOOhTlqk0JDiBwD+ZPM8ynFAOU3AuPuVYBFBA==", + "license": "MIT", + "dependencies": { + "@types/d3": "^3" + } + }, + "node_modules/@types/d3-cloud/node_modules/@types/d3": { + "version": "3.5.53", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.53.tgz", + "integrity": "sha512-8yKQA9cAS6+wGsJpBysmnhlaaxlN42Qizqkw+h2nILSlS+MAG2z4JdO6p+PJrJ+ACvimkmLJL281h157e52psQ==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-sankey": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/@types/d3-sankey/-/d3-sankey-0.12.4.tgz", + "integrity": "sha512-YTicQNwioitIlvuvlfW2GfO6sKxpohzg2cSQttlXAPjFwoBuN+XpGLhUN3kLutG/dI3GCLC+DUorqiJt7Naetw==", + "license": "MIT", + "dependencies": { + "@types/d3-shape": "^1" + } + }, + "node_modules/@types/d3-sankey/node_modules/@types/d3-path": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.11.tgz", + "integrity": "sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==", + "license": "MIT" + }, + "node_modules/@types/d3-sankey/node_modules/@types/d3-shape": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.12.tgz", + "integrity": "sha512-8oMzcd4+poSLGgV0R1Q1rOlx/xdmozS4Xab7np0eamFFUYq71AU9pOCJEFnkXW2aI/oXdVYJzw6pssbSut7Z9Q==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "^1" + } + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "dev": true, + "license": "MIT" }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-voronoi": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.12.tgz", + "integrity": "sha512-DauBl25PKZZ0WVJr42a6CNvI6efsdzofl9sajqZr2Gf5Gu733WkDdUGiPkUHXiUvYGzNNlFQde2wdZdfQPG+yw==", + "license": "MIT" + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/ms": "*" + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" } }, "node_modules/@types/dompurify": { @@ -3307,19 +3548,27 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, "node_modules/@types/google-map-react": { "version": "2.1.10", "resolved": "https://registry.npmjs.org/@types/google-map-react/-/google-map-react-2.1.10.tgz", "integrity": "sha512-8/0UllZS7tF08WNBRPQlSJCkETvz3e3sZoPxzDaWkj2iV5dmFSnOKXVtoeKo8dLZSe+RkLn479t1wj6nXmLLSA==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } }, "node_modules/@types/google.maps": { - "version": "3.55.9", - "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.55.9.tgz", - "integrity": "sha512-phaOMtezbT3NaXPKiI3m0OosUS7Nly0auw3Be5s/CgMWLVoDAUP1Yb/Ld0TRoRp8ibrlT4VqM5kmzfvUA0UNLQ==" + "version": "3.58.1", + "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz", + "integrity": "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==", + "license": "MIT" }, "node_modules/@types/graceful-fs": { "version": "4.1.9", @@ -3395,12 +3644,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/js-levenshtein": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz", - "integrity": "sha512-jd+Q+sD20Qfu9e2aEXogiO3vpOC1PYJOUdyN9gvs4Qrvkg4wF43L5OhqrPeokdv8TL0/mXoYfpkcoGZMNN2pkQ==", - "dev": true - }, "node_modules/@types/jsdom": { "version": "20.0.1", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", @@ -3421,14 +3664,7 @@ "node_modules/@types/lodash": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", - "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", - "dev": true - }, - "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", - "dev": true + "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==" }, "node_modules/@types/node": { "version": "20.11.30", @@ -3450,22 +3686,22 @@ "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/react": { - "version": "18.2.67", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.67.tgz", - "integrity": "sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==", + "version": "18.3.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.22", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", - "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", - "dev": true, - "dependencies": { - "@types/react": "*" + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" } }, "node_modules/@types/react-router": { @@ -3504,32 +3740,25 @@ "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, - "node_modules/@types/set-cookie-parser": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.7.tgz", - "integrity": "sha512-+ge/loa0oTozxip6zmhRIk8Z/boU51wl9Q6QdLZcokIGMzY5lFXYy/x7Htj2HTC6/KZP1hUbZ1ekx8DYXICvWg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, + "node_modules/@types/statuses": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz", + "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", @@ -3852,598 +4081,1653 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "license": "MIT" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, "node_modules/@vis.gl/react-google-maps": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@vis.gl/react-google-maps/-/react-google-maps-1.0.1.tgz", - "integrity": "sha512-GCPuK9HNndTh3BATj/4HcsjnKo4qFLWVFfjfwxKP8GxHEWEj7Na0fxT7eY1zFIEyPIak9ekmWFHJhDk8knf7Uw==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vis.gl/react-google-maps/-/react-google-maps-1.5.2.tgz", + "integrity": "sha512-0Ypmde7M73GgV4TgcaUTNKXsbcXWToPVuawMNrVg7htXmhpEfLARHwhtmP6N1da3od195ZKC8ShXzC6Vm+zYHQ==", + "license": "MIT", "dependencies": { "@types/google.maps": "^3.54.10", "fast-deep-equal": "^3.1.3" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "react": ">=16.8.0 || ^19.0 || ^19.0.0-rc", + "react-dom": ">=16.8.0 || ^19.0 || ^19.0.0-rc" } }, - "node_modules/@vitejs/plugin-react": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", - "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", - "dev": true, + "node_modules/@visx/annotation": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/annotation/-/annotation-3.12.0.tgz", + "integrity": "sha512-ZH6Y4jfrb47iEUV9O2itU9TATE5IPzhs5qvP6J7vmv26qkqwDcuE7xN3S3l9R70WjyEKGbpO8js4EijA3FJWkA==", + "license": "MIT", "dependencies": { - "@babel/core": "^7.23.5", - "@babel/plugin-transform-react-jsx-self": "^7.23.3", - "@babel/plugin-transform-react-jsx-source": "^7.23.3", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" + "@types/react": "*", + "@visx/drag": "3.12.0", + "@visx/group": "3.12.0", + "@visx/text": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.5.10", + "react-use-measure": "^2.0.4" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, - "peer": true, + "node_modules/@visx/axis": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/axis/-/axis-3.12.0.tgz", + "integrity": "sha512-8MoWpfuaJkhm2Yg+HwyytK8nk+zDugCqTT/tRmQX7gW4LYrHYLXFUXOzbDyyBakCVaUbUaAhVFxpMASJiQKf7A==", + "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@types/react": "*", + "@visx/group": "3.12.0", + "@visx/point": "3.12.0", + "@visx/scale": "3.12.0", + "@visx/shape": "3.12.0", + "@visx/text": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.6.0" + }, + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "peer": true, + "node_modules/@visx/bounds": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/bounds/-/bounds-3.12.0.tgz", + "integrity": "sha512-peAlNCUbYaaZ0IO6c1lDdEAnZv2iGPDiLIM8a6gu7CaMhtXZJkqrTh+AjidNcIqITktrICpGxJE/Qo9D099dvQ==", + "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" + "@types/react": "*", + "@types/react-dom": "*", + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0", + "react-dom": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dev": true, - "peer": true, + "node_modules/@visx/brush": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/brush/-/brush-3.12.0.tgz", + "integrity": "sha512-ceqQe/IlIi9X9FT/DuiO6b3l5YAGnux/aQMX8M1gvLdz4T8pXIW8nDv1OhqbZ7lmbQEUEEM9IexOkR9ix7pL+Q==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@visx/drag": "3.12.0", + "@visx/event": "3.12.0", + "@visx/group": "3.12.0", + "@visx/scale": "3.12.0", + "@visx/shape": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.6.1" + }, + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "peer": true, + "node_modules/@visx/clip-path": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/clip-path/-/clip-path-3.12.0.tgz", + "integrity": "sha512-pjpjyoQ15lhOrgpDhxfWKAxC4IswzREHGOHhrdWtxQbPoGzVZvFH8HHvwRi4afL11uYDO10z235MDnaDwP8GnQ==", + "license": "MIT", "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "@types/react": "*", + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "peer": true, + "node_modules/@visx/curve": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/curve/-/curve-3.12.0.tgz", + "integrity": "sha512-Ng1mefXIzoIoAivw7dJ+ZZYYUbfuwXgZCgQynShr6ZIVw7P4q4HeQfJP3W24ON+1uCSrzoycHSXRelhR9SBPcw==", + "license": "MIT", "dependencies": { - "@xtuc/long": "4.2.2" + "@types/d3-shape": "^1.3.1", + "d3-shape": "^1.0.6" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true, - "peer": true + "node_modules/@visx/curve/node_modules/@types/d3-path": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.11.tgz", + "integrity": "sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==", + "license": "MIT" }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, - "peer": true, + "node_modules/@visx/curve/node_modules/@types/d3-shape": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.12.tgz", + "integrity": "sha512-8oMzcd4+poSLGgV0R1Q1rOlx/xdmozS4Xab7np0eamFFUYq71AU9pOCJEFnkXW2aI/oXdVYJzw6pssbSut7Z9Q==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@types/d3-path": "^1" } }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dev": true, - "peer": true, + "node_modules/@visx/delaunay": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/delaunay/-/delaunay-3.12.0.tgz", + "integrity": "sha512-bc8UCJ3l5G6lGnQt5AUo8GIZTm16vKpJycb/6IWHTDeBv4hJL0uahG5QKhy1d08T0cFtYQ3qv/xp5LQkwFxfsw==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@types/react": "*", + "@visx/vendor": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.6.1" + }, + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dev": true, - "peer": true, + "node_modules/@visx/drag": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/drag/-/drag-3.12.0.tgz", + "integrity": "sha512-LXOoPVw//YPjpYhDJYBsCYDuv1QimsXjDV98duH0aCy4V94ediXMQpe2wHq4pnlDobLEB71FjOZMFrbFmqtERg==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@types/react": "*", + "@visx/event": "3.12.0", + "@visx/point": "3.12.0", + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dev": true, - "peer": true, + "node_modules/@visx/event": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/event/-/event-3.12.0.tgz", + "integrity": "sha512-9Lvw6qJ0Fi+y1vsC1WspfdIKCxHTb7oy59Uql1uBdPGT8zChP0vuxW0jQNQRDbKgoefj4pCXAFi8+MF1mEtVTw==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@types/react": "*", + "@visx/point": "3.12.0" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dev": true, - "peer": true, + "node_modules/@visx/geo": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/geo/-/geo-3.12.0.tgz", + "integrity": "sha512-/74NMEqGrAGXOKIdvuLsarUNs5liTjUs3XrgLb4UbSDMoo2itgQN6tCZuIxFKMdEBahfJl+s6pEVPLur5bH4vg==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" + "@types/geojson": "*", + "@types/react": "*", + "@visx/group": "3.12.0", + "@visx/vendor": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", - "dev": true, - "engines": { - "node": ">=10.0.0" + "node_modules/@visx/glyph": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/glyph/-/glyph-3.12.0.tgz", + "integrity": "sha512-E9ST9MoPNyXQzjZxYYAGXT4CbBpnB90Qhx8UvUUM2/n/SZUNeH+m6UiB/CzT0jGK2b0lPHF91mlOiQ8JXBRhYg==", + "license": "MIT", + "dependencies": { + "@types/d3-shape": "^1.3.1", + "@types/react": "*", + "@visx/group": "3.12.0", + "classnames": "^2.3.1", + "d3-shape": "^1.2.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "peer": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "peer": true - }, - "node_modules/@zxing/text-encoding": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", - "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", - "dev": true, - "optional": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true + "node_modules/@visx/glyph/node_modules/@types/d3-path": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.11.tgz", + "integrity": "sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==", + "license": "MIT" }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "node_modules/@visx/glyph/node_modules/@types/d3-shape": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.12.tgz", + "integrity": "sha512-8oMzcd4+poSLGgV0R1Q1rOlx/xdmozS4Xab7np0eamFFUYq71AU9pOCJEFnkXW2aI/oXdVYJzw6pssbSut7Z9Q==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "^1" } }, - "node_modules/acorn-globals": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", - "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", - "dev": true, + "node_modules/@visx/gradient": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/gradient/-/gradient-3.12.0.tgz", + "integrity": "sha512-QRatjjdUEPbcp4pqRca1JlChpAnmmIAO3r3ZscLK7D1xEIANlIjzjl3uNgrmseYmBAYyPCcJH8Zru07R97ovOg==", + "license": "MIT", "dependencies": { - "acorn": "^8.1.0", - "acorn-walk": "^8.0.2" + "@types/react": "*", + "prop-types": "^15.5.7" + }, + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "peer": true, + "node_modules/@visx/grid": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/grid/-/grid-3.12.0.tgz", + "integrity": "sha512-L4ex2ooSYhwNIxJ3XFIKRhoSvEGjPc2Y3YCrtNB4TV5Ofdj4q0UMOsxfrH23Pr8HSHuQhb6VGMgYoK0LuWqDmQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/curve": "3.12.0", + "@visx/group": "3.12.0", + "@visx/point": "3.12.0", + "@visx/scale": "3.12.0", + "@visx/shape": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.6.2" + }, "peerDependencies": { - "acorn": "^8" + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, + "node_modules/@visx/group": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/group/-/group-3.12.0.tgz", + "integrity": "sha512-Dye8iS1alVXPv7nj/7M37gJe6sSKqJLH7x6sEWAsRQ9clI0kFvjbKcKgF+U3aAVQr0NCohheFV+DtR8trfK/Ag==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "classnames": "^2.3.1", + "prop-types": "^15.6.2" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, - "engines": { - "node": ">=0.4.0" + "node_modules/@visx/heatmap": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/heatmap/-/heatmap-3.12.0.tgz", + "integrity": "sha512-+YhXHfMvwQOMf9xMd15FUOoiKqf84o1UF0zsmnNsCC75MqFMpjvzc3DeoC37fi69iBIKchU8DjhVubvCE9N4jA==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/group": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.6.1" + }, + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, + "node_modules/@visx/hierarchy": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/hierarchy/-/hierarchy-3.12.0.tgz", + "integrity": "sha512-+X1HOeLEOODxjAD7ixrWJ4KCVei4wFe8ra3dYU0uZ14RdPPgUeiuyBfdeXWZuAHM6Ix9qrryneatQjkC3h4mvA==", + "license": "MIT", "dependencies": { - "debug": "4" + "@types/d3-hierarchy": "^1.1.6", + "@types/react": "*", + "@visx/group": "3.12.0", + "classnames": "^2.3.1", + "d3-hierarchy": "^1.1.4", + "prop-types": "^15.6.1" }, - "engines": { - "node": ">= 6.0.0" + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "node_modules/@visx/hierarchy/node_modules/@types/d3-hierarchy": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.11.tgz", + "integrity": "sha512-lnQiU7jV+Gyk9oQYk0GGYccuexmQPTp08E0+4BidgFdiJivjEvf+esPSdZqCZ2C7UwTWejWpqetVaU8A+eX3FA==", + "license": "MIT" + }, + "node_modules/@visx/legend": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/legend/-/legend-3.12.0.tgz", + "integrity": "sha512-Tr6hdauEDXRXVNeNgIQ9JtCCrxn8Fbr8UCVlO9XsSxenk2hBC/2PIY5QPzpnKFEEEuH/C8vhj8T0JfFZV+D9zQ==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@types/react": "*", + "@visx/group": "3.12.0", + "@visx/scale": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.5.10" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, + "node_modules/@visx/marker": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/marker/-/marker-3.12.0.tgz", + "integrity": "sha512-11aCWC13+PqbAatNgMVcm33J8PRNdyGiDbfMfwUXt5/FS2XLs2e1fjfhIwAxmCCLZ13FYlabrc1qnjnhwXbTVQ==", + "license": "MIT", "dependencies": { - "ajv": "^8.0.0" + "@types/react": "*", + "@visx/group": "3.12.0", + "@visx/shape": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.6.2" }, "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, + "node_modules/@visx/mock-data": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/mock-data/-/mock-data-3.12.0.tgz", + "integrity": "sha512-HI8LKdO3sU2tIBv16ZYRTc2JYsu0Ai/hQc7YUOBqbjhXUW993iCBe98pAgEdHDrSWqK2yvXY4En5ceBTAP34Jw==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "@types/d3-random": "^2.2.0", + "d3-random": "^2.2.2" } }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/@visx/mock-data/node_modules/@types/d3-random": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-2.2.3.tgz", + "integrity": "sha512-Ghs4R3CcgJ3o6svszRzIH4b8PPYex/COo+rhhZjDAs+bVducXwjmVSi27WcDOaLLCBV2t3tfVH9bYXAL76IvQA==", + "license": "MIT" }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peer": true, + "node_modules/@visx/network": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/network/-/network-3.12.0.tgz", + "integrity": "sha512-mVWF9TQVpe6Qz95IJ+Pm+FB6xhdjzFGRKK7/qQFhjRloIJqVZkChAiBIua04Ux8BeyCt37wdFgQKFl6C2u3DXA==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/group": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.6.2" + }, "peerDependencies": { - "ajv": "^6.9.1" + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, + "node_modules/@visx/pattern": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/pattern/-/pattern-3.12.0.tgz", + "integrity": "sha512-ZkNA/2TkULNiiY4cw2IkuQcQRp9zI3SQ0/JoZMQ+UmUvY5RNBcsdTmic7649egHq0FRYCbY0DDQVJicccW5JUg==", + "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" + "@types/react": "*", + "classnames": "^2.3.1", + "prop-types": "^15.5.10" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/@visx/point": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/point/-/point-3.12.0.tgz", + "integrity": "sha512-I6UrHoJAEVbx3RORQNupgTiX5EzjuZpiwLPxn8L2mI5nfERotPKi1Yus12Cq2WtXqEBR/WgqTnoImlqOXBykcA==", + "license": "MIT" + }, + "node_modules/@visx/react-spring": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/react-spring/-/react-spring-3.12.0.tgz", + "integrity": "sha512-ehtmjFrUQx3g0mZ684M4LgI9UfQ84ZWD/m9tKfvXhEm1Vl8D4AjaZ4af1tTOg9S7vk2VlpxvVOVN7+t5pu0nSA==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/axis": "3.12.0", + "@visx/grid": "3.12.0", + "@visx/scale": "3.12.0", + "@visx/text": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "@react-spring/web": "^9.4.5", + "react": "^16.3.0-0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@visx/responsive": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-3.12.0.tgz", + "integrity": "sha512-GV1BTYwAGlk/K5c9vH8lS2syPnTuIqEacI7L6LRPbsuaLscXMNi+i9fZyzo0BWvAdtRV8v6Urzglo++lvAXT1Q==", + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "@types/lodash": "^4.14.172", + "@types/react": "*", + "lodash": "^4.17.21", + "prop-types": "^15.6.1" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, + "node_modules/@visx/sankey": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/sankey/-/sankey-3.12.0.tgz", + "integrity": "sha512-B3zIUejzv8ySGmcgJhqiy616llauT0CwvL7wWyTh2z3eCBkFOlPVF85NBrQq823w/0DkwoX8+LmLpKyelh6Vpw==", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@types/d3-sankey": "^0.12.4", + "@types/react": "*", + "@visx/group": "3.12.0", + "classnames": "^2.3.1", + "d3-sankey": "^0.12.3", + "d3-shape": "1.3.7" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "node_modules/@visx/scale": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/scale/-/scale-3.12.0.tgz", + "integrity": "sha512-+ubijrZ2AwWCsNey0HGLJ0YKNeC/XImEFsr9rM+Uef1CM3PNM43NDdNTrdBejSlzRq0lcfQPWYMYQFSlkLcPOg==", + "license": "MIT", + "dependencies": { + "@visx/vendor": "3.12.0" + } }, - "node_modules/aria-hidden": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", - "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", - "dev": true, + "node_modules/@visx/shape": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/shape/-/shape-3.12.0.tgz", + "integrity": "sha512-/1l0lrpX9tPic6SJEalryBKWjP/ilDRnQA+BGJTI1tj7i23mJ/J0t4nJHyA1GrL4QA/bM/qTJ35eyz5dEhJc4g==", + "license": "MIT", "dependencies": { - "tslib": "^2.0.0" + "@types/d3-path": "^1.0.8", + "@types/d3-shape": "^1.3.1", + "@types/lodash": "^4.14.172", + "@types/react": "*", + "@visx/curve": "3.12.0", + "@visx/group": "3.12.0", + "@visx/scale": "3.12.0", + "classnames": "^2.3.1", + "d3-path": "^1.0.5", + "d3-shape": "^1.2.0", + "lodash": "^4.17.21", + "prop-types": "^15.5.10" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, + "node_modules/@visx/shape/node_modules/@types/d3-path": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.11.tgz", + "integrity": "sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==", + "license": "MIT" + }, + "node_modules/@visx/shape/node_modules/@types/d3-shape": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.12.tgz", + "integrity": "sha512-8oMzcd4+poSLGgV0R1Q1rOlx/xdmozS4Xab7np0eamFFUYq71AU9pOCJEFnkXW2aI/oXdVYJzw6pssbSut7Z9Q==", + "license": "MIT", "dependencies": { - "deep-equal": "^2.0.5" + "@types/d3-path": "^1" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, + "node_modules/@visx/text": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/text/-/text-3.12.0.tgz", + "integrity": "sha512-0rbDYQlbuKPhBqXkkGYKFec1gQo05YxV45DORzr6hCyaizdJk1G+n9VkuKSHKBy1vVQhBA0W3u/WXd7tiODQPA==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" + "@types/lodash": "^4.14.172", + "@types/react": "*", + "classnames": "^2.3.1", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "reduce-css-calc": "^1.3.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, + "node_modules/@visx/threshold": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/threshold/-/threshold-3.12.0.tgz", + "integrity": "sha512-HpbJbFBKaFOM7FiMiOQwZhQAoDtd5+xSUZRlZ3U7N7TF3S2oVKIBRNlMakhcu0eick7UNvmCl7ZTW2lI65IX4g==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" + "@types/react": "*", + "@visx/clip-path": "3.12.0", + "@visx/shape": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.5.10" }, - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" + } + }, + "node_modules/@visx/tooltip": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/tooltip/-/tooltip-3.12.0.tgz", + "integrity": "sha512-pWhsYhgl0Shbeqf80qy4QCB6zpq6tQtMQQxKlh3UiKxzkkfl+Metaf9p0/S0HexNi4vewOPOo89xWx93hBeh3A==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/bounds": "3.12.0", + "classnames": "^2.3.1", + "prop-types": "^15.5.10", + "react-use-measure": "^2.0.4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "react": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0", + "react-dom": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0" + } + }, + "node_modules/@visx/vendor": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/vendor/-/vendor-3.12.0.tgz", + "integrity": "sha512-SVO+G0xtnL9dsNpGDcjCgoiCnlB3iLSM9KLz1sLbSrV7RaVXwY3/BTm2X9OWN1jH2a9M+eHt6DJ6sE6CXm4cUg==", + "license": "MIT and ISC", + "dependencies": { + "@types/d3-array": "3.0.3", + "@types/d3-color": "3.1.0", + "@types/d3-delaunay": "6.0.1", + "@types/d3-format": "3.0.1", + "@types/d3-geo": "3.1.0", + "@types/d3-interpolate": "3.0.1", + "@types/d3-scale": "4.0.2", + "@types/d3-time": "3.0.0", + "@types/d3-time-format": "2.1.0", + "d3-array": "3.2.1", + "d3-color": "3.1.0", + "d3-delaunay": "6.0.2", + "d3-format": "3.1.0", + "d3-geo": "3.1.0", + "d3-interpolate": "3.0.1", + "d3-scale": "4.0.2", + "d3-time": "3.1.0", + "d3-time-format": "4.1.0", + "internmap": "2.0.3" + } + }, + "node_modules/@visx/vendor/node_modules/@types/d3-array": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", + "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==", + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==", + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==", + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" } }, - "node_modules/array-union": { + "node_modules/@visx/vendor/node_modules/@types/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@visx/vendor/node_modules/@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-time-format": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", + "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==", + "license": "MIT" + }, + "node_modules/@visx/visx": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/visx/-/visx-3.12.0.tgz", + "integrity": "sha512-Lx8XKFUz8eyaR07jdUWcMcPYRp+sfrd3OsGw8uFIuZeAJ0hF6Ni7f7TVvyW1W5chlvCrL4/MGQTCjN/A8o3UZQ==", + "license": "MIT", + "dependencies": { + "@visx/annotation": "3.12.0", + "@visx/axis": "3.12.0", + "@visx/bounds": "3.12.0", + "@visx/brush": "3.12.0", + "@visx/clip-path": "3.12.0", + "@visx/curve": "3.12.0", + "@visx/delaunay": "3.12.0", + "@visx/drag": "3.12.0", + "@visx/event": "3.12.0", + "@visx/geo": "3.12.0", + "@visx/glyph": "3.12.0", + "@visx/gradient": "3.12.0", + "@visx/grid": "3.12.0", + "@visx/group": "3.12.0", + "@visx/heatmap": "3.12.0", + "@visx/hierarchy": "3.12.0", + "@visx/legend": "3.12.0", + "@visx/marker": "3.12.0", + "@visx/mock-data": "3.12.0", + "@visx/network": "3.12.0", + "@visx/pattern": "3.12.0", + "@visx/point": "3.12.0", + "@visx/responsive": "3.12.0", + "@visx/sankey": "3.12.0", + "@visx/scale": "3.12.0", + "@visx/shape": "3.12.0", + "@visx/text": "3.12.0", + "@visx/threshold": "3.12.0", + "@visx/tooltip": "3.12.0", + "@visx/voronoi": "3.12.0", + "@visx/wordcloud": "3.12.0", + "@visx/xychart": "3.12.0", + "@visx/zoom": "3.12.0" + }, + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, + "node_modules/@visx/voronoi": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/voronoi/-/voronoi-3.12.0.tgz", + "integrity": "sha512-U3HWu6g5UjQchFDq8k/A4U9WrlN+80rAFPdGOUvIGOueQw9RmlZlNaeg8IJcQr2yk1s4O/VSpt3nR82zdINWMw==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" + "@types/d3-voronoi": "^1.1.9", + "@types/react": "*", + "classnames": "^2.3.1", + "d3-voronoi": "^1.1.2", + "prop-types": "^15.6.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, + "node_modules/@visx/wordcloud": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/wordcloud/-/wordcloud-3.12.0.tgz", + "integrity": "sha512-TAo9w1Z65ddRM1OPmrELXNvDSOYf4MRO0+VAIX5FNFAc8v4FNmTJriSWc+A/FIZL+1svDOKnDP9SwF86NX4Alg==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "@types/d3-cloud": "1.2.5", + "@visx/group": "3.12.0", + "d3-cloud": "^1.2.5" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "react": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, + "node_modules/@visx/xychart": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/xychart/-/xychart-3.12.0.tgz", + "integrity": "sha512-itJ7qvj/STpVmHesVyo2vPOataBM1mgSaf9R6/s4Bpe340wZldfCJ+IqRcNgdtbBagz1Hlr/sRnla4tWE2yw9A==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "@types/lodash": "^4.14.172", + "@types/react": "*", + "@visx/annotation": "3.12.0", + "@visx/axis": "3.12.0", + "@visx/event": "3.12.0", + "@visx/glyph": "3.12.0", + "@visx/grid": "3.12.0", + "@visx/react-spring": "3.12.0", + "@visx/responsive": "3.12.0", + "@visx/scale": "3.12.0", + "@visx/shape": "3.12.0", + "@visx/text": "3.12.0", + "@visx/tooltip": "3.12.0", + "@visx/vendor": "3.12.0", + "@visx/voronoi": "3.12.0", + "classnames": "^2.3.1", + "d3-interpolate-path": "2.2.1", + "d3-shape": "^2.0.0", + "lodash": "^4.17.21", + "mitt": "^2.1.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "@react-spring/web": "^9.4.5", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@visx/xychart/node_modules/d3-shape": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz", + "integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1 - 2" + } + }, + "node_modules/@visx/zoom": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@visx/zoom/-/zoom-3.12.0.tgz", + "integrity": "sha512-JmxkOROPkjnMEdFGnnSKLo5BkFHgOkLe/N5KkWR02cA5bE+bmEkfAh7DJfrtVsPkqSPvwGH1TrMWWthJwoivPA==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@use-gesture/react": "^10.0.0-beta.22", + "@visx/event": "3.12.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "peer": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base16": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", + "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", - "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", - "es-shim-unscopables": "^1.0.2" + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node-int64": "^0.4.0" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "node_modules/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 }, - "node_modules/available-typed-arrays": { + "node_modules/call-bind": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "possible-typed-array-names": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -4452,921 +5736,998 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" } }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" + "node": ">=6" } }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/caniuse-lite": { + "version": "1.0.30001599", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", + "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { - "color-convert": "^2.0.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.8.0" } }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=10" } }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/chromatic": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-7.6.0.tgz", + "integrity": "sha512-4MwlX8EDMyfQKf1NXTdUhJ2b0EYueByaVrF75pdFaOzHH7n3OhzknmQYbUSegLiFhKvHuvM8nZvf9SCajO+Cow==", + "dev": true, + "bin": { + "chroma": "dist/bin.js", + "chromatic": "dist/bin.js", + "chromatic-cli": "dist/bin.js" + } }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/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, + "peer": true, "engines": { - "node": ">=8" + "node": ">=6.0" } }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "engines": { "node": ">=8" } }, - "node_modules/babel-loader": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", - "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, - "dependencies": { - "find-cache-dir": "^4.0.0", - "schema-utils": "^4.0.0" - }, + "license": "ISC", "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5" + "node": ">= 12" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" + "color-name": "~1.1.4" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=7.0.0" } }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=10", - "npm": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" } }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/balanced-match": { + "node_modules/collect-v8-coverage": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base16": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", - "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "color-name": "1.1.3" } }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, + "node_modules/color2k": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz", + "integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dependencies": { - "fill-range": "^7.0.1" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "peer": true + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" + "layout-base": "^1.0.0" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@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" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=10" } }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, "dependencies": { - "fast-json-stable-stringify": "2.x" + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/create-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/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 - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/create-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/create-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/create-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/create-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001599", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", - "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==", + "node_modules/create-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" + "node": ">=8" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">= 8" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", "dev": true }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "cssom": "~0.3.6" }, "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=8" } }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/cytoscape": { + "version": "3.30.2", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.2.tgz", + "integrity": "sha512-oICxQsjW8uSaRmn4UK/jkczKOqTrVqt5/1WL0POiJUT2EKNc9STM4hYFHv917yu55aTBMFNRzymlJhVAiWPCxw==", "engines": { - "node": ">= 6" + "node": ">=0.10" } }, - "node_modules/chromatic": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-7.6.0.tgz", - "integrity": "sha512-4MwlX8EDMyfQKf1NXTdUhJ2b0EYueByaVrF75pdFaOzHH7n3OhzknmQYbUSegLiFhKvHuvM8nZvf9SCajO+Cow==", - "dev": true, - "bin": { - "chroma": "dist/bin.js", - "chromatic": "dist/bin.js", - "chromatic-cli": "dist/bin.js" + "node_modules/cytoscape-automove": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/cytoscape-automove/-/cytoscape-automove-1.10.3.tgz", + "integrity": "sha512-Byj9RkFolphbSoZ/XAse3ch3i/5mDEwaYAy+s8iEJzbzDsnakxQ4BgaHNm9ydUqq38I3vtM6NSmRMTV2DK9QaA==", + "peerDependencies": { + "cytoscape": "^3.2.0" } }, - "node_modules/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, - "peer": true, - "engines": { - "node": ">=6.0" + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" } }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" + "node_modules/cytoscape-navigator": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/cytoscape-navigator/-/cytoscape-navigator-2.0.2.tgz", + "integrity": "sha512-TZFBLFWEMW858UOt4rzusOjtDj7YT5vNx2uCwpUuicUYbaWCHHcUROBZWO+hiuSPWpVhvGLFlOq3NBcAVYOAgw==", + "peerDependencies": { + "cytoscape": "^2.6.0 || ^3.0.0" } }, - "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "node_modules/cytoscape-popper": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cytoscape-popper/-/cytoscape-popper-4.0.0.tgz", + "integrity": "sha512-M4q2YeIhZvRDslMLzVuGZKb6HAU3O6M51NAaRc0hr3KubQabiK2c9dEGwfVIBPcDnxr9u/oFAMhAU7DEf2EHaA==", + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, + "node_modules/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", + "license": "ISC", "dependencies": { - "restore-cursor": "^3.1.0" + "internmap": "1 - 2" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/cli-width": { + "node_modules/d3-brush": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, "engines": { - "node": ">= 10" + "node": ">=12" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "d3-path": "1 - 3" }, "engines": { "node": ">=12" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/d3-cloud": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/d3-cloud/-/d3-cloud-1.2.7.tgz", + "integrity": "sha512-8TrgcgwRIpoZYQp7s3fGB7tATWfhckRb8KcVd1bOgqkNdkJRDGWfdSf4HkHHzZxSczwQJdSxvfPudwir5IAJ3w==", + "license": "BSD-3-Clause", "dependencies": { - "color-convert": "^2.0.1" - }, + "d3-dispatch": "^1.0.3" + } + }, + "node_modules/d3-cloud/node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": ">=12" } }, - "node_modules/cliui/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "delaunator": "5" }, "engines": { - "node": ">=7.0.0" + "node": ">=12" } }, - "node_modules/cliui/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "d3-dispatch": "1 - 3", + "d3-selection": "3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=12" } }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, "engines": { - "node": ">=0.8" + "node": ">=12" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 10" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=12" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dev": true, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", "dependencies": { - "color-name": "1.1.3" + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dev": true, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "license": "ISC", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/color2k": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz", - "integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==" + "node_modules/d3-hierarchy": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", + "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==", + "license": "BSD-3-Clause" }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { - "delayed-stream": "~1.0.0" + "d3-color": "1 - 3" }, "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "peer": true - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true + "node_modules/d3-interpolate-path": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/d3-interpolate-path/-/d3-interpolate-path-2.2.1.tgz", + "integrity": "sha512-6qLLh/KJVzls0XtMsMpcxhqMhgVEN7VIbR/6YGZe2qlS8KDgyyVB20XcmGnDyB051HcefQXM/Tppa9vcANEA4Q==", + "license": "BSD-3-Clause" }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", "engines": { - "node": ">= 0.6" + "node": ">=12" } }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "node_modules/d3-random": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-2.2.2.tgz", + "integrity": "sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", "dependencies": { - "@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" - }, - "engines": { - "node": ">=10" + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" } }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=12" } }, - "node_modules/create-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", "dependencies": { - "color-convert": "^2.0.1" + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=12" } }, - "node_modules/create-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "d3-path": "1" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=12" } }, - "node_modules/create-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "d3-time": "1 - 3" }, "engines": { - "node": ">=7.0.0" + "node": ">=12" } }, - "node_modules/create-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/create-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/create-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" } }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, + "node_modules/d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" }, "engines": { - "node": ">= 8" + "node": ">=12" } }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true + "node_modules/d3/node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true + "node_modules/d3/node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, + "node_modules/d3/node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "dependencies": { - "cssom": "~0.3.6" + "d3-path": "^3.1.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -5516,18 +6877,6 @@ "node": ">=0.10.0" } }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -5562,6 +6911,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -6179,6 +7537,17 @@ "eslint": ">=5.0.0" } }, + "node_modules/eslint-plugin-tsdoc": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.4.0.tgz", + "integrity": "sha512-MT/8b4aKLdDClnS8mP3R/JNjg29i0Oyqd/0ym6NnQf+gfKbJJ4ZcSh2Bs1H0YiUMTBwww5JwXGTWot/RwyJ7aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.15.1", + "@microsoft/tsdoc-config": "0.17.1" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -6418,6 +7787,7 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "peer": true, "engines": { "node": ">=0.8.x" } @@ -6470,20 +7840,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6547,30 +7903,6 @@ "bser": "2.1.1" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -7077,10 +8409,11 @@ } }, "node_modules/headers-polyfill": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.2.5.tgz", - "integrity": "sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA==", - "dev": true + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", + "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", + "dev": true, + "license": "MIT" }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", @@ -7150,12 +8483,12 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -7166,26 +8499,6 @@ "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -7280,155 +8593,59 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "dependencies": { + "p-limit": "^2.2.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "find-up": "^4.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } }, - "node_modules/inquirer/node_modules/has-flag": { + "node_modules/indent-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "once": "^1.3.0", + "wrappy": "1" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -7443,6 +8660,15 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -7516,18 +8742,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -7663,15 +8877,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -7841,18 +9046,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -9891,6 +11084,13 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, "node_modules/jotai": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.7.1.tgz", @@ -9935,15 +11135,6 @@ "react": ">=17.0.0" } }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10169,6 +11360,11 @@ "node": ">=6" } }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -10244,92 +11440,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -10427,6 +11537,12 @@ "tmpl": "1.0.5" } }, + "node_modules/math-expression-evaluator": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.4.0.tgz", + "integrity": "sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==", + "license": "MIT" + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -10521,145 +11637,85 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mitt": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz", + "integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "node_modules/msw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/msw/-/msw-1.3.3.tgz", - "integrity": "sha512-CiPyRFiYJCXYyH/vwxT7m+sa4VZHuUH6cGwRBj0kaTjBGpsk4EnL47YzhoA859htVCF2vzqZuOsomIUlFqg9GQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@mswjs/cookies": "^0.2.2", - "@mswjs/interceptors": "^0.17.10", - "@open-draft/until": "^1.0.3", - "@types/cookie": "^0.4.1", - "@types/js-levenshtein": "^1.1.1", - "chalk": "^4.1.1", - "chokidar": "^3.4.2", - "cookie": "^0.4.2", - "graphql": "^16.8.1", - "headers-polyfill": "3.2.5", - "inquirer": "^8.2.0", - "is-node-process": "^1.2.0", - "js-levenshtein": "^1.1.6", - "node-fetch": "^2.6.7", - "outvariant": "^1.4.0", - "path-to-regexp": "^6.2.0", - "strict-event-emitter": "^0.4.3", - "type-fest": "^2.19.0", - "yargs": "^17.3.1" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.4.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/msw/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/msw/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/msw/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/msw/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/msw/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/msw/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + }, + "node_modules/msw": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.8.5.tgz", + "integrity": "sha512-uSp82wwBjOBV+VIt4rtUgwrbNFCobZICSd2iexS4IMIwFxDexSojiwnrZF3TK6yxxUt1PBHZdsfOwuI9JzWphA==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@bundled-es-modules/cookie": "^2.0.1", + "@bundled-es-modules/statuses": "^1.0.1", + "@bundled-es-modules/tough-cookie": "^0.1.6", + "@inquirer/confirm": "^5.0.0", + "@mswjs/interceptors": "^0.38.7", + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.6.0", + "@types/statuses": "^2.0.4", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "path-to-regexp": "^6.3.0", + "picocolors": "^1.1.1", + "strict-event-emitter": "^0.5.1", + "type-fest": "^4.26.1", + "yargs": "^17.7.2" + }, + "bin": { + "msw": "cli/index.js" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.8.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/msw/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=12.20" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, "node_modules/nanoid": { "version": "3.3.7", @@ -10692,47 +11748,17 @@ "dev": true, "peer": true }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "node_modules/newick": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/newick/-/newick-2.0.0.tgz", + "integrity": "sha512-WzIBgGkSUxoOx9pjZq4YhdcflCZqL50PJAXl46hrnrgGdkV4gB0B7//6Zy9pIRb0BnJly5cUFQqRG9sKgnZkkg==", + "license": "ISC" }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } + "node_modules/newick-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/newick-js/-/newick-js-1.2.1.tgz", + "integrity": "sha512-qyZVNtlXmORBf2w9vg2S/5N5mQlU46xDFdPX7SEDZTeSElafNQUelNzR7HWSKcVOpjXiDnBqkvjd5RlEG7/SEA==", + "license": "MIT" }, "node_modules/node-int64": { "version": "0.4.0", @@ -10936,113 +11962,12 @@ "node": ">= 0.8.0" } }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/outvariant": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.2.tgz", - "integrity": "sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==", - "dev": true + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "dev": true, + "license": "MIT" }, "node_modules/p-limit": { "version": "3.1.0", @@ -11156,10 +12081,11 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", - "dev": true + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", @@ -11170,9 +12096,10 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -11495,9 +12422,10 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -11738,6 +12666,21 @@ "react-dom": ">=16.6.0" } }, + "node_modules/react-use-measure": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz", + "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/react-window": { "version": "1.8.10", "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz", @@ -11767,32 +12710,6 @@ "react": "*" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -11806,6 +12723,32 @@ "node": ">=8" } }, + "node_modules/reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + } + }, + "node_modules/reduce-css-calc/node_modules/balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==", + "license": "MIT" + }, + "node_modules/reduce-function-call": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", + "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", @@ -11949,19 +12892,6 @@ "node": ">=10" } }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -11987,6 +12917,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { "version": "3.29.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", @@ -12003,15 +12939,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -12035,14 +12962,11 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" }, "node_modules/safe-array-concat": { "version": "1.1.2", @@ -12080,7 +13004,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "peer": true }, "node_modules/safe-regex-test": { "version": "1.0.3", @@ -12102,8 +13027,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/saxes": { "version": "6.0.0", @@ -12197,12 +13121,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", - "dev": true - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -12373,6 +13291,16 @@ "node": ">=8" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -12386,19 +13314,11 @@ } }, "node_modules/strict-event-emitter": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz", - "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } + "license": "MIT" }, "node_modules/string-length": { "version": "4.0.2", @@ -12778,22 +13698,12 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" + "@popperjs/core": "^2.9.0" } }, "node_modules/tmpl": { @@ -12823,10 +13733,11 @@ } }, "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -13494,25 +14405,6 @@ } } }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, "node_modules/v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", @@ -13666,27 +14558,6 @@ "node": ">=10.13.0" } }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/web-encoding": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", - "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", - "dev": true, - "dependencies": { - "util": "^0.12.3" - }, - "optionalDependencies": { - "@zxing/text-encoding": "0.9.0" - } - }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -13809,18 +14680,6 @@ "node": ">=12" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/whatwg-mimetype": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", @@ -13942,6 +14801,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -13956,6 +14816,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13971,6 +14832,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13982,7 +14844,8 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/wrappy": { "version": "1.0.2", @@ -14100,6 +14963,19 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 19e237d9..6b366664 100644 --- a/package.json +++ b/package.json @@ -26,33 +26,48 @@ "@mui/lab": "^5.0.0-alpha.170", "@mui/material": "^5.14.11", "@mui/x-data-grid": "^6.15.0", - "@vis.gl/react-google-maps": "^1.0.1", "@mui/x-tree-view": "^7.5.1", "@popperjs/core": "^2.11.8", + "@types/cytoscape": "^3.21.5", + "@types/d3-hierarchy": "^3.1.7", + "@types/d3-scale": "^4.0.8", + "@types/d3-selection": "^3.0.11", "@types/react-router-dom": "^5.3.3", + "@vis.gl/react-google-maps": "^1.5.1", + "@visx/visx": "^3.11.0", "axios": "^1.5.1", "color2k": "^2.0.2", + "cytoscape": "^3.30.1", + "cytoscape-automove": "^1.10.3", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-navigator": "^2.0.2", + "cytoscape-popper": "^4.0.0", + "d3": "^7.9.0", "dompurify": "^3.0.6", "flexlayout-react": "^0.7.11", "idb": "^7.1.1", "jotai": "^2.4.3", "lodash": "^4.17.21", - "react": "^18.2.0", + "newick": "^2.0.0", + "newick-js": "^1.2.1", + "react": "^18.3.1", "react-dom": "^18.2.0", "react-router-dom": "^6.16.0", - "react-window": "^1.8.9" + "react-window": "^1.8.9", + "tippy.js": "^6.3.7" }, "devDependencies": { "@eslint/js": "^9.3.0", "@testing-library/jest-dom": "^6.1.3", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.1", + "@types/d3": "^7.4.3", "@types/dompurify": "^3.0.3", "@types/google-map-react": "^2.1.10", "@types/jest": "^29.5.5", "@types/lodash": "^4.14.199", - "@types/react": "^18.2.23", - "@types/react-dom": "^18.2.8", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@types/react-window": "^1.8.6", "@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/parser": "^6.0.0", @@ -66,11 +81,12 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-tsdoc": "^0.4.0", "globals": "^15.2.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "jotai-devtools": "^0.7.0", - "msw": "^1.3.1", + "msw": "^2.6.5", "prettier": "3.1.0", "react-draggable": "^4.4.6", "react-transition-group": "^4.4.5", @@ -84,4 +100,4 @@ "vite-plugin-eslint": "^1.8.1", "vite-tsconfig-paths": "^4.2.1" } -} \ No newline at end of file +} diff --git a/thumbnails/legendAIV.png b/thumbnails/legendAIV.png new file mode 100644 index 00000000..4d9a3e1c Binary files /dev/null and b/thumbnails/legendAIV.png differ