From 5ff16c5409e9fa1d13653d39e4422b3008a1199c Mon Sep 17 00:00:00 2001 From: Dave MacFarlane Date: Mon, 11 Dec 2023 11:26:35 -0500 Subject: [PATCH] [dataquery] New Data Query Module (#8907) This implements a completely new, CouchDB free data query module based on the LORIS data query framework and the API introduced in PR#8268. In the new module, all queries that are run by the user are saved into a history. The user can star or name a query in order to make it easier to find, rather than having to decide ahead of time that they want to save or share a query. Admins can pin queries (either to the top of the module or to the LORIS dashboard). The UI is also (generally) simplified and more context-sensitive. The "define filters" tab should be easier to understand. The view data tab has a new view where candidates are rows, fields are columns, and session-scoped variables are displayed inline in the cell in a table. Permissions are enforced for modules, candidates, and sessions. --- Makefile | 3 + SQL/0000-00-02-Permission.sql | 3 +- .../2023-12-02-DQT-AdminPermission.sql | 6 + jsx/DataTable.d.ts | 70 + jsx/DataTable.js | 19 +- jsx/Panel.d.ts | 53 + modules/dataquery/jsx/calcpayload.tsx | 51 + .../jsx/components/expansionpanels.tsx | 37 + .../jsx/components/filterableselectgroup.tsx | 90 + modules/dataquery/jsx/criteriaterm.tsx | 167 + modules/dataquery/jsx/definefields.tsx | 615 ++ .../jsx/definefilters.addfiltermodal.tsx | 445 + .../jsx/definefilters.importcsvmodal.tsx | 208 + modules/dataquery/jsx/definefilters.tsx | 400 + modules/dataquery/jsx/fielddisplay.tsx | 44 + .../jsx/getdictionarydescription.tsx | 29 + .../dataquery/jsx/hooks/usebreadcrumbs.tsx | 96 + .../dataquery/jsx/hooks/usedatadictionary.tsx | 105 + modules/dataquery/jsx/hooks/usequery.tsx | 328 + .../dataquery/jsx/hooks/usesharedqueries.tsx | 416 + modules/dataquery/jsx/hooks/usevisits.tsx | 51 + modules/dataquery/jsx/index.tsx | 261 + modules/dataquery/jsx/nextsteps.tsx | 163 + modules/dataquery/jsx/querydef.tsx | 89 + modules/dataquery/jsx/querytree.tsx | 285 + modules/dataquery/jsx/types.tsx | 118 + modules/dataquery/jsx/viewdata.tsx | 970 ++ .../dataquery/jsx/welcome.adminquerymodal.tsx | 95 + .../dataquery/jsx/welcome.namequerymodal.tsx | 65 + modules/dataquery/jsx/welcome.tsx | 1116 +++ modules/dataquery/php/dataquery.class.inc | 63 + modules/dataquery/php/module.class.inc | 76 + .../php/provisioners/alluserqueries.class.inc | 2 +- .../php/provisioners/starredqueries.class.inc | 61 + .../php/provisioners/studyqueries.class.inc | 52 + modules/dataquery/php/query.class.inc | 2 +- modules/dataquery/php/visitlist.class.inc | 94 + modules/dataquery/templates/starredwidget.tpl | 15 + .../templates/studyquerieswidget.tpl | 42 + .../php/instrumentqueryengine.class.inc | 20 +- package-lock.json | 8385 +---------------- package.json | 5 +- php/libraries/NDB_BVL_Instrument.class.inc | 4 +- smarty/templates/main.tpl | 6 +- webpack.config.js | 1 + 45 files changed, 7014 insertions(+), 8212 deletions(-) create mode 100644 SQL/New_patches/2023-12-02-DQT-AdminPermission.sql create mode 100644 jsx/DataTable.d.ts create mode 100644 jsx/Panel.d.ts create mode 100644 modules/dataquery/jsx/calcpayload.tsx create mode 100644 modules/dataquery/jsx/components/expansionpanels.tsx create mode 100644 modules/dataquery/jsx/components/filterableselectgroup.tsx create mode 100644 modules/dataquery/jsx/criteriaterm.tsx create mode 100644 modules/dataquery/jsx/definefields.tsx create mode 100644 modules/dataquery/jsx/definefilters.addfiltermodal.tsx create mode 100644 modules/dataquery/jsx/definefilters.importcsvmodal.tsx create mode 100644 modules/dataquery/jsx/definefilters.tsx create mode 100644 modules/dataquery/jsx/fielddisplay.tsx create mode 100644 modules/dataquery/jsx/getdictionarydescription.tsx create mode 100644 modules/dataquery/jsx/hooks/usebreadcrumbs.tsx create mode 100644 modules/dataquery/jsx/hooks/usedatadictionary.tsx create mode 100644 modules/dataquery/jsx/hooks/usequery.tsx create mode 100644 modules/dataquery/jsx/hooks/usesharedqueries.tsx create mode 100644 modules/dataquery/jsx/hooks/usevisits.tsx create mode 100644 modules/dataquery/jsx/index.tsx create mode 100644 modules/dataquery/jsx/nextsteps.tsx create mode 100644 modules/dataquery/jsx/querydef.tsx create mode 100644 modules/dataquery/jsx/querytree.tsx create mode 100644 modules/dataquery/jsx/types.tsx create mode 100644 modules/dataquery/jsx/viewdata.tsx create mode 100644 modules/dataquery/jsx/welcome.adminquerymodal.tsx create mode 100644 modules/dataquery/jsx/welcome.namequerymodal.tsx create mode 100644 modules/dataquery/jsx/welcome.tsx create mode 100644 modules/dataquery/php/dataquery.class.inc create mode 100644 modules/dataquery/php/provisioners/starredqueries.class.inc create mode 100644 modules/dataquery/php/provisioners/studyqueries.class.inc create mode 100644 modules/dataquery/php/visitlist.class.inc create mode 100644 modules/dataquery/templates/starredwidget.tpl create mode 100644 modules/dataquery/templates/studyquerieswidget.tpl diff --git a/Makefile b/Makefile index 474fd56dc3d..5f33742acf2 100755 --- a/Makefile +++ b/Makefile @@ -62,6 +62,9 @@ data_release: instrument_manager: target=instrument_manager npm run compile +dataquery: + target=dataquery npm run compile + login: target=login npm run compile diff --git a/SQL/0000-00-02-Permission.sql b/SQL/0000-00-02-Permission.sql index 65eb207676f..fe9183fe6f6 100644 --- a/SQL/0000-00-02-Permission.sql +++ b/SQL/0000-00-02-Permission.sql @@ -131,7 +131,8 @@ INSERT INTO `permissions` VALUES (60,'behavioural_quality_control_view','Flagged Behavioural Entries',(SELECT ID FROM modules WHERE Name='behavioural_qc'),'View','2'), (61,'api_docs','API documentation',(SELECT ID FROM modules WHERE Name='api_docs'),'View','2'), (62,'electrophysiology_browser_edit_annotations','Annotations',(SELECT ID FROM modules WHERE Name='electrophysiology_browser'),'Create/Edit','2'), - (63,'monitor_eeg_uploads','Monitor EEG uploads',(SELECT ID FROM modules WHERE Name='electrophysiology_uploader'),NULL,'2'); + (63,'monitor_eeg_uploads','Monitor EEG uploads',(SELECT ID FROM modules WHERE Name='electrophysiology_uploader'),NULL,'2'), + (64,'dataquery_admin','Admin dataquery queries',(SELECT ID FROM modules WHERE Name='dataquery'),NULL,'2'); INSERT INTO `user_perm_rel` (userID, permID) SELECT u.ID, p.permID diff --git a/SQL/New_patches/2023-12-02-DQT-AdminPermission.sql b/SQL/New_patches/2023-12-02-DQT-AdminPermission.sql new file mode 100644 index 00000000000..243f2df4e2b --- /dev/null +++ b/SQL/New_patches/2023-12-02-DQT-AdminPermission.sql @@ -0,0 +1,6 @@ +INSERT INTO permissions (code, description, moduleID) + VALUES ( + 'dataquery_admin', + 'Dataquery Admin', + (SELECT ID FROM modules WHERE Name='dataquery') + ); diff --git a/jsx/DataTable.d.ts b/jsx/DataTable.d.ts new file mode 100644 index 00000000000..82c89b7b4e4 --- /dev/null +++ b/jsx/DataTable.d.ts @@ -0,0 +1,70 @@ +import {ReactNode} from 'react'; + +type TableRow = (string|null)[] + +type Field = { + show: boolean + label: string +} + +type hideOptions = { + rowsPerPage: boolean + downloadCSV: boolean + defaultColumn: boolean +} +type DataTableProps = { + data: TableRow[] + rowNumLabel?: string + getFormattedCell: (label: string, + data: string, + row: TableRow, + headers: string[], + fieldNo: number) => ReactNode + onSort?: () => void + hide?: hideOptions + fields: Field[] + nullTableShow?: boolean + noDynamicTable?: boolean + getMappedCell?: ( + label: string, + data: string|null, + row: TableRow, + headers: string[], + fieldNo: number) => string|(string|null)[]|null +} + +/** + * The DataTable class. See DataTable.js + */ +class DataTable { + props: DataTableProps + state: any + context: object + refs: {[key: string]: ReactInstance} + + /** + * Construct a new modal + */ + constructor(props: DataTableProps) + + /** + * React lifecycle method + * + * @returns {ReactNode} + */ + render(): ReactNode + + /** + * React lifecycle method + * + * @param {object} newstate - the state to overwrite + */ + setState(newstate: object): void + + /** + * React lifecycle method + */ + forceUpdate(): void +} + +export default DataTable; diff --git a/jsx/DataTable.js b/jsx/DataTable.js index 9ced01ee47d..be7f98c52a3 100644 --- a/jsx/DataTable.js +++ b/jsx/DataTable.js @@ -114,13 +114,22 @@ class DataTable extends Component { * * @param {number[]} filteredRowIndexes - The filtered Row Indexes */ + downloadCSV(filteredRowIndexes) { let csvData = filteredRowIndexes.map((id) => this.props.data[id]); // Map cell data to proper values if applicable. if (this.props.getMappedCell) { csvData = csvData .map((row, i) => this.props.fields - .map((field, j) => this.props.getMappedCell(field.label, row[j])) + .flatMap((field, j) => this.props.getMappedCell( + field.label, + row[j], + row, + this.props.fields.map( + (val) => val.label, + ), + j + )) ); } @@ -497,12 +506,18 @@ class DataTable extends Component { this.props.fields .forEach((field, k) => row[field.label] = rowData[k]); + const headers = this.props.fields.map( + (val) => val.label + ); + // Get custom cell formatting if available if (this.props.getFormattedCell) { cell = this.props.getFormattedCell( this.props.fields[j].label, celldata, - row + row, + headers, + j ); } else { cell = {celldata}; diff --git a/jsx/Panel.d.ts b/jsx/Panel.d.ts new file mode 100644 index 00000000000..5688f325ed9 --- /dev/null +++ b/jsx/Panel.d.ts @@ -0,0 +1,53 @@ +import {ReactNode} from 'react'; + +type PanelProps = { + initCollapsed?: boolean + collapsed?: boolean + parentId?: string + id?: string + height?: string + title?: string + class?: string + children: ReactNode + views?: object + collapsing?: boolean + bold?: boolean + panelSize?: string + style?: React.CSSProperties +} + +/** + * The Modal class. See Modal.js + */ +class Panel { + props: PanelProps + state: any + context: object + refs: {[key: string]: ReactInstance} + + /** + * Construct a new modal + */ + constructor(props: PanelProps) + + /** + * React lifecycle method + * + * @returns {ReactNode} + */ + render(): ReactNode + + /** + * React lifecycle method + * + * @param {object} newstate - the state to overwrite + */ + setState(newstate: object): void + + /** + * React lifecycle method + */ + forceUpdate(): void +} + +export default Panel; diff --git a/modules/dataquery/jsx/calcpayload.tsx b/modules/dataquery/jsx/calcpayload.tsx new file mode 100644 index 00000000000..0229cf71103 --- /dev/null +++ b/modules/dataquery/jsx/calcpayload.tsx @@ -0,0 +1,51 @@ +import {QueryTerm, QueryGroup} from './querydef'; +import { + APIQueryObject, + APIQueryField, + APIQueryGroupField, + APIQueryCriteriaGroup, +} from './types'; +/** + * Calculates the payload to submit to the search endpoint + * to run the query. + * + * @param {APIQueryField[]} fields - the fields to query + * @param {QueryGroup} filters - the root of the filters + * @returns {APIQueryObject} - The query to send to the API + */ +export function calcPayload( + fields: APIQueryField[], + filters: QueryGroup +): APIQueryObject { + const payload: APIQueryObject = { + type: 'candidates', + fields: fields.map((val: APIQueryField) => { + const fieldpayload: APIQueryField = { + module: val.module, + category: val.category, + field: val.field, + }; + if (val.visits) { + fieldpayload.visits = val.visits; + } + return fieldpayload; + }, + ), + }; + if (filters.group.length > 0) { + payload.criteria = { + operator: filters.operator, + group: filters.group.map( (val) => { + if (val instanceof QueryTerm) { + return val as APIQueryGroupField; + } else if (val instanceof QueryGroup) { + return val as APIQueryCriteriaGroup; + } else { + throw new Error('Invalid query'); + } + }), + }; + } + return payload; +} + diff --git a/modules/dataquery/jsx/components/expansionpanels.tsx b/modules/dataquery/jsx/components/expansionpanels.tsx new file mode 100644 index 00000000000..c8a5510fa73 --- /dev/null +++ b/modules/dataquery/jsx/components/expansionpanels.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import Panel from 'jsx/Panel'; + +/** + * Render a series of expansion panels + * + * @param {object} props - React props + * @param {boolean?} props.alwaysOpen - If true, panels can not be toggled + * @param {object} props.panels - Array of individual panels + * @returns {React.ReactElement} - The panels + */ +const ExpansionPanels = (props: { + alwaysOpen?: boolean, + panels: { + title: string, + content: React.ReactElement, + defaultOpen?: boolean, + alwaysOpen: boolean, + }[] +}) => { + return ( +
+ { props.panels.map((panel, index) => ( + + {panel.content} + + ))} +
+ ); +}; + +export default ExpansionPanels; diff --git a/modules/dataquery/jsx/components/filterableselectgroup.tsx b/modules/dataquery/jsx/components/filterableselectgroup.tsx new file mode 100644 index 00000000000..6ef42e2015d --- /dev/null +++ b/modules/dataquery/jsx/components/filterableselectgroup.tsx @@ -0,0 +1,90 @@ +import Select, {SingleValue} from 'react-select'; + +type SelectOption = { + label: string, + value: string, + module: string, +}; + +type SelectGroup = { + label: string, + options: SelectOption[], +}; +/** + * Render a select with option groups that can be + * filtered + * + * @param {object} props - react props + * @param {function} props.onChange - Callback on selection change + * @param {string?} props.placeholder - An optional placeholder value when no elements are selected + * @param {object} props.groups - Groups to select the dropdown into + * @param {function} props.mapGroupName - A mapper from backend to frontend name for groups + * @returns {React.ReactElement} - The element + */ +function FilterableSelectGroup(props: { + onChange: (module: string, value: string) => void, + placeholder?: string, + groups: object, + mapGroupName?: (module: string) => string, +}) { + const groups: SelectGroup[] = []; + const placeholder = props.placeholder || 'Select a category'; + for (const [module, subcategories] + of Object.entries(props.groups)) { + const options: SelectOption[] = []; + for (const [value, desc] + of Object.entries(subcategories) as unknown as [string, string]) { + options.push({ + value: value, + label: desc, + module: module, + }); + } + + let label = module; + if (props.mapGroupName) { + label = props.mapGroupName(module); + } + groups.push({ + label: label, + options: options, + }); + } + + /** + * Callback to call when the selection changes. + * + * @param {object} e - The click event callback + * @param {string} e.module - The module + * @param {string} e.value - The value + * @returns {void} + */ + const selected = (e: SingleValue) => { + // The callback should be (e: SelectOption) but typescript + // is convinced that it's a SingleValue. + // console.log(e) confirms that it has the same structure + // as SelectOption, so just convert it and explicitly + // cast it unsafely to make the compiler happy. + const val: SelectOption = e as unknown as SelectOption; + props.onChange(val.module, val.value); + }; + return ( +
+ { + return {value: visit, label: visit}; + }) + } + isMulti + onChange={selected} + placeholder='Select Visits' + value={selectedVisits.map( (visit: string): VisitOption => { + return {value: visit, label: visit}; + }) + } + menuPortalTarget={document.body} + styles={ + {menuPortal: + /** + * Adds appropriate zIndex to the react select's base CSS + * + * @param {object} base - The current CSS + * @returns {object} New CSS with z-index added + */ + (base) => ({...base, zIndex: 9999}), + } + } + closeMenuOnSelect={false} + /> +
; + } + } + const download = value.type == 'URI' ? + : null; + return ( +
props.onFieldToggle( + props.module, + props.category, + item, + selectedVisits, + )}> +
+
{item}
+
{value.description} {download}
+
+ {visits} +
); +} + +/** + * Render the define fields tab + * + * @param {object} props - React props + * @param {APIQueryField[]} props.selected - The currently selected fields + * @param {function} props.setSelected - Function to set the currently selected fields + * @param {function} props.onCategoryChange - Callback when the selected category changes + * @param {function} props.onFieldToggle - Callback when an item is clicked in the field list + * @param {function} props.onChangeVisitList - Callback when the visits are changed for a field + * @param {function} props.onChangeDefaultVisits - Callback when the default visits are changed + * @param {function} props.onAddAll - Callback when the "Add All" button is clicked + * @param {function} props.onRemoveAll - Callback when the "Remove All" button is clicked + * @param {function} props.onClearAll - Callback when the "Clear All" button is clicked + * @param {string} props.module - The module of the currently selected category + * @param {string} props.category - The currently selected category + * @param {FullDictionary} props.fulldictionary - The dictionary of all elements + * @param {function} props.removeField - callback to remove a single field + * @param {string[]} props.defaultVisits - The default visits + * @param {DictionaryCategory} props.displayedFields - The category currently selected to display + * @param {CategoriesAPIReturn} props.allCategories - all categories that exist + * @param {string[]} props.allVisits - All (non-phantom) visits for this LORIS instance + * @returns {React.ReactElement} - The Define Fields page + */ +function DefineFields(props: { + selected: APIQueryField[], + onCategoryChange: (module: string, category: string) => void, + setSelected: (newselected: APIQueryField[]) => void, + fulldictionary: FullDictionary, + displayedFields: DictionaryCategory, + removeField: (module: string, item: string, field: string) => void, + onClearAll: () => void, + defaultVisits: string[], + allCategories: CategoriesAPIReturn, + allVisits: string[], + onChangeDefaultVisits: (newvisits: readonly VisitOption[]) => void, + module: string, + category: string, + onRemoveAll: (removeelements: APIQueryField[]) => void, + onAddAll: (elements: APIQueryField[]) => void, + onChangeVisitList: ( + module: string, + category: string, + field: string, + visits: string[] + ) => void, + onFieldToggle: ( + module: string, + category: string, + field: string, + visits: string[] + ) => void, +}) { + const [activeFilter, setActiveFilter] = useState(''); + const [syncVisits, setSyncVisits] = useState(false); + const [zoomTo, setZoomTo] = useState(null); + useEffect(() => { + if (!syncVisits) { + return; + } + let modifiedvisits = false; + props.selected.forEach( (field: APIQueryField) => { + // Valid visits according to the dictionary + const category = props.fulldictionary[field.module][field.category]; + const dict = category[field.field]; + + if (dict.scope == 'candidate') { + return; + } + if (typeof dict.visits !== 'undefined') { + const newvisits = dict.visits.filter((visit) => { + return props.defaultVisits.includes(visit); + }); + field.visits = newvisits; + modifiedvisits = true; + } + }); + if (modifiedvisits) { + props.setSelected([...props.selected]); + } + }, [syncVisits, props.defaultVisits]); + const displayed: string[] = Object.keys( + props.displayedFields || {} + ).filter((value) => { + if (activeFilter === '') { + // No filter set + return true; + } + + // Filter with a case insensitive comparison to either the description or + // the field name displayed to the user + const lowerFilter = activeFilter.toLowerCase(); + const desc = props.displayedFields[value].description; + return (value.toLowerCase().includes(lowerFilter) + || desc.toLowerCase().includes(lowerFilter)); + }); + + const fields = displayed.map((item: string) => { + /** + * Return true if this element equals + * the selected. + * + * @param {APIQueryField} element - The element + * @returns {boolean} - true if equal + */ + const equalField = (element: APIQueryField) => { + return (element.module == props.module + && element.category === props.category + && element.field == item); + }; + const selobj = props.selected.find(equalField); + return setZoomTo(null)} + key={item} + item={item} + value={props.displayedFields[item]} + selected={selobj} + module={props.module} + category={props.category} + onFieldToggle={props.onFieldToggle} + onChangeVisitList={props.onChangeVisitList} + defaultVisits={props.defaultVisits} + />; + }); + + /** + * Set the filter that is being applied to displayed fields + * + * @param {React.ChangeEventHandler} e - The mouse event + */ + const setFilter = (e: React.FormEvent) => { + const target = e.target as HTMLInputElement; + setActiveFilter(target.value); + }; + + /** + * Add all items from the selected category to selected fields + * + * @returns {void} + */ + const addAll = () => { + const toAdd = displayed.map((item) => { + const dict = props.displayedFields[item]; + const retObj: APIQueryField = { + module: props.module, + category: props.category, + field: item, + }; + // Only include defined visits which intersect + // with the default ones, convert to the react-select + // format used internally. + if (dict.visits) { + retObj['visits'] = dict.visits.filter((visit) => { + return props.defaultVisits.includes(visit); + }); + } + return retObj; + }); + props.onAddAll(toAdd); + }; + /** + * Removes all items from the currently selected category + * + * @returns {void} + */ + const removeAll = () => { + const toRemove = displayed.map((item) => { + const dict = props.displayedFields[item]; + return { + module: props.module, + category: props.category, + field: item, + dictionary: dict, + }; + }); + props.onRemoveAll(toRemove); + }; + + let fieldList: React.ReactElement|null = null; + if (props.category) { + // Put into a short variable name for line length + const mCategories = props.allCategories.categories[props.module]; + const cname = mCategories[props.category]; + let defaultVisits; + if (props.defaultVisits) { + const allVisits = props.allVisits.map((el) => { + return {value: el, label: el}; + }); + const selectedVisits = props.defaultVisits.map((el) => { + return {value: el, label: el}; + }); + defaultVisits =
+

Default Visits

+ + + + +
+
+ + +
+ + +
{fields}
+ ); + } + + return ( +
+
+
+

Available Fields

+ props.allCategories.modules[key]} + onChange={props.onCategoryChange} + /> + {fieldList} +
+
+
+
+

Selected Fields

+
+ +
+
+ { + setZoomTo(item); + props.onCategoryChange(module, category); + }} + /> +
+
+
+
); +} + +/** + * Render the selected fields + * + * @param {object} props - React props + * @param {FullDictionary} props.fulldictionary - The fully loaded data dictionary for known modules + * @param {function} props.snapToView - Function which will snap the item to the viewport, changing pages if necessary + * @param {function} props.removeField - Remove a field from selected fields + * @param {APIQueryField[]} props.selected - The currently selected fields + * @param {function} props.setSelected - Function to set the currently selected fields + * @returns {React.ReactElement} - The selected field list + */ +function SelectedFieldList(props: { + fulldictionary: FullDictionary, + snapToView: (module: string, item: string, field: string) => void, + removeField: (module: string, item: string, field: string) => void, + selected: APIQueryField[], + setSelected: (newselected: APIQueryField[]) => void, +}) { + const [removingIdx, setRemovingIdx] = useState(null); + + const [draggingIdx, setDraggingIdx] = useState(null); + const [droppingIdx, setDroppingIdx] = useState(null); + + /** + * Move the currently selected item from draggingIdx to + * droppingIdx. + * + * @returns {void} + */ + const moveSelected = () => { + if (draggingIdx=== null || droppingIdx === null) { + return; + } + const newSelected: APIQueryField[] = props.selected; + + const removed: APIQueryField = newSelected.splice(draggingIdx, 1)[0]; + const newIdx: number|null = (droppingIdx||0 <= draggingIdx||0) + ? droppingIdx + : (droppingIdx - 1); + + if (newIdx == null) { + return; + } + newSelected.splice( + newIdx, + 0, + removed, + ); + props.setSelected([...newSelected]); + setDroppingIdx(null); + setDraggingIdx(null); + }; + + const fields = props.selected.map((item, i) => { + /** + * Removes an item from the selected + * + * @param {APIQueryField} item - The field to remove + * @returns {void} + */ + const removeField = (item: APIQueryField) => { + props.removeField(item.module, item.category, item.field); + }; + const style: React.CSSProperties = {display: 'flex', + flexWrap: 'nowrap' as const, + cursor: 'grab', + justifyContent: 'space-between'}; + if (removingIdx === i) { + style.textDecoration = 'line-through' as const; + } + if (droppingIdx === i) { + style.borderTop = 'thin solid black'; + } + if (draggingIdx == i) { + style.background = '#f5f5f5'; + } + let fieldvisits; + if (item.visits) { + const style = { + fontStyle: 'italic', + color: '#aaa', + fontSize: '0.7em', + marginLeft: 20, + }; + fieldvisits =
{item.visits.join(', ')}
; + } + return (
{ + props.snapToView(item.module, item.category, item.field); + }} + onDragStart={() => { + setDraggingIdx(i); + }} + + onDragEnd={() => { + setDraggingIdx(null); + setDroppingIdx(null); + }} + + onDragEnter={() => { + setDroppingIdx(i); + }} + + onDragOver ={(e) => { + e.stopPropagation(); + e.preventDefault(); + }} + onDrop={() => moveSelected()} + > +
+
{item.field}
+
{getDictionaryDescription( + item.module, + item.category, + item.field, + props.fulldictionary, + )}
+ {fieldvisits} +
+
setRemovingIdx(i)} + onMouseLeave={() => setRemovingIdx(null)}> + removeField(item)} + style={{cursor: 'pointer'}} /> +
+
); + }); + if (draggingIdx !== null) { + // Add a sink after the last element, so that we can drop on + // the end + const style: React.CSSProperties = {height: 50}; + const nItems = fields.length; + if (droppingIdx === nItems) { + style.borderTop = 'thin solid black' as const; + } + fields.push(
setDroppingIdx(nItems) } + onDragOver ={(e) => { + e.stopPropagation(); + e.preventDefault(); + }} + onDrop={() => moveSelected()}>  +
); + } + + return
{fields}
; +} + + +export default DefineFields; diff --git a/modules/dataquery/jsx/definefilters.addfiltermodal.tsx b/modules/dataquery/jsx/definefilters.addfiltermodal.tsx new file mode 100644 index 00000000000..b3f36f67541 --- /dev/null +++ b/modules/dataquery/jsx/definefilters.addfiltermodal.tsx @@ -0,0 +1,445 @@ +import {useState} from 'react'; +import FilterableSelectGroup from './components/filterableselectgroup'; +import Modal from 'jsx/Modal'; +import Select from 'react-select'; +import swal from 'sweetalert2'; +import { + NumericElement, + DateElement, + TimeElement, + SelectElement, + TextboxElement, +} from 'jsx/Form'; +import {QueryTerm, QueryGroup} from './querydef'; +import { + Operators, + FieldDictionary, + DictionaryCategory, + VisitOption, +} from './types'; +import {CategoriesAPIReturn} from './hooks/usedatadictionary'; + +/** + * Renders a selectable list of visits + * + * @param {object} props - React props + * @param {string[]} props.selected - The currently selected visits + * @param {string[]} props.options - The valid options + * @param {function} props.onChange - callback when the value selected changes + * @returns {React.ReactElement} - The visit list dropdown + */ +function VisitList(props: { + selected: string[], + options: string[], + onChange: (newvals: string[]) => void, +}) { + const selectOptions: VisitOption[] = props.options.map( + (vl) => { + return {value: vl, label: vl}; + } + ); + + const selectedVisits = selectOptions.filter((opt) => { + return props.selected.includes(opt.value); + }); + + return setCSVType('candidate')} + /> Candidates + setCSVType('session')} + /> Sessions + +
Candidate identifier type
+
setIdType('CandID')} + /> DCC ID + setIdType('PSCID')} + /> PSCID +
+
+ Does CSV contain a header line? +
+
setCSVHeader(true)} + /> Yes + setCSVHeader(false)} + /> No +
+
CSV File
+
{ + setCSVFile(file); + const papaparseConfig: + Papa.ParseConfig = { + skipEmptyLines: true, + complete: csvParsed, + // Setting this to try would cause + // papaparse to return an object + // instead of string. We just skip + // the first row if the user says + // they have a header when parsing + // results. + header: false, + }; + // Only 1 column, papaparse can't detect + // the delimiter if it's not explicitly + // specified. + if (csvType == 'candidate') { + papaparseConfig.delimiter = ','; + } + Papa.parse(file, papaparseConfig); + } + } + />
+ + + + + + ; +} + +export default ImportCSVModal; diff --git a/modules/dataquery/jsx/definefilters.tsx b/modules/dataquery/jsx/definefilters.tsx new file mode 100644 index 00000000000..3e97e519ab7 --- /dev/null +++ b/modules/dataquery/jsx/definefilters.tsx @@ -0,0 +1,400 @@ +import {useState, useEffect} from 'react'; +import {APIQueryField} from './types'; +import {QueryTerm, QueryGroup} from './querydef'; +import AddFilterModal from './definefilters.addfiltermodal'; +import ImportCSVModal from './definefilters.importcsvmodal'; +import QueryTree from './querytree'; +import {CriteriaTerm} from './criteriaterm'; +import InfoPanel from 'jsx/InfoPanel'; +import {ButtonElement} from 'jsx/Form'; +import {FullDictionary, DictionaryCategory} from './types'; +import {calcPayload} from './calcpayload'; +import {CategoriesAPIReturn} from './hooks/usedatadictionary'; +import React from 'react'; + +/** + * The define filters tab of the DQT + * + * @param {object} props - React props + * @param {APIQueryField[]} props.fields - The fields selected + * @param {QueryGroup} props.query - The criteria currently selected + * @param {function} props.setQuery - Sets the current criteria + * @param {CategoriesAPIReturn} props.categories - The list of categories displayed + * @param {DictionaryCategory} props.displayedFields - All fields from the currently selected category + * @param {string} props.module - The module of the currently selected module + * @param {string} props.category - The currently selected category + * @param {function} props.onCategoryChange - Callback to call when the category changes + * @param {FullDictionary} props.fulldictionary - The fully loaded dictionary + * @param {function} props.mapModuleName - Mapper from backend name to frontend name + * @param {function} props.mapCategoryName - Mapper from backend name to frontend name + * @param {function} props.getModuleFields - Function that will ensure a module's fields + * are fully populated in fulldictionary + * @param {function} props.addQueryGroupItem - Function that will add a new term to the + * existing QueryGroup + * @param {function} props.addNewQueryGroup - Function that will add a new QueryGroup subgroup + * to the existing QueryGroup + * @param {function} props.removeQueryGroupItem - Function that will remove an item from a + * QueryGroup by index. + * @returns {React.ReactElement} - The Define Filters page + */ +function DefineFilters(props: { + fields: APIQueryField[], + query: QueryGroup, + categories: CategoriesAPIReturn, + setQuery: (newcriteria: QueryGroup) => void, + + module: string, + category: string, + + displayedFields: DictionaryCategory, // fields from currently selected category + onCategoryChange: (module: string, category: string) => void, + fulldictionary: FullDictionary, + mapModuleName: (module: string) => string, + mapCategoryName: (module: string, category: string) => string, + getModuleFields: (module: string) => void, + + addQueryGroupItem: ( + querygroup: QueryGroup, + condition: QueryTerm + ) => QueryGroup, + addNewQueryGroup: (group: QueryGroup) => void, + removeQueryGroupItem: (group: QueryGroup, i: number) => QueryGroup, +}) : React.ReactElement { + let displayquery: React.ReactNode = null; + const [addModal, setAddModal] = useState(false); + const [csvModal, setCSVModal] = useState(false); + const [showAdvanced, setShowAdvanced] = useState(false); + // The subgroup used for the "Add Filter" modal window + // to add to. Default to top level unless click from a + // query group, in which case the callback changes it + // to that group. + const [modalQueryGroup, setModalGroup] = useState(props.query); + const [deleteItemIndex, setDeleteItemIndex] = useState(null); + const [queryMatches, setQueryMatches] = useState(null); + useEffect(() => { + setQueryMatches(null); + const payload = calcPayload(props.fields, props.query); + fetch( + '/dataquery/queries', + { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify(payload), + }, + ).then( + (resp) => { + if (!resp.ok) { + throw new Error('Error creating query.'); + } + return resp.json(); + } + ).then( + (data) => { + fetch( + '/dataquery/queries/' + + data.QueryID + '/count', + { + method: 'GET', + credentials: 'same-origin', + } + ).then((resp) => { + if (!resp.ok) { + throw new Error('Could not get count.'); + } + return resp.json(); + }).then((result) => { + setQueryMatches(result.count); + }); + } + ); + }, [props.fields, props.query]); + + const bGroupStyle = { + display: 'flex' as const, + flexWrap: 'wrap' as const, + marginTop: '1ex', + }; + + const mapModuleName = props.mapModuleName; + const mapCategoryName = props.mapCategoryName; + + const advancedLabel = showAdvanced ? 'Hide Advanced' : 'Show Advanced'; + let advancedButtons; + const toggleAdvancedButton = ( +
+
+ { + e.preventDefault(); + setShowAdvanced(!showAdvanced); + }} + /> +
+
+ ); + if (props.query.group.length == 0) { + if (showAdvanced) { + advancedButtons = ( +
+

The "nested groups" options are advanced options for queries + that do not have any specific condition at the + base of the query. + Use Add nested "or" condition groups if + you need to build a query of the form. + (a or b) and (c or d) [or (e and f)..]. +

+
+ { + e.preventDefault(); + props.query.operator = 'and'; + props.addNewQueryGroup(props.query); + }} + /> +
+

+ Use Add nested "and" condition groups if you + need to build a query of the form + (a and b) or (c and d) [or (e and f)..]. +

+
+ { + e.preventDefault(); + props.query.operator = 'or'; + props.addNewQueryGroup(props.query); + }} + /> +
+
+ ); + } + // Only 1 add condition button since "and" or "or" + // are the same with only 1 term + displayquery =
+
+

Currently querying for ALL candidates.

+

You can add conditions by clicking one of the buttons below.

+

Click Add Condition to add one or more conditions + to your filters (ie. "Date Of Birth < 2015-02-15"). This is + most likely where you want to start your filters. +

+

You can also import a population from a CSV by clicking + the Import from CSV button.

+

The advanced options are for queries that do not have + a condition to add at the base of the query.

+
+
+
+
+
+ { + e.preventDefault(); + setAddModal(true); + }} + /> +
+
+ { + e.preventDefault(); + // Need to be sure that we've loaded + // candidate_parameters so it's in + // fulldictionary + props.getModuleFields( + 'candidate_parameters', + ); + setCSVModal(true); + }} + /> +
+
+ {toggleAdvancedButton} + {advancedButtons} +
+
+
; + } else if (props.query.group.length == 1 && + props.query.group[0] instanceof QueryTerm + ) { + if (showAdvanced) { + advancedButtons = ( +
+
+

Use New "and" subgroup if the rest of the + query you need to write is a subgroup consisting + of "and" conditions. ie your query is of the form: +

+ (your condition above) or (c and d [and e and f..]) +
+

+ { + e.preventDefault(); + props.query.operator = 'or'; + props.addNewQueryGroup(props.query); + }} /> +

Use New "or" subgroup if the rest of the + query you need to write is a subgroup consisting + of "or" conditions. ie your query is of the form: +

+ (your condition above) and (c or d [or e or f..]) +
+

+ { + e.preventDefault(); + props.query.operator = 'and'; + props.addNewQueryGroup(props.query); + }} /> +
+
+ ); + } + // buttons for 1. Add "and" condition 2. Add "or" condition + displayquery = (
+

Currently querying for any candidates with:

+ +
+
+
+ +
{ + const newquery = props.removeQueryGroupItem( + props.query, + 0 + ); + setModalGroup(newquery); + }} + onMouseEnter={() => setDeleteItemIndex(0)} + onMouseLeave={() => setDeleteItemIndex(null)} + style={{cursor: 'pointer'}} /> +
+
+
+
+ { + e.preventDefault(); + props.query.operator = 'and'; + setAddModal(true); + }} /> + { + e.preventDefault(); + setAddModal(true); + props.query.operator = 'or'; + }} /> +
+
+ {toggleAdvancedButton} + {advancedButtons} +
+ +
); + } else { + // Add buttons are delegated to the QueryTree rendering so they + // can be placed at the right level + displayquery =
+

Currently querying for any candidates with:

+
+
+ { + setModalGroup(group); + setAddModal(true); + }} + setModalGroup={setModalGroup} + backgroundColour='rgb(240, 240, 240)' + newGroup={props.addNewQueryGroup} + fulldictionary={props.fulldictionary} + /> +
+
+
; + } + const modal = addModal ? ( + setAddModal(false)} + addQueryGroupItem={(querygroup, condition) => { + const newquery = props.addQueryGroupItem( + querygroup, + condition, + ); + setModalGroup(newquery); + }} + categories={props.categories} + onCategoryChange={props.onCategoryChange} + displayedFields={props.displayedFields} + + module={props.module} + category={props.category} + />) + : ''; + const csvModalHTML = csvModal ? ( + setCSVModal(false)} + /> + ) : ''; + + const matchCount = queryMatches === null + ?
 
// So the header doesn't jump around + :
Query matches {queryMatches} candidates
; + return (
+ {modal} + {csvModalHTML} +
+

Current Query

+ {matchCount} +
+ + Note that only candidates which you have permission to + access in LORIS are included in results. Number of + results may vary from other users running the same query. + + {displayquery} +
+ ); +} + +export default DefineFilters; diff --git a/modules/dataquery/jsx/fielddisplay.tsx b/modules/dataquery/jsx/fielddisplay.tsx new file mode 100644 index 00000000000..13b94664899 --- /dev/null +++ b/modules/dataquery/jsx/fielddisplay.tsx @@ -0,0 +1,44 @@ +import {FullDictionary} from './types'; + +import getDictionaryDescription from './getdictionarydescription'; + +/** + * A single field to display + * + * @param {object} props - React props + * @param {string} props.module - The module with the field + * @param {string} props.category - The field's category + * @param {string} props.fieldname - The field's field name + * @param {FullDictionary} props.fulldictionary - The complete loaded dictionary + * @param {function} props.mapModuleName - Mapper from module backend to frontend name + * @param {function} props.mapCategoryName - Mapper from category backend to frontend name + * @returns {React.ReactElement} - the react element + */ +function FieldDisplay(props: { + module: string, + category: string, + fieldname: string, + + fulldictionary: FullDictionary, + mapModuleName: (module: string) => string, + mapCategoryName: (module: string, category: string) => string, +}) { + const description = getDictionaryDescription( + props.module, + props.category, + props.fieldname, + props.fulldictionary, + ); + + return (
+
+ {description} +
+
+ {props.mapCategoryName(props.module, props.category)} +  ({props.mapModuleName(props.module)}) +
+
+ ); +} +export default FieldDisplay; diff --git a/modules/dataquery/jsx/getdictionarydescription.tsx b/modules/dataquery/jsx/getdictionarydescription.tsx new file mode 100644 index 00000000000..02d5f9c32ed --- /dev/null +++ b/modules/dataquery/jsx/getdictionarydescription.tsx @@ -0,0 +1,29 @@ +import {FullDictionary} from './types'; + +/** + * Get the dictionary for a given term + * + * @param {string} module - the module + * @param {string} category - the category + * @param {string} fieldname - the field + * @param {FullDictionary} dict - all loaded dictionaries + * @returns {string} - the description if available, otherwise the fieldname + */ +function getDictionaryDescription( + module: string, + category: string, + fieldname: string, + dict: FullDictionary, +): string { + if (!dict + || !dict[module] + || !dict[module][category] + || !dict[module][category][fieldname] + ) { + return fieldname; + } + + return dict[module][category][fieldname].description; +} + +export default getDictionaryDescription; diff --git a/modules/dataquery/jsx/hooks/usebreadcrumbs.tsx b/modules/dataquery/jsx/hooks/usebreadcrumbs.tsx new file mode 100644 index 00000000000..a4a33b192a5 --- /dev/null +++ b/modules/dataquery/jsx/hooks/usebreadcrumbs.tsx @@ -0,0 +1,96 @@ +import React, {useEffect} from 'react'; +import Breadcrumbs from 'jsx/Breadcrumbs'; + +// Declared in smarty main.tpl +declare const breadcrumbsRoot: any; +declare const loris: any; + +/** + * Update the DQT breadcrumbs based on the active tab + * + * @param {string} activeTab - The active tab + * @param {function} setActiveTab - set the state on click + */ +function useBreadcrumbs( + activeTab: string, + setActiveTab: (newtab: string) => void +) { + // update breadcrumbs breadcrumbs + useEffect(() => { + const breadcrumbs = [ + { + text: 'Data Query Tool (Alpha)', + /** + * OnClick handler for the main breadcrumb + * + * @param {React.MouseEvent} e - Callback for when hovering over the delete icon + * @returns {void} + */ + onClick: (e: React.MouseEvent) => { + e.preventDefault(); + setActiveTab('Info'); + }, + }, + ]; + if (activeTab == 'DefineFields' + || activeTab == 'DefineFilters' + || activeTab == 'ViewData') { + breadcrumbs.push({ + text: 'Define Fields', + /** + * OnClick handler for the define fields breadcrumb + * + * @param {React.MouseEventHandler} e - Callback for when hovering over the delete icon + * @returns {void} + */ + onClick: (e) => { + e.preventDefault(); + setActiveTab('DefineFields'); + }, + }); + } + if (activeTab == 'DefineFilters' + || activeTab == 'ViewData') { + breadcrumbs.push({ + text: 'Define Filters', + /** + * OnClick handler for the define filters breadcrumb + * + * @param {React.MouseEventHandler} e - Callback for when hovering over the delete icon + * @returns {void} + */ + onClick: (e) => { + e.preventDefault(); + setActiveTab('DefineFilters'); + }, + }); + } + + if (activeTab == 'ViewData') { + breadcrumbs.push({ + text: 'View Data', + /** + * OnClick handler for the View Data breadcrumb + * + * @param {React.MouseEventHandler} e - Callback for when hovering over the delete icon + * @returns {void} + */ + onClick: (e) => { + e.preventDefault(); + setActiveTab('View Data'); + }, + }); + } + + if (breadcrumbsRoot) { + breadcrumbsRoot.render( + , + ); + } + }, [activeTab]); +} + +export default useBreadcrumbs; diff --git a/modules/dataquery/jsx/hooks/usedatadictionary.tsx b/modules/dataquery/jsx/hooks/usedatadictionary.tsx new file mode 100644 index 00000000000..bc94f750a60 --- /dev/null +++ b/modules/dataquery/jsx/hooks/usedatadictionary.tsx @@ -0,0 +1,105 @@ +import {useState, useEffect} from 'react'; + +import {ModuleDictionary, FullDictionary} from '../types'; + +interface ModuleList { + [backendname: string]: string; +} +interface CategoryList { + [backendname: string]: string; +} +interface ModuleCategories { + [modulename: string]: CategoryList; +} + +export type CategoriesAPIReturn = { + modules: ModuleList; + categories: ModuleCategories; +} +/** + * React hook to load categories from the server. + * + * @returns {CategoriesAPIReturn} - Categories returned by dictionary API + */ +function useCategories(): CategoriesAPIReturn|null { + const [categories, setCategories] = useState(null); + useEffect(() => { + if (categories !== null) { + return; + } + fetch('/dictionary/categories', {credentials: 'same-origin'}) + .then((resp) => { + if (!resp.ok) { + throw new Error('Invalid response'); + } + return resp.json(); + }).then((result) => { + setCategories(result); + } + ).catch( (error) => { + console.error(error); + }); + }, []); + return categories; +} + +type DataDictionaryReturnType = [ + FullDictionary, + (module: string) => Promise, +]; + +/** + * React hook to use a data dictionary loaded from a LORIS server. + * + * @returns {array} - The retrieved dictionary and a callback to populate a new module into it + */ +function useDataDictionary(): DataDictionaryReturnType { + const [fulldictionary, setDictionary] = useState({}); + // XXX: This should be {[module: string]: Promise} but then + // typescript says the key is always defined when we try and check if + // it's set, need to figure out the correct way to do that, for now just use any + const [pendingModules, setPendingModules] = useState({}); + + /** + * Fetch a module's dictionary and cache it into fulldictionary. + * + * @param {string} module - The module name to fetch the dictionary for + * @returns {Promise} - A promise that resolves to module's dictionary + */ + const fetchModuleDictionary = (module: string): Promise => { + if (fulldictionary[module]) { + const promise = Promise.resolve(fulldictionary[module]); + return promise; + } + if (pendingModules[module]) { + return pendingModules[module]; + } + const promise: Promise = new Promise( + (resolve, reject) => { + fetch('/dictionary/module/' + module, + {credentials: 'same-origin'} + ).then((resp) => { + if (!resp.ok) { + throw new Error('Invalid response'); + } + return resp.json(); + }).then((result) => { + fulldictionary[module] = result; + setDictionary({...fulldictionary}); + + resolve(result); + }).catch( (error) => { + console.error(error); + reject(error); + }); + } + ); + const newUsedModules = pendingModules; + newUsedModules[module] = promise; + setPendingModules(newUsedModules); + return promise; + }; + return [fulldictionary, fetchModuleDictionary]; +} + +export {useDataDictionary, useCategories}; diff --git a/modules/dataquery/jsx/hooks/usequery.tsx b/modules/dataquery/jsx/hooks/usequery.tsx new file mode 100644 index 00000000000..20a84bbe2c8 --- /dev/null +++ b/modules/dataquery/jsx/hooks/usequery.tsx @@ -0,0 +1,328 @@ +import {useState} from 'react'; +import {QueryGroup, QueryTerm} from '../querydef'; +import {APIQueryField} from '../types'; + +type FieldActions = { + clear: () => void, + remove: (module: string, category: string, field: string) => void, + modifyVisits: ( + module: string, + category: string, + field: string, + visits: string[] + ) => void, + removeMany: (removeelements: APIQueryField[]) => void, + addRemoveField: ( + module: string, + category: string, + field: string, + visits: string[] + ) => void, + addMany: (elements: APIQueryField[]) => void, + setFields: (fields: APIQueryField[]) => void, +} + +type useQueryReturnType = [ + QueryGroup, + (fields: APIQueryField[], filters: QueryGroup|null) => void, + APIQueryField[], + FieldActions, + { + addQueryGroupItem: ( + querygroup: QueryGroup, + condition: QueryTerm + ) => QueryGroup, + removeQueryGroupItem: ( + querygroup: QueryGroup, + idx: number + ) => QueryGroup, + addNewQueryGroup: (parentgroup: QueryGroup) => void, + setCriteria: (newcriteria: QueryGroup) => void, + }, +]; + +/** + * React hook to manage loading of queries. + * + * @returns {useQueryReturnType} - A veritable plethora of actions and values + */ +function useQuery(): useQueryReturnType { + const [fields, setFields] = useState([]); + const [criteria, setCriteria] = useState(new QueryGroup('and')); + + /** + * Add a term to the current QueryGroup + * + * @param {QueryGroup} querygroup - The group to add the term to + * @param {QueryTerm} condition - The term to add to the group + * @returns {QueryGroup} - The new QueryGroup + */ + const addQueryGroupItem = ( + querygroup: QueryGroup, + condition: QueryTerm, + ): QueryGroup => { + // clone the top level query to force + // a new rendering + const newquery = new QueryGroup(criteria.operator); + + // Add to this level of the tree + querygroup.addTerm(condition); + + + newquery.group = [...criteria.group]; + setCriteria(newquery); + return newquery; + }; + + /** + * Remove a given index from the current QueryGroup and return + * a new group. + * + * @param {QueryGroup} querygroup - The querygroup to remove an item from + * @param {number} idx - The index to remove + * @returns {QueryGroup} - the new QueryGroup + */ + const removeQueryGroupItem = ( + querygroup: QueryGroup, + idx: number + ): QueryGroup => { + // Remove from this level of the tree + querygroup.removeTerm(idx); + + // clone the top level query to force + // a new rendering + const newquery = new QueryGroup(criteria.operator); + + newquery.group = [...criteria.group]; + setCriteria(newquery); + + return newquery; + }; + + /** + * Add a new, empty query group to the end of a QueryGroup + * + * @param {QueryGroup} parentgroup - the group to get a new querygroup child + * @returns {void} + */ + const addNewQueryGroup = (parentgroup: QueryGroup): void => { + // Add to this level of the tree + parentgroup.addGroup(); + + // clone the top level query to force + // a new rendering + const newquery = new QueryGroup(criteria.operator); + newquery.group = [...criteria.group]; + + setCriteria(newquery); + }; + + /** + * Load a new query as the currently managed query by this hook. + * + * @param {APIQueryField[]} fields - The fields of the new query + * @param {QueryGroup} filters - The filters of the new query. + * @returns {void} + */ + const loadQuery = ( + fields: APIQueryField[], + filters: QueryGroup|null + ): void => { + setFields(fields); + if (!filters) { + setCriteria(new QueryGroup('and')); + } else { + setCriteria(filters); + } + }; + const fieldActions: FieldActions = { + /** + * Clear all fields from this query + * + * @returns {void} + */ + clear: function() { + setFields([]); + }, + /** + * Remove a field from this query + * + * @param {string} module - The module of the field to remove + * @param {string} category - The category of the field to remove + * @param {string} field - The field to remove + * @returns {void} + */ + remove: ( + module: string, + category: string, + field: string, + ): void => { + /** + * Returns true if an element in fields is equal to this field + * + * @param {APIQueryField} element - The element to compare + * @returns {boolean} - true if equal + */ + const equalField = (element: APIQueryField): boolean => { + return (element.module == module + && element.category === category + && element.field == field); + }; + const newfields = fields.filter((el) => !(equalField(el))); + setFields(newfields); + }, + /** + * Modify the visits for a selected field + * + * @param {string} module - The module of the field to modify + * @param {string} category - The category of the field to modify + * @param {string} field - The field to modify + * @param {string[]} visits - The new visits for the field + * @returns {void} + */ + modifyVisits: ( + module: string, + category: string, + field: string, + visits: string[] + ) => { + const newfields: APIQueryField[] = [...fields]; + + /** + * Returns true if an element in fields is equal to this field + * + * @param {APIQueryField} element - The element to compare + * @returns {boolean} - true if equal + */ + const equalField = (element: APIQueryField) => { + return (element.module == module + && element.category === category + && element.field == field); + }; + + for (let i = 0; i < newfields.length; i++) { + if (equalField(newfields[i])) { + newfields[i].visits = visits; + setFields(newfields); + return; + } + } + }, + /** + * Toggle whether a field is present by adding it if missing or removing it if + * present. + * + * @param {string} module - the module for the field + * @param {string} category - the category for the field + * @param {string} field - the field name + * @param {string[]} visits - the list of visits to add if adding + */ + addRemoveField: ( + module: string, + category: string, + field: string, + visits: string[] + ): void => { + const newFieldObj: APIQueryField = { + module: module, + category: category, + field: field, + visits: visits, + }; + /** + * Returns true if an element in fields is equal to this field + * + * @param {APIQueryField} element - The element to compare + * @returns {boolean} - true if equal + */ + const equalField = (element: APIQueryField) => { + return (element.module == module + && element.category === category + && element.field == field); + }; + if (fields.some(equalField)) { + // Remove + const newfields: APIQueryField[] = fields.filter( + (el) => !(equalField(el)) + ); + setFields(newfields); + } else { + // Add + const newfields: APIQueryField[] = [...fields, newFieldObj]; + setFields(newfields); + } + }, + /** + * Remove multiple elements from the current query + * + * @param {APIQueryField[]} removeelements - The elements to remove + * @returns {void} + */ + removeMany: (removeelements: APIQueryField[]): void => { + /** + * Returns true if el1 is equal to el2 + * + * @param {APIQueryField} el1 - The first element to compare + * @param {APIQueryField} el2 - The second element to compare + * @returns {boolean} - true if equal + */ + const equalField = ( + el1: APIQueryField, + el2: APIQueryField + ): boolean => { + return (el1.module == el2.module + && el1.category === el2.category + && el1.field == el2.field); + }; + const newfields = fields.filter((el) => { + if (removeelements.some((rel) => equalField(rel, el))) { + return false; + } + return true; + }); + setFields(newfields); + }, + /** + * Adds many fields to the selected query + * + * @param {APIQueryField[]} elements - the fields to add + * @returns {void} + */ + addMany: (elements: APIQueryField[]): void => { + let newfields = fields; + for (let i = 0; i < elements.length; i++) { + const newFieldObj = elements[i]; + /** + * Returns true if an element in fields is equal to this field + * + * @param {APIQueryField} element - The element to compare + * @returns {boolean} - true if equal + */ + const equalField = (element: APIQueryField) => { + return (element.module == newFieldObj.module + && element.category === newFieldObj.category + && element.field == newFieldObj.field); + }; + if (!newfields.some((el: APIQueryField) => equalField(el))) { + newfields = [...newfields, newFieldObj]; + } + } + setFields(newfields); + }, + setFields: setFields, + }; + return [ + criteria, + loadQuery, + fields, + fieldActions, + { + addQueryGroupItem: addQueryGroupItem, + removeQueryGroupItem: removeQueryGroupItem, + addNewQueryGroup: addNewQueryGroup, + setCriteria: setCriteria, + }, + ]; +} + +export default useQuery; diff --git a/modules/dataquery/jsx/hooks/usesharedqueries.tsx b/modules/dataquery/jsx/hooks/usesharedqueries.tsx new file mode 100644 index 00000000000..2ac2e1cba9e --- /dev/null +++ b/modules/dataquery/jsx/hooks/usesharedqueries.tsx @@ -0,0 +1,416 @@ +import {useState, useEffect} from 'react'; +import swal from 'sweetalert2'; +import {QueryTerm, QueryGroup} from '../querydef'; +import {FlattenedField, FlattenedQuery, VisitOption} from '../types'; +import { + APIQuery, + APIQueryRun, + APIQueryField, + APIQueryGroupField, + APIQueryCriteriaGroup, +} from '../types'; + +type QueryActionType = [ + (queryID: number|null) => void, + (action: string) => void, +]; + +interface FlattenedQueryMap { + [queryId: number]: FlattenedQuery +} +/** + * React hook for triggering toggling of starred queries + * on a LORIS server. + * + * @param {function} onCompleteCallback - an action to perform after pinning + * @returns {array} - QueryAction functions + */ +function useStarredQueries(onCompleteCallback: () => void): QueryActionType { + const [starQueryID, setStarQueryID] = useState(null); + const [starAction, setStarAction] = useState('true'); + useEffect(() => { + if (starQueryID == null) { + return; + } + + fetch( + '/dataquery/queries/' + starQueryID + '?star=' + starAction, + { + method: 'PATCH', + credentials: 'same-origin', + }, + ).then( () => { + setStarQueryID(null); + if (onCompleteCallback) { + onCompleteCallback(); + } + } + ); + }, [starQueryID, starAction]); + return [setStarQueryID, setStarAction]; +} + +/** + * React hook for triggering toggling of shared queries + * on a LORIS server. + * + * @param {function} onCompleteCallback - an action to perform after pinning + * @returns {array} - QueryAction functions + */ +function useShareQueries(onCompleteCallback: () => void): QueryActionType { + const [shareQueryID, setShareQueryID] = useState(null); + const [shareAction, setShareAction] = useState('true'); + useEffect(() => { + if (shareQueryID == null) { + return; + } + + fetch( + '/dataquery/queries/' + shareQueryID + '?share=' + shareAction, + { + method: 'PATCH', + credentials: 'same-origin', + }, + ).then( () => { + setShareQueryID(null); + if (onCompleteCallback) { + onCompleteCallback(); + } + } + ); + }, [shareQueryID, shareAction]); + return [setShareQueryID, setShareAction]; +} + +type SharedQueriesType = [ + { + recent: FlattenedQuery[], + shared: FlattenedQuery[], + top: FlattenedQuery[], + }, + () => void, + { + star: (queryID: number) => void, + unstar: (queryID: number) => void, + share: (queryID: number) => void, + unshare: (queryID: number) => void, + } +]; +/** + * React hook to load recent and shared queries from the server + * + * @param {string} username - The username accessing the module + * @returns {array} - [{queries}, reload function(), {queryActions}] + */ +function useSharedQueries(username: string): SharedQueriesType { + const [recentQueries, setRecentQueries] = useState([]); + const [sharedQueries, setSharedQueries] = useState([]); + const [topQueries, setTopQueries] = useState([]); + + + const [loadQueriesForce, setLoadQueriesForce] = useState(0); + /** + * Force the client to reload queries + * + * @returns {void} + */ + const reloadQueries = () => setLoadQueriesForce(loadQueriesForce+1); + const [setStarQueryID, setStarAction] = useStarredQueries(reloadQueries); + const [setShareQueryID, setShareAction] = useShareQueries(reloadQueries); + + useEffect(() => { + fetch('/dataquery/queries', {credentials: 'same-origin'}) + .then((resp) => { + if (!resp.ok) { + throw new Error('Invalid response'); + } + return resp.json(); + }).then((result) => { + const convertedshared: FlattenedQuery[] = []; + const convertedtop: FlattenedQuery[] = []; + const allQueries: FlattenedQueryMap = {}; + if (result.queries) { + result.queries.forEach( (query: APIQuery) => { + const flattened: FlattenedQuery = query2flattened(query); + allQueries[query.QueryID] = flattened; + + if (query.Pinned == true) { + convertedtop.push(flattened); + } + if (query.Public == true) { + // If we're the only person who shared it, don't show it in our + // shared queries. + // If other people shared it too, then remove ourselves from the + // "shared by" list in the Shared Queries panel. + if (query.SharedBy.length == 1 + && query.SharedBy[0] == username + ) { + // don't include + } else { + // filter + query.SharedBy = query.SharedBy.filter( + (item: string) => { + return item != username; + } + ); + // Make a new copy to avoid mutating the version used by other + // tabs + const flattened2: FlattenedQuery + = query2flattened(query); + convertedshared.push(flattened2); + } + } + }); + } + setSharedQueries(convertedshared); + setTopQueries(convertedtop); + return allQueries; + }).then((allQueries) => { + fetch('/dataquery/queries/runs', {credentials: 'same-origin'}) + .then((resp) => { + if (!resp.ok) { + throw new Error('Invalid response'); + } + return resp.json(); + }).then((result) => { + if (result.queryruns) { + const convertedrecent: FlattenedQuery[] = []; + result.queryruns.forEach( (queryRun: APIQueryRun) => { + const queryObj: FlattenedQuery + = allQueries[queryRun.QueryID]; + if (!queryObj) { + console.error( + 'Could not get ', + queryRun.QueryID, + ' from ', + allQueries); + return; + } + convertedrecent.push({ + RunTime: queryRun.RunTime, + ...queryObj, + }); + }); + setRecentQueries(convertedrecent); + } + }); + }).catch( (error) => { + console.error(error); + }); + }, [loadQueriesForce]); + + return [ + { + recent: recentQueries, + shared: sharedQueries, + top: topQueries, + }, + reloadQueries, + { + /** + * Stars a query on the server + * + * @param {number} queryID - The queryID to star + * @returns {void} + */ + star: (queryID: number) => { + setShareQueryID(null); + setStarAction('true'); + setStarQueryID(queryID); + }, + /** + * Unstars a query on the server + * + * @param {number} queryID - The queryID to unstar + * @returns {void} + */ + unstar: (queryID: number) => { + setShareQueryID(null); + setStarAction('false'); + setStarQueryID(queryID); + }, + /** + * Shares a query on the server + * + * @param {number} queryID - The queryID to share + * @returns {void} + */ + share: (queryID: number) => { + setStarQueryID(null); + setShareAction('true'); + setShareQueryID(queryID); + }, + /** + * Unshares a query on the server + * + * @param {number} queryID - The queryID to unshare + * @returns {void} + */ + unshare: (queryID: number) => { + setStarQueryID(null); + setShareAction('false'); + setShareQueryID(queryID); + }, + }, + ]; +} + +/** + * Check if a term from a sub-term from query group is an APIQueryGroupField + * or an APIQueryCriteriaGroup + * + * @param {APIQueryGroupField|APIQueryCriteriaGroup} term - The term to check + * @returns {boolean} - true if the term is an APIQueryCriteriaGroup + */ +function isAPIQueryCriteriaGroup( + term: APIQueryGroupField|APIQueryCriteriaGroup +): term is APIQueryCriteriaGroup { + return (term as APIQueryCriteriaGroup).operator !== undefined; +} +/** + * Takes a saved query from a JSON object and marshal + * it into a QueryGroup object + * + * @param {object} query - the json object + * @returns {QueryGroup} - The object converted into a QueryGroup + */ +function unserializeSavedQuery(query: APIQueryCriteriaGroup): QueryGroup { + if (!query.operator) { + throw new Error('Invalid query tree'); + } + const root = new QueryGroup(query.operator); + query.group.forEach((val) => { + if (isAPIQueryCriteriaGroup(val)) { + const childTree: QueryGroup = unserializeSavedQuery(val); + root.group.push(childTree); + return; + } else { + if (!val.module + || !val.category + || !val.fieldname + || !val.op) { + console.error('Invalid criteria', val); + return; + } + + const term = val as APIQueryGroupField; + + root.addTerm( + new QueryTerm( + term.module, + term.category, + term.fieldname, + term.op, + term.value, + term.visits, + ) + ); + } + }); + return root; +} + +/** + * React hook to load a query if one was passed in the URL. + * + * @param {function} loadQuery - function to load the query into React state + */ +function useLoadQueryFromURL( + loadQuery: (fields: APIQueryField[], filters: QueryGroup|null) => void +) { + // Load query if queryID was passed + useEffect(() => { + const params = new URLSearchParams(window.location.search); + const queryID = params.get('queryID'); + if (!queryID) { + return; + } + fetch( + '/dataquery/queries/' + queryID, + { + method: 'GET', + credentials: 'same-origin', + }, + ).then((resp) => { + if (!resp.ok) { + throw new Error('Invalid response'); + } + return resp.json(); + }).then((result) => { + if (result.Query.criteria) { + result.Query.criteria = unserializeSavedQuery( + result.Query.criteria + ); + } + loadQuery(result.Query.fields, result.Query.criteria); + swal.fire({ + type: 'success', + text: 'Loaded query', + }); + }).catch( (error) => { + swal.fire({ + type: 'error', + text: 'Could not load query', + }); + console.error(error); + }); + }, []); +} + + +/** + * Convert a query from the format returned by the API to the format + * used by the displayed query list on the main page. + * + * @param {APIQuery} query - The query to convert + * @returns {FlattenedQuery} - The query converted to the new type + */ +function query2flattened(query: APIQuery): FlattenedQuery { + const rv: FlattenedQuery = { + QueryID: query.QueryID, + fields: query.Query.fields.map( + (field: APIQueryField): FlattenedField => { + if (!field.visits) { + return { + module: field.module, + category: field.category, + field: field.field, + visits: null, + }; + } + return { + module: field.module, + category: field.category, + field: field.field, + visits: field.visits.map( (vl: string): VisitOption => { + return {label: vl, value: vl}; + }), + }; + }), + }; + + if (query.Query.criteria) { + rv.criteria = unserializeSavedQuery(query.Query.criteria); + } + if (query.Name) { + rv.Name = query.Name; + } + if (query.AdminName) { + rv.AdminName = query.AdminName; + } + if (query.Public) { + rv.Public = query.Public; + } + if (query.Starred) { + rv.Starred = query.Starred; + } + if (query.SharedBy) { + rv.SharedBy = query.SharedBy; + } + return rv; +} + +export { + useSharedQueries, + useLoadQueryFromURL, +}; diff --git a/modules/dataquery/jsx/hooks/usevisits.tsx b/modules/dataquery/jsx/hooks/usevisits.tsx new file mode 100644 index 00000000000..1fbc4d4f527 --- /dev/null +++ b/modules/dataquery/jsx/hooks/usevisits.tsx @@ -0,0 +1,51 @@ +import {useState, useEffect} from 'react'; +import {VisitOption} from '../types'; + +type UseVisitsReturn = { + // All visits that exist on the server + all: string[], + // The subset of all that were selected by the user as defaults + default_: string[], + // Callback to set the defaults + modifyDefault: (values: readonly VisitOption[]) => void, +}; +/** + * React hook to load a list of valid visits from the server + * and manage which should be selected by default + * + * @returns {UseVisitsReturn} - list of default and all visits + */ +function useVisits(): UseVisitsReturn { + const [allVisits, setAllVisits] = useState([]); + const [defaultVisits, setDefaultVisits] = useState([]); + useEffect(() => { + fetch('/dataquery/visitlist', {credentials: 'same-origin'}) + .then((resp) => { + if (!resp.ok) { + throw new Error('Invalid response'); + } + return resp.json(); + }).then((result) => { + setDefaultVisits(result.Visits); + setAllVisits(result.Visits); + } + ).catch( (error) => { + console.error(error); + }); + }, []); + return { + all: allVisits, + default_: defaultVisits, + /** + * Modify the default visits to use + * + * @param {VisitOption[]} values - The selected options from ReactSelect + * @returns {void} + */ + modifyDefault: (values: readonly VisitOption[]) => { + setDefaultVisits(values.map((el) => el.value)); + }, + }; +} + +export default useVisits; diff --git a/modules/dataquery/jsx/index.tsx b/modules/dataquery/jsx/index.tsx new file mode 100644 index 00000000000..f234e44eaa1 --- /dev/null +++ b/modules/dataquery/jsx/index.tsx @@ -0,0 +1,261 @@ +import {createRoot} from 'react-dom/client'; + +import {useState} from 'react'; + +import Welcome from './welcome'; +import DefineFilters from './definefilters'; +import DefineFields from './definefields'; +import ViewData from './viewdata'; + +import NextSteps from './nextsteps'; + +import useBreadcrumbs from './hooks/usebreadcrumbs'; +import useVisits from './hooks/usevisits'; +import useQuery from './hooks/usequery'; +import {useSharedQueries, useLoadQueryFromURL} from './hooks/usesharedqueries'; + +import {useDataDictionary, useCategories} from './hooks/usedatadictionary'; +import {ModuleDictionary, DictionaryCategory} from './types'; + +type ActiveCategoryType = { + module: string, + category: string, + currentDictionary: DictionaryCategory, + changeCategory: (module: string, category: string) => void, +}; + +/** + * React hook to manage the selection of an active module and category + * + * @param {function} retrieveModuleDictionary - a function that will return a + promise to retrieve the module's dictionary + * @returns {ActiveCategoryType} - an object of the current dictionary and action to change it + */ +function useActiveCategory( + retrieveModuleDictionary: (module: string) => Promise +): ActiveCategoryType { + const [module, setModule] = useState(''); + const [category, setCategory] = useState(''); + const [moduleDict, setModuleDict] = useState({}); + /** + * Change the current category, retrieving the module dictionary from + * the server if necessary. + * + * @param {string} module - the module to become active + * @param {string} category - the category to become active + * @returns {void} + */ + const changeCategory = (module: string, category: string) => { + retrieveModuleDictionary(module).then( (dict) => { + setModule(module); + setCategory(category); + setModuleDict(dict[category]); + }); + }; + return { + module: module, + category: category, + currentDictionary: moduleDict, + changeCategory: changeCategory, + }; +} + +/** + * Return the main page for the DQT + * + * @param {object} props - React props + * @param {boolean} props.queryAdmin - true if the current user has permission to administer study queries + * @param {string} props.username - The user accessing the app + * @returns {React.ReactElement} - The main page of the app + */ +function DataQueryApp(props: { + queryAdmin: boolean, + username: string +}) { + const [activeTab, setActiveTab] = useState('Info'); + useBreadcrumbs(activeTab, setActiveTab); + + const [queries, reloadQueries, queryActions] + = useSharedQueries(props.username); + + const visits = useVisits(); + + const [ + fulldictionary, + fetchModuleDictionary, + ] = useDataDictionary(); + const categories = useCategories(); + + const activeCategory = useActiveCategory( + fetchModuleDictionary, + ); + + const [query, + loadQuery, + selectedFields, + fieldActions, + criteriaActions, + ] = useQuery(); + + useLoadQueryFromURL(loadQuery); + + if (!categories) { + return
Loading...
; + } + let content; + + /** + * Maps a module name from the backend name to a human friendly name. + * + * @param {string} name - The module name + * @returns {string} - the human friendly name + */ + const mapModuleName = (name: string): string => { + if (categories && categories.modules) { + return categories.modules[name]; + } + return name; + }; + /** + * Maps a category name from the backend name to a human friendly name. + * + * @param {string} module - The module name + * @param {string} category - The category name within the module + * @returns {string} - the human friendly name + */ + const mapCategoryName = (module: string, category: string): string => { + if (categories && categories.categories + && categories.categories[module]) { + return categories.categories[module][category]; + } + return category; + }; + + /** + * Function to retrieve a module's data dictionary from the server. + * + * @param {string} module - the module whole fields should be retrieved + * @returns {void} + */ + const getModuleFields = (module: string): void => { + fetchModuleDictionary(module); + }; + + switch (activeTab) { + case 'Info': + content = setActiveTab('DefineFields')} + + queryAdmin={props.queryAdmin} + />; + break; + case 'DefineFields': + content = ; + break; + case 'DefineFilters': + content = ; + break; + case 'ViewData': + content = ; + break; + default: + content =
Invalid tab
; + } + return
+
{content}
+ setActiveTab(page) + }/> +
; +} + +declare const loris: any; +window.addEventListener('load', () => { + const element = document.getElementById('lorisworkspace'); + if (!element) { + throw new Error('Missing lorisworkspace'); + } + const root = createRoot(element); + + root.render( + , + ); +}); + +export default DataQueryApp; diff --git a/modules/dataquery/jsx/nextsteps.tsx b/modules/dataquery/jsx/nextsteps.tsx new file mode 100644 index 00000000000..6293533bc46 --- /dev/null +++ b/modules/dataquery/jsx/nextsteps.tsx @@ -0,0 +1,163 @@ +import React, {useState} from 'react'; +import {APIQueryField} from './types'; +import {ButtonElement} from 'jsx/Form'; +import {QueryGroup} from './querydef'; + +/** + * Next steps options for query navigation + * + * @param {object} props - React props + * @param {APIQueryField[]} props.fields - The fields selected + * @param {QueryGroup} props.filters - The filters selected + * @param {string} props.page - The current page name + * @param {function} props.changePage - A function to change the current page + * @returns {React.ReactElement} - The "Next Steps" menu + */ +function NextSteps(props: { + fields: APIQueryField[] + filters: QueryGroup, + page: string, + changePage: (newpage: string) => void, +}) { + const [expanded, setExpanded] = useState(true); + const steps: React.ReactElement[] = []; + + + const canRun = (props.fields && props.fields.length > 0); + const fieldLabel = (props.fields && props.fields.length > 0) + ? 'Modify Fields' + : 'Choose Fields'; + const filterLabel = (props.filters && props.filters.group.length > 0) + ? 'Modify Filters' + : 'Add Filters'; + switch (props.page) { + case 'Info': + if (canRun) { + // A previous query was loaded, it can be either + // modified or run + steps.push( props.changePage('DefineFields')} + />); + steps.push( props.changePage('DefineFilters')} + />); + steps.push( props.changePage('ViewData')} + />); + } else { + // No query loaded, must define fields + steps.push( props.changePage('DefineFields')} + />); + } + break; + case 'DefineFields': + steps.push( props.changePage('DefineFilters')} + />); + if (canRun) { + steps.push( props.changePage('ViewData')} + />); + } + break; + case 'DefineFilters': + if (canRun) { + steps.push( props.changePage('ViewData')} + />); + } + steps.push( props.changePage('DefineFields')} + />); + break; + case 'ViewData': + steps.push( props.changePage('DefineFields')} + />); + steps.push( props.changePage('DefineFilters')} + />); + break; + } + + const expandIcon = setExpanded(!expanded)} + >; + const style = expanded ? { + background: 'white', + padding: '0.5em', + paddingLeft: '2em', + } : { + display: 'none', + visibility: 'hidden' as const, + padding: '0.5em', + paddingLeft: '2em', + }; + + return ( +
+
+
+

Next Steps

+
+ {steps} +
+
+
{expandIcon}
+
+
+ ); +} + +export default NextSteps; diff --git a/modules/dataquery/jsx/querydef.tsx b/modules/dataquery/jsx/querydef.tsx new file mode 100644 index 00000000000..5c28b34362a --- /dev/null +++ b/modules/dataquery/jsx/querydef.tsx @@ -0,0 +1,89 @@ +/** + * A single term in a query hierarchy. + */ +export class QueryTerm { + module: string + category: string; + fieldname: string; + op: string; + visits: string[]|undefined; + value: string|string[]; + + /** + * Constructor + * + * @param {string} module - the module name + * @param {string} category - the field name + * @param {string} fieldname - the field name within the module + * @param {string} op - the criteria operator + * @param {string} value - the criteria value + * @param {array} visits - the visits for the criteria + */ + constructor( + module: string, + category: string, + fieldname: string, + op: string, + value: string|string[], + visits?: string[] + ) { + this.module = module; + this.category = category; + this.fieldname = fieldname; + this.op = op; + this.value = value; + this.visits = visits; + } +} + +/** + * And AND/OR group of terms within a query + */ +export class QueryGroup { + operator: 'and' | 'or'; + group: (QueryTerm|QueryGroup)[] + + /** + * Constructor + * + * @param {string} op -- 'and' or 'or' -- the operator used for this group + */ + constructor(op: 'and' | 'or') { + this.operator = op; + this.group = []; + } + + /** + * Adds a term to this group + * + * @param {object} condition - the term's conditions + */ + addTerm(condition: QueryTerm) { + this.group.push(condition); + } + + /** + * Removes the term and index idx from this group + * + * @param {number} idx - the index to remove + * @returns {QueryGroup} - the new querygroup + */ + removeTerm(idx: number): QueryGroup { + this.group = this.group.filter((el, fidx) => { + return idx != fidx; + }); + return this; + } + + /** + * Adds a new group of AND/OR clauses + * as a subgroup. + */ + addGroup(): void { + // The default operation for a subgroup + // is the opposite of this one, otherwise + // there would be no reason for a new group + const newOp = this.operator == 'and' ? 'or' : 'and'; + this.group.push(new QueryGroup(newOp)); + } +} diff --git a/modules/dataquery/jsx/querytree.tsx b/modules/dataquery/jsx/querytree.tsx new file mode 100644 index 00000000000..1cb319674cd --- /dev/null +++ b/modules/dataquery/jsx/querytree.tsx @@ -0,0 +1,285 @@ +import {useState} from 'react'; +import {QueryGroup, QueryTerm} from './querydef'; +import {CriteriaTerm} from './criteriaterm'; +import {ButtonElement} from 'jsx/Form'; +import {FullDictionary} from './types'; + +/** + * Alternate background colour for a QueryTree + * + * @param {string} c - the current colour + * @returns {string} - The next colour after c + */ +function alternateColour(c: string): string { + if (c == 'rgb(255, 255, 255)') { + return 'rgb(240, 240, 240)'; + } + return 'rgb(255, 255, 255)'; +} + +/** + * Recursively render a tree of AND/OR + * conditions + * + * @param {object} props - React props + * @param {React.CSSProperties} props.buttonStyle - CSS to add to buttons + * @param {React.CSSProperties} props.buttonGroupStyle - CSS to add to groups of buttons + * @param {string} props.backgroundColour - The colour to use for the background of this QueryTree + * @param {QueryGroup} props.items - The QueryGroup to render into a tree + * @param {boolean} props.subtree - True if this is a sub-tree + * @param {React.MouseEventHandler} props.onDeleteHover - Callback for when hovering over the delete icon + * @param {React.MouseEventHandler} props.onDeleteLeave - Callback for when no longer hovering over the delete icon + * @param {React.MouseEventHandler} props.deleteItem - Callback for when delete is clicked. + * @param {QueryGroup} props.activeGroup - The active group that a modal is managing + * @param {function} props.newGroup - Callback to create a new group at the end of props.items + * @param {function} props.newItem - Callback to create a new item (term) at the end of props.items + * @param {function} props.removeQueryGroupItem - Callback that should remove item i from props.items and return a new QueryGroup + * @param {function} props.setModalGroup - Callback that should set the group that a modal (managed by the parent) is managing + * @param {object} props.mapModuleName - Function to map the backend module name to a user friendly name + * @param {object} props.mapCategoryName - Function to map the backend category name to a user friendly name + * @param {object} props.fulldictionary - The dictionary of all modules that have been loaded + * @returns {React.ReactElement} - the react element + */ +function QueryTree(props: { + buttonStyle?: React.CSSProperties, + buttonGroupStyle?: React.CSSProperties, + backgroundColour?: string, + items: QueryGroup, + subtree?: boolean, + onDeleteHover?: React.MouseEventHandler, + onDeleteLeave?: React.MouseEventHandler, + deleteItem?: React.MouseEventHandler, + activeGroup?: QueryGroup, + newGroup?: (items: QueryGroup) => void, + newItem?: (items: QueryGroup) => void, + removeQueryGroupItem?: (items: QueryGroup, i: number) => QueryGroup, + setModalGroup?: (newgroup: QueryGroup) => void, + fulldictionary: FullDictionary, + mapModuleName: (module: string) => string, + mapCategoryName: (module: string, category: string) => string, +}) { + const [deleteItemIndex, setDeleteItemIndex] = useState(null); + + /** + * Render a single term of the QueryTree group. + * + * @param {QueryGroup|QueryTerm} item - The item to render from a group + * @param {number} i - the index being rendered + * @returns {React.ReactElement} - The react element + */ + const renderitem = + (item: QueryGroup|QueryTerm, i: number): React.ReactElement => { + const operator = i != props.items.group.length-1 ? + props.items.operator : ''; + const style: React.CSSProperties = { + display: 'flex' as const, + flexDirection: 'column' as const, + width: '100%', + }; + const operatorStyle = { + alignSelf: 'center', + fontWeight: 'bold', + }; + if (deleteItemIndex == i) { + style.textDecoration = 'line-through'; + } + + /** + * Deletes an item from the group and call the removeQueryGroupItem + * callback. + * + * @returns {void} + */ + const deleteItem = () => { + if (props.removeQueryGroupItem) { + const newquery = props.removeQueryGroupItem( + props.items, + i, + ); + if (props.setModalGroup) { + props.setModalGroup(newquery); + } + } + }; + if (item instanceof QueryTerm) { + const deleteIcon = props.removeQueryGroupItem ? ( +
+ setDeleteItemIndex(i)} + onMouseLeave={() => setDeleteItemIndex(null)} + style={{cursor: 'pointer'}} + /> +
+ ) : ''; + + return
  • +
    + + {deleteIcon} +
    +
    {operator}
    +
  • ; + } else if (item instanceof QueryGroup) { + const buttonStyle: React.CSSProperties = deleteItemIndex == i ? { + textDecoration: 'line-through', + } : {}; + + return (
  • +
    + setDeleteItemIndex(i)} + onDeleteLeave={ + () => setDeleteItemIndex(null) + } + subtree={true} + fulldictionary={props.fulldictionary} + + /> +
    +
    {operator}
    +
  • ); + } else { + console.error('Invalid tree'); + } + return
  • {i}
  • ; + }; + + const terms: React.ReactElement[] = props.items.group.map(renderitem); + let warning; + switch (props.items.group.length) { + case 0: + warning =
    + +
    + Group does not have any items. +
    +
    ; + break; + case 1: + warning =
    + +
    + Group only has 1 item. A group with only 1 item is equivalent + to not having the group. +
    +
    ; + break; + } + + /** + * Handler to calls newItem callback onClick + * + * @param {React.MouseEvent} e - The event + * @returns {void} + */ + const newItemClick = (e: React.MouseEvent) => { + e.preventDefault(); + if (props.newItem) { + props.newItem(props.items); + } + }; + + /** + * Call newGroup callback onClick + * + * @param {React.MouseEvent} e - The event + * @returns {void} + */ + const newGroupClick = (e: React.MouseEvent) => { + e.preventDefault(); + if (props.newGroup) { + props.newGroup(props.items); + } + }; + + const antiOperator = props.items.operator == 'and' ? 'or' : 'and'; + const style: React.CSSProperties= {}; + if (props.activeGroup == props.items) { + style.background = 'pink'; + } + + let deleteGroupHTML; + if (props.deleteItem) { + deleteGroupHTML = ( +
    + +
    + ); + } + const marginStyle: React.CSSProperties = props.subtree === true ? {} : { + margin: 0, + padding: 0, + }; + return ( +
    +
      + {terms} +
    • +
      +
      + +
      +
      + +
      + {warning} + {deleteGroupHTML} +
    • +
    +
    + ); +} + +export default QueryTree; diff --git a/modules/dataquery/jsx/types.tsx b/modules/dataquery/jsx/types.tsx new file mode 100644 index 00000000000..bde23bc32a4 --- /dev/null +++ b/modules/dataquery/jsx/types.tsx @@ -0,0 +1,118 @@ +import {QueryGroup} from './querydef'; +/** + * These types match the types that come from the backend and + * are defined in the swagger schema. They must be kept in sync + */ +export type APIQueryField = { + module: string; + category: string; + field: string; + visits?: string[]; +}; + +export enum Operators { + // Standard operators + LT = 'lt', + LTE ='lte', + EQ = 'eq', + NEQ = 'neq', + GTE = 'gte', + GT = 'gt', + // enum operator + IN = 'in', + // String operators + STARTSWITH = 'startsWith', + ENDSWITH = 'endsWith', + CONTAINS = 'contains', + // Optional cardinality operators + ISNOTNULL = 'isnotnull', + ISNULL = 'isnull', + // Many cardinality operators + EXISTS = 'exists', + NOTEXISTS = 'notexists', + NUMBEROF = 'numberof', +} + +export type APIQueryGroupField = { + module: string; + category: string; + fieldname: string; + op: Operators, + value: string|string[]; + visits?: string[]; +} + +export type APIQueryCriteriaGroup = { + operator: 'and' | 'or'; + group: (APIQueryCriteriaGroup|APIQueryGroupField)[]; +} + +export type APIQuery = { + QueryID: number; + Starred: boolean; + Public: boolean; + Pinned: boolean; + SharedBy: string[]; + Name: string; + AdminName: string; + Query: APIQueryObject + +} +export type APIQueryObject = { + type: 'candidates'; + fields: APIQueryField[]; + criteria?: APIQueryCriteriaGroup; +}; +export type APIQueryRun = { + self: string, + QueryURI: string, + RunTime: string, + QueryID: number, + QueryRunID: number, +} + +// Queries that have been processed into the QueryList format +// Not from the API. +export type FlattenedField = { + module: string, + category: string, + field: string, + visits: VisitOption[]|null, +} +export type FlattenedQuery = { + QueryID: number, + fields: FlattenedField[], + criteria?: QueryGroup, + Name?: string, + Public?: boolean, + Starred?: boolean, + SharedBy?: string[], + RunTime?: string + AdminName?: string, +} + +// Option in the format expected by React select +export type VisitOption = { + label: string, + value: string +} + +export interface FullDictionary { + [modulename: string]: ModuleDictionary +} +export interface ModuleDictionary { + [category: string]: DictionaryCategory +} + +export type FieldDictionary = { + description: string, + scope: 'candidate' | 'session', + type: string, + cardinality: 'unique' | 'single' | 'optional' | 'many', + visits?: string[], // session only + options?: string[], // enum only +} + +export interface DictionaryCategory { + [fieldname: string]: FieldDictionary +} diff --git a/modules/dataquery/jsx/viewdata.tsx b/modules/dataquery/jsx/viewdata.tsx new file mode 100644 index 00000000000..709ab67812c --- /dev/null +++ b/modules/dataquery/jsx/viewdata.tsx @@ -0,0 +1,970 @@ +import swal from 'sweetalert2'; +import {useState, useEffect, ReactNode} from 'react'; + +import fetchDataStream from 'jslib/fetchDataStream'; + +import DataTable from 'jsx/DataTable'; +import {SelectElement} from 'jsx/Form'; +import {APIQueryField, APIQueryObject} from './types'; +import {QueryGroup} from './querydef'; +import {FullDictionary, FieldDictionary} from './types'; +import {calcPayload} from './calcpayload'; +import getDictionaryDescription from './getdictionarydescription'; + +type TableRow = (string|null)[]; + +type JSONString = string; + +type SessionRowCell = { + VisitLabel: string; + value?: string + values?: string[] +}; + +type KeyedValue = { + value: string; + key: string; +} + +/** + * Convert a piece of data from JSON to the format to be displayed + * in the cell. Used for either CSV or frontend display. + * + * @param {string} data - the raw, unparsed string data. + * @returns {string} the non-JSON value + */ +function cellValue(data: string) { + try { + const parsed = JSON.parse(data); + if (typeof parsed === 'object') { + // Can't include objects as react children, if we got here + // there's probably a bug. + return data; + } + return parsed; + } catch (e) { + return data; + } +} +/** + * Renders a single table cell value, converting from JSON string to + * normal string if necessary. + * + * @param {object} props - React props + * @param {string} props.data - The JSON string to display + * @returns {React.ReactElement} - the Table Cell + */ +function TableCell(props: {data: string}) { + return {cellValue(props.data)}; +} + +/** + * Display a progress bar. + * + * @param {object} props - React props + * @param {string} props.type - the type of progress being displayed + * @param {number} props.value - The current value + * @param {number} props.max - The maximum value + * @returns {React.ReactElement} - The ProgressBar element + */ +function ProgressBar(props: {type: string, value: number, max: number}) { + switch (props.type) { + case 'loading': + if (props.value == 0) { + return

    Query not yet run

    ; + } + return (
    + + + {props.value} of {props.max} candidates + +
    ); + case 'headers': + return (
    + + + {props.value} of {props.max} columns + +
    ); + case 'dataorganization': + return (
    + + + {props.value} of {props.max} columns + +
    ); + } + return

    Invalid progress type: {props.type}

    ; +} + +type RunQueryType = { + loading: boolean, + data: string[][], + totalcount: number, +}; +/** + * React hook to run a given query. + * + * @param {APIQueryField[]} fields - The fields selected + * @param {QueryGroup} filters - The filters selected + * @param {function} onRun - Callback to call when the query is run + * @returns {RunQueryType} - a description of the status of the loading and the loaded values + */ +function useRunQuery( + fields: APIQueryField[], + filters: QueryGroup, + onRun: () => void +): RunQueryType { + const [expectedResults, setExpectedResults] = useState(0); + const [resultData, setResultData] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + setLoading(true); + const payload: APIQueryObject = calcPayload(fields, filters); + fetch( + '/dataquery/queries', + { + method: 'post', + credentials: 'same-origin', + body: JSON.stringify(payload), + }, + ).then( + (resp) => { + if (!resp.ok) { + throw new Error('Error creating query.'); + } + return resp.json(); + } + ).then( + (data) => { + const resultbuffer: any[] = []; + fetch( + '/dataquery/queries/' + + data.QueryID + '/count', + { + method: 'GET', + credentials: 'same-origin', + } + ).then((resp) => resp.json() + ).then( (json) => { + setExpectedResults(json.count); + }); + fetchDataStream( + '/dataquery/queries/' + data.QueryID + '/run', + (row: any) => { + resultbuffer.push(row); + }, + () => { + if (resultbuffer.length % 10 == 0) { + setResultData([...resultbuffer]); + } + }, + () => { + setResultData([...resultbuffer]); + setLoading(false); + }, + 'post', + ); + onRun(); // forces query list to be reloaded + } + ).catch( + (msg) => { + swal.fire({ + type: 'error', + text: msg, + }); + } + ); + }, [fields, filters]); + return { + loading: loading, + data: resultData, + totalcount: expectedResults, + }; +} + +type DataOrganizationType = { + headers: string[], + data: TableRow[], + status: 'headers'|'data'|'done'|null, + progress: number, + } +/** + * Hook to re-organize tabulated data returned from the API into the format selected by the user + * + * @param {RunQueryType} queryData - The data returned by the API + * @param {string} visitOrganization - The type of data organization selected by the user + * @param {string} headerDisplay - The display to use for the headers + * @param {APIQueryField[]} fields - The fields that need to be organized + * @param {FullDictionary} fulldictionary - The full dictionary of all selected modules + * @returns {object} - the headers and data re-organised according to the user's selection + */ +function useDataOrganization( + queryData: RunQueryType, + visitOrganization: VisitOrgType, + headerDisplay: HeaderDisplayType, + fields: APIQueryField[], + fulldictionary: FullDictionary +) : DataOrganizationType { + const [tableData, setTableData] = useState([]); + const [orgStatus, setOrgStatus] + = useState<'headers'|'data'|'done'|null>(null); + const [progress, setProgress] = useState(0); + const [headers, setHeaders] = useState([]); + useEffect( () => { + if (queryData.loading == true) { + return; + } + setOrgStatus('headers'); + organizeHeaders(fields, + visitOrganization, + headerDisplay, + fulldictionary, + (i) => setProgress(i), + ).then( (headers: string[]) => { + setHeaders(headers); + setOrgStatus('data'); + + organizeData( + queryData.data, + visitOrganization, + fulldictionary, + fields, + (i) => setProgress(i), + ).then((data: TableRow[]) => { + setTableData(data); + setOrgStatus('done'); + }); + }); + }, [visitOrganization, headerDisplay, queryData.loading, queryData.data]); + return { + 'headers': headers, + 'data': tableData, + + 'status': orgStatus, + 'progress': progress, + }; +} + +/** + * The View Data tab + * + * @param {object} props - React props + * @param {APIQueryField[]} props.fields - The selected fields + * @param {QueryGroup} props.filters - The selected filters + * @param {object} props.fulldictionary - the data dictionary + * @param {function} props.onRun - Callback for when the query is run + * @returns {React.ReactElement} - The ViewData tab + */ +function ViewData(props: { + fields: APIQueryField[], + filters: QueryGroup, + onRun: () => void + fulldictionary: FullDictionary, +}) { + const [visitOrganization, setVisitOrganization] + = useState('inline'); + const [headerDisplay, setHeaderDisplay] + = useState('fieldnamedesc'); + const queryData = useRunQuery(props.fields, props.filters, props.onRun); + const organizedData = useDataOrganization( + queryData, + visitOrganization, + headerDisplay, + props.fields, + props.fulldictionary + ); + + let queryTable; + if (queryData.loading) { + queryTable = ; + } else { + switch (organizedData['status']) { + case null: + return queryTable =

    Query not yet run

    ; + case 'headers': + queryTable = ; + break; + case 'data': + queryTable = ; + break; + case 'done': + try { + queryTable = { + return {show: true, label: val}; + }) + } + data={organizedData.data} + getMappedCell={ + organizedMapper( + visitOrganization, + props.fields, + props.fulldictionary, + ) + } + getFormattedCell={ + organizedFormatter( + queryData.data, + visitOrganization, + props.fields, + props.fulldictionary, + ) + } + hide={ + { + rowsPerPage: false, + defaultColumn: true, + downloadCSV: visitOrganization == 'inline', + } + } + />; + } catch (e) { + // OrganizedMapper/Formatter can throw an error + // before the loading is complete + return
    Loading..
    ; + } + break; + default: + throw new Error('Unhandled organization status'); + } + } + + return
    + + setHeaderDisplay(value) + } + sortByValue={false} + /> + + setVisitOrganization(value) + } + sortByValue={false} + /> + {queryTable} +
    ; +} + +/** + * Organize the session data into tabular data based on + * the visit organization settings + * + * @param {array} resultData - The result of the query as returned by the API + * @param {string} visitOrganization - The visit organization + * option selected + * @param {FullDictionary} fulldict - the full data dictionary + * @param {APIQueryField[]} fields - the selected fields from the query. + * @param {function} onProgress - Callback to update progress status display. + * @returns {string[][]} - The data organized into a tabulated form + * such that the result matches the visual table shown by the + * frontend cell-for-cell. This may involve adding rows or columns + * for the sessions or headers. + */ +function organizeData( + resultData: string[][], + visitOrganization: VisitOrgType, + fulldict: FullDictionary, + fields: APIQueryField[], + onProgress: (i: number) => void +) : Promise { + switch (visitOrganization) { + case 'raw': + return Promise.resolve(resultData); + case 'inline': + // Organize with flexbox within the cell by the + // formatter + return Promise.resolve(resultData); + case 'longitudinal': + // the formatter splits into multiple cells + return Promise.resolve(resultData); + case 'crosssection': + return new Promise((resolve) => { + let rowNum = 0; + const promises: Promise[] = []; + for (const candidaterow of resultData) { + promises.push(new Promise((resolve) => { + // Collect list of visits for this candidate + setTimeout( () => { + const candidatevisits: {[visit: string]: boolean} = {}; + for (const i in candidaterow) { + if (!candidaterow.hasOwnProperty(i)) { + continue; + } + const dictionary = getDictionary(fields[i], fulldict); + if (dictionary && dictionary.scope == 'session') { + if (candidaterow[i] === null + || candidaterow[i] == '') { + continue; + } + const cellobj: any = JSON.parse(candidaterow[i]); + for (const session in cellobj) { + if (!cellobj.hasOwnProperty(session)) { + continue; + } + const vl: string = cellobj[session].VisitLabel; + candidatevisits[vl] = true; + } + } + } + + const dataRows: TableRow[] = []; + for (const visit in candidatevisits) { + if (!candidatevisits.hasOwnProperty(visit)) { + continue; + } + const dataRow: TableRow = []; + dataRow.push(visit); + for (let i = 0; i < candidaterow.length; i++) { + const dictionary = getDictionary(fields[i], fulldict); + if (dictionary && dictionary.scope == 'session') { + if (candidaterow[i] === null + || candidaterow[i] == '') { + dataRow.push(null); + continue; + } + const allCells: SessionRowCell[] = Object.values( + JSON.parse(candidaterow[i])); + const values: SessionRowCell[] = allCells.filter( + (sessionval: SessionRowCell) => { + return sessionval.VisitLabel == visit; + } + ); + switch (values.length) { + case 0: + dataRow.push(null); + break; + case 1: + if (typeof values[0].value === 'undefined') { + dataRow.push(null); + } else { + dataRow.push(values[0].value); + } + break; + default: + throw new Error('Too many visit values'); + } + } else { + dataRow.push(candidaterow[i]); + } + } + dataRows.push(dataRow); + } + onProgress(rowNum++); + resolve(dataRows); + }); + })); + } + + Promise.all(promises).then((values: TableRow[][]) => { + const mappedData: TableRow[] = []; + for (const row of values) { + mappedData.push(...row); + } + resolve(mappedData); + }); + }); + default: throw new Error('Unhandled visit organization'); + } +} + +/** + * Return a cell formatter specific to the options chosen for a CSV + * + * @param {string} visitOrganization - The visit organization + * option selected + * @param {array} fields - The fields selected + * @param {array} dict - The full dictionary + * @returns {function} - the appropriate column formatter for this data organization + */ +function organizedMapper( + visitOrganization: VisitOrgType, + fields: APIQueryField[], + dict: FullDictionary +) { + switch (visitOrganization) { + case 'raw': + return (fieldlabel: string, value: string|null): string => { + if (value === null) { + return ''; + } + return value; + }; + case 'crosssection': + return (fieldlabel: string, value: string|null): string => { + if (value === null) { + return ''; + } + return cellValue(value); + }; + case 'longitudinal': + return (label: string, + value: string|null, + row: TableRow, + headers: string[], + fieldNo: number): (string|null)[]|string|null => { + if (value === null) { + return ''; + } + const cells = expandLongitudinalCells(value, fieldNo, fields, dict); + if (cells === null) { + return null; + } + return cells.map( (val: string|null): string => { + if (val === null) { + return ''; + } + return cellValue(val); + }); + }; + default: return (): string => 'error'; + } +} + +/** + * Takes a longitudinal cell with n visits and convert it to + * n cells to be displayed in the longitudinal display, for either + * CSV or display. + * + * @param {string|null} value - The raw cell value + * @param {number} fieldNo - the raw index of the field + * @param {array} fields - The fields selected + * @param {array} dict - The full dictionary + * @returns {(string|null[])|null} - Expanded array of cells mapped + * to display value. Null in an array of (string|null)[] implies + * the cell has no data. null being returned directly implies that + * there are no table cells to be added based on this data. + */ +function expandLongitudinalCells( + value: string|null, + fieldNo: number, + fields: APIQueryField[], + dict: FullDictionary +): (string|null)[]|null { + // We added num fields * num visits headers, but + // resultData only has numFields rows. For each row + // we add multiple table cells for the number of visits + // for that fieldNo. ie. we treat cellPos as fieldNo. + // This means we need to bail once we've passed the + // number of fields we have in resultData. + if (fieldNo >= fields.length) { + return null; + } + // if candidate -- return directly + // if session -- get visits from query def, put in + const fieldobj = fields[fieldNo]; + const fielddict = getDictionary(fieldobj, dict); + if (fielddict === null) { + return null; + } + switch (fielddict.scope) { + case 'candidate': + if (fielddict.cardinality == 'many') { + throw new Error('Candidate cardinality many not implemented'); + } + return [value]; + case 'session': + let displayedVisits: string[]; + if (fieldobj.visits) { + displayedVisits = fieldobj.visits; + } else { + // All visits + if (fielddict.visits) { + displayedVisits = fielddict.visits; + } else { + displayedVisits = []; + } + } + if (!displayedVisits) { + displayedVisits = []; + } + const values = displayedVisits.map((visit) => { + if (!value) { + return null; + } + try { + const data = JSON.parse(value); + for (const session in data) { + if (data[session].VisitLabel == visit) { + return data[session].value; + } + } + return null; + } catch (e) { + throw new Error('Internal error'); + } + }); + return values; + } +} +/** + * Return a cell formatter specific to the options chosen + * + * @param {array} resultData - The result of the query + * @param {string} visitOrganization - The visit organization + * option selected + * @param {array} fields - The fields selected + * @param {array} dict - The full dictionary + * @returns {function} - the appropriate column formatter for this data organization + */ +function organizedFormatter( + resultData: string[][], + visitOrganization: VisitOrgType, + fields: APIQueryField[], + dict: FullDictionary +) { + let callback; + switch (visitOrganization) { + case 'raw': + /** + * Callback to return the raw JSON data as returned by the API, in + * table form for the DataTable + * + * @param {string} label - The table header + * @param {string} cell - The cell value + * @returns {React.ReactElement} - The table cell + */ + callback = (label: string, cell: string): ReactNode => { + return {cell}; + }; + return callback; + case 'inline': + /** + * Callback to format the data as inline data, with a list for each + * session inside of a cell for the candidate. + * + * @param {string} label - The table header + * @param {string} cell - The cell value + * @param {string[]} row - The entire row + * @param {string[]} headers - The entire row's headers + * @param {number} fieldNo - the cell index + * @returns {React.ReactElement} - The table cell + */ + callback = ( + label: string, + cell: string, + row: TableRow, + headers: string[], + fieldNo: number + ): ReactNode => { + // if candidate -- return directly + // if session -- get visits from query def, put in + const fieldobj = fields[fieldNo]; + const fielddict = getDictionary(fieldobj, dict); + if (fielddict === null) { + return null; + } + if (fielddict.scope == 'candidate' + && fielddict.cardinality != 'many') { + if (cell === '') { + return (No data); + } + + return ; + } + let val; + if (fielddict.scope == 'session') { + let displayedVisits: string[]; + if (fields[fieldNo] && fields[fieldNo].visits) { + // need to explicitly tell typescript it's defined otherwise + // it thinks visits is string[]|undefined + displayedVisits = fields[fieldNo].visits as string[]; + } else { + // All visits + if (fielddict.visits) { + displayedVisits = fielddict.visits; + } else { + displayedVisits = []; + } + } + + val = displayedVisits.map((visit) => { + /** + * Maps the JSON value from the session to a list of + * values to display to the user + * + * @param {string} visit - The visit label + * @param {string} cell - The JSON returned by the API + * for this cell + * @returns {React.ReactElement} - The HTML list react element + */ + const visitval = (visit: string, cell: string) => { + if (cell === '') { + return (No data); + } + try { + const json = JSON.parse(cell); + for (const sessionid in json) { + if (json[sessionid].VisitLabel == visit) { + if (fielddict.cardinality === 'many') { + return valuesList( + json[sessionid].values + ); + } else { + return json[sessionid].value; + } + } + } + } catch (e) { + return (Internal error); + } + return (No data); + }; + return (
    +
    {visit} +
    +
    + {visitval(visit, cell)} +
    +
    ); + }); + } else { + return FIXME: {cell}; + } + const value = (
    + {val} +
    ); + return {value}; + }; + return callback; + case 'longitudinal': + /** + * Callback to organize this data longitudinally + * + * @param {string} label - The header label + * @param {string} cell - the JSON value of the cell + * @param {string[]} row - the entire row + * @param {string[]} headers - the headers for the table + * @param {number} fieldNo - The field number of this cell + * @returns {React.ReactElement} - The table cell + */ + callback = ( + label: string, + cell: string, + row: TableRow, + headers: string[], + fieldNo: number + ): ReactNode => { + const cells = expandLongitudinalCells(cell, fieldNo, fields, dict); + if (cells === null) { + return null; + } + return <>{cells.map((val: string|null) => { + if (val === null) { + return (No data); + } + return ; + })}; + }; + return callback; + case 'crosssection': + /** + * Callback that organizes data cross-sectionally + * + * @param {string} label - The label for the column + * @param {string} cell - The raw cell value returned by the API. + * @returns {React.ReactElement} - The table cell for this cell. + */ + callback = (label: string, cell: JSONString): ReactNode => { + if (cell === null) { + return No data for visit; + } + return ; + }; + return callback; + } +} + +/** + * Get the data dictionary for a specific field + * + * @param {APIQueryField} fieldobj - The field in the format of props.fields + * @param {FullDictionary} dict - the full data dictionary + * @returns {FieldDictionary?} - The field dictionary for this field + */ +function getDictionary( + fieldobj: APIQueryField, + dict: FullDictionary, +): FieldDictionary|null { + if (!dict || !fieldobj + || !dict[fieldobj.module] + || !dict[fieldobj.module][fieldobj.category] + || !dict[fieldobj.module][fieldobj.category][fieldobj.field] + ) { + return null; + } + return dict[fieldobj.module][fieldobj.category][fieldobj.field]; +} + +/** + * Return a cardinality many values field as a list + * + * @param {object} values - values object with keys as id + * @returns {React.ReactElement} - The values in an HTML list + */ +function valuesList(values: KeyedValue[]) { + const items = Object.values(values).map((val) => { + return
  • {val.value}
  • ; + }); + return (
      + {items} +
    ); +} + +type VisitOrgType = 'raw' | 'inline' | 'longitudinal' | 'crosssection'; +type HeaderDisplayType = 'fieldname' | 'fielddesc' | 'fieldnamedesc'; +/** + * Generate the appropriate table headers based on the visit + * organization + * + * @param {array} fields - the selected fields + * @param {string} org - the visit organization + * @param {string} display - the header display format + * @param {object} fulldict - the data dictionary + * @param {function} onProgress - Callback to indicate progress in processing + * @returns {array} - A promise which resolves to the array of headers to display + * in the frontend table + */ +function organizeHeaders( + fields: APIQueryField[], + org: VisitOrgType, + display: HeaderDisplayType, + fulldict: FullDictionary, + onProgress: (i: number) => void): Promise { + /** + * Format a header according to the selected display type + * + * @param {APIQueryField} header - The header to format + * @returns {string} - The string to display to the user + */ + const formatHeader = (header: APIQueryField): string => { + switch (display) { + case 'fieldname': return header.field; + case 'fielddesc': return getDictionaryDescription( + header.module, + header.category, + header.field, + fulldict + ); + case 'fieldnamedesc': return header.field + + ': ' + getDictionaryDescription( + header.module, + header.category, + header.field, + fulldict + ); + default: + throw new Error('Unhandled field display type'); + } + }; + switch (org) { + case 'raw': + return Promise.resolve(fields.map((val, i) => { + onProgress(i); + return formatHeader(val); + })); + case 'inline': + return Promise.resolve(fields.map((val, i) => { + onProgress(i); + return formatHeader(val); + })); + case 'longitudinal': + const headers: string[] = []; + let i = 0; + for (const field of fields) { + i++; + const dict = getDictionary(field, fulldict); + + if (dict === null) { + headers.push('Internal Error'); + } else if (dict.scope == 'candidate') { + headers.push(formatHeader(field)); + } else { + if (typeof field.visits !== 'undefined') { + for (const visit of field.visits) { + headers.push(formatHeader(field) + ': ' + visit); + } + } + } + onProgress(i); + } + // Split session level selections into multiple headers + return Promise.resolve(headers); + case 'crosssection': + return new Promise( (resolve) => { + setTimeout( () => { + resolve(['Visit Label', + ...fields.map((val, i) => { + onProgress(i); + return formatHeader(val); + }), + ]); + }); + }); + default: throw new Error('Unhandled visit organization'); + } +} + +export default ViewData; diff --git a/modules/dataquery/jsx/welcome.adminquerymodal.tsx b/modules/dataquery/jsx/welcome.adminquerymodal.tsx new file mode 100644 index 00000000000..959750ccf6c --- /dev/null +++ b/modules/dataquery/jsx/welcome.adminquerymodal.tsx @@ -0,0 +1,95 @@ +import Modal from 'jsx/Modal'; +import swal from 'sweetalert2'; +import {useState} from 'react'; +import {CheckboxElement, TextboxElement, FieldsetElement} from 'jsx/Form'; + +/** + * Render a modal window for naming a query + * + * @param {object} props - React props + * @param {number} props.QueryID - The QueryID being modified + * @param {string} props.defaultName - The default name to show before edited by the user + * @param {function} props.closeModal - A callback to close the modal + * @param {function} props.onSubmit - A callback to call on submit + * @returns {React.ReactElement} - The modal + */ +function AdminQueryModal(props: { + QueryID: number, + defaultName: string, + closeModal: () => void, + onSubmit: (name: string, topQuery: boolean, dashboardQuery: boolean) + => void, +}) { + const [queryName, setQueryName] = useState(props.defaultName || ''); + const [topQuery, setTopQuery] = useState(true); + const [dashboardQuery, setDashboardQuery] = useState(true); + /** + * Convert the onSubmit callback to a promise function of the format + * expected by jsx/Modal. + * + * @returns {Promise} - The promise + */ + const submitPromise = () => { + let sbmt: Promise = new Promise((resolve, reject) => { + if (queryName.trim() == '') { + swal.fire({ + type: 'error', + text: 'Must provide a query name to pin query as.', + }); + reject(); + return; + } + if (!topQuery && !dashboardQuery) { + swal.fire({ + type: 'error', + text: 'Must pin as study query or pin to dashboard.', + }); + reject(); + return; + } + resolve([queryName.trim(), topQuery, dashboardQuery]); + }); + if (props.onSubmit) { + sbmt = sbmt.then((val: [string, boolean, boolean]) => { + const [name, topq, dashq] = val; + props.onSubmit(name, topq, dashq); + }); + } + return sbmt; + }; + return +
    + + setQueryName(value) + } + /> + setTopQuery(value) + } + label='Pin Study Query' + /> + + setDashboardQuery(value) + } + /> + +
    +
    ; +} + +export default AdminQueryModal; diff --git a/modules/dataquery/jsx/welcome.namequerymodal.tsx b/modules/dataquery/jsx/welcome.namequerymodal.tsx new file mode 100644 index 00000000000..78c28a4c618 --- /dev/null +++ b/modules/dataquery/jsx/welcome.namequerymodal.tsx @@ -0,0 +1,65 @@ +import Modal from 'jsx/Modal'; +import swal from 'sweetalert2'; +import {useState} from 'react'; +import {TextboxElement, FieldsetElement} from 'jsx/Form'; + +/** + * Render a modal window for naming a query + * + * @param {object} props - React props + * @param {number} props.QueryID - The QueryID being modified + * @param {string} props.defaultName - The default name to show before edited by the user + * @param {function} props.closeModal - A callback to close the modal + * @param {function} props.onSubmit - A callback to call on submit + * @returns {React.ReactElement} - the query modal element + */ +function NameQueryModal(props: { + QueryID: number, + defaultName: string, + closeModal: () => void, + onSubmit: (name: string) => void, +}) { + const [queryName, setQueryName] = useState(props.defaultName || ''); + /** + * Convert the onSubmit callback function to a promise expected by Modal + * + * @returns {Promise} - The submit promise + */ + const submitPromise = (): Promise => { + const sbmt = new Promise((resolve, reject) => { + if (queryName == '') { + swal.fire({ + type: 'error', + text: 'Must provide a query name.', + }); + reject(); + return; + } + resolve(queryName); + }); + if (props.onSubmit) { + return sbmt.then(props.onSubmit); + } + return sbmt; + }; + return +
    + + setQueryName(value) + } + /> + +
    +
    ; +} + +export default NameQueryModal; diff --git a/modules/dataquery/jsx/welcome.tsx b/modules/dataquery/jsx/welcome.tsx new file mode 100644 index 00000000000..0e05b9c34de --- /dev/null +++ b/modules/dataquery/jsx/welcome.tsx @@ -0,0 +1,1116 @@ +import ExpansionPanels from './components/expansionpanels'; +import swal from 'sweetalert2'; +import FieldDisplay from './fielddisplay'; +import {useEffect, useState} from 'react'; +import QueryTree from './querytree'; +import {QueryTerm, QueryGroup} from './querydef'; +import NameQueryModal from './welcome.namequerymodal'; +import AdminQueryModal from './welcome.adminquerymodal'; +import getDictionaryDescription from './getdictionarydescription'; +import PaginationLinks from 'jsx/PaginationLinks'; +import {ButtonElement, CheckboxElement, TextboxElement} from 'jsx/Form'; +import {APIQueryField} from './types'; +import {FullDictionary} from './types'; +import {FlattenedField, FlattenedQuery, VisitOption} from './types'; +/** + * Return the welcome tab for the DQT + * + * @param {object} props - React props + * @param {FlattenedQuery[]} props.recentQueries - List of recent queries to display + * @param {FlattenedQuery[]} props.topQueries - List of top queries to display pinned to the top of the tab + * @param {FlattenedQuery[]} props.sharedQueries - List of queries shared with the current user + * @param {function} props.onContinue - Callback when the "Continue" button is called in the welcome message + * @param {boolean} props.useAdminName - True if the display should display the admin name of the query + * @param {boolean} props.queryAdmin - True if the current user can pin study queries + * @param {function} props.reloadQueries - Reload the list of queries from the server + * @param {function} props.loadQuery - Load a query to replace the active query + * @param {function} props.starQuery - Function that will star a query + * @param {function} props.unstarQuery - Function that will unstar a query + * @param {function} props.shareQuery - Function that will share a query + * @param {function} props.unshareQuery - Function that will unshare a query + * @param {function} props.getModuleFields - Retrieve a module's fields from the backend and populate them into fulldictionary + * @param {object} props.mapModuleName - Function to map the backend module name to a user friendly name + * @param {object} props.mapCategoryName - Function to map the backend category name to a user friendly name + * @param {object} props.fulldictionary - The dictionary of all modules that have been loaded + * @returns {React.ReactElement} - The Welcome tab element + */ +function Welcome(props: { + recentQueries: FlattenedQuery[] + sharedQueries: FlattenedQuery[], + topQueries: FlattenedQuery[], + + queryAdmin: boolean, + + onContinue: () => void, + reloadQueries: () => void, + shareQuery: (queryID: number) => void, + unshareQuery: (queryID: number) => void, + starQuery: (queryID: number) => void, + unstarQuery: (queryID: number) => void, + getModuleFields: (module: string) => void, + loadQuery: (fields: APIQueryField[], filters: QueryGroup|null) => void, + mapModuleName: (module: string) => string, + mapCategoryName: (module: string, category: string) => string, + fulldictionary:FullDictionary, +}) { + const panels: { + title: string, + content: React.ReactElement, + alwaysOpen: boolean, + defaultOpen: boolean, + }[] = []; + if (props.topQueries.length > 0) { + panels.push({ + title: 'Study Queries', + content: ( +
    + +
    + ), + alwaysOpen: false, + defaultOpen: true, + }); + } + panels.push({ + title: 'Instructions', + content: 0} + onContinue={props.onContinue} + />, + alwaysOpen: false, + defaultOpen: true, + }); + panels.push({ + title: 'Recent Queries', + content: ( +
    + +
    + ), + alwaysOpen: false, + defaultOpen: true, + }); + + if (props.sharedQueries.length > 0) { + panels.push({ + title: 'Shared Queries', + content: ( +
    + +
    + ), + alwaysOpen: false, + defaultOpen: true, + }); + } + + return ( +
    +

    + Welcome to the Data Query Tool +

    + +
    + ); +} + +/** + * Display a list of queries + * + * @param {object} props - React props + * @param {FlattenedQuery[]} props.queries - The list of queries to show in the list + * @param {boolean} props.queryAdmin - True if the current user can pin study queries + * @param {boolean} props.defaultCollapsed - True if the queries should default to be collapsed + * @param {function} props.starQuery - Function that will star a query + * @param {function} props.unstarQuery - Function that will unstar a query + * @param {function} props.shareQuery - Function that will share a query + * @param {function} props.unshareQuery - Function that will unshare a query + * @param {function} props.loadQuery - Load a query to replace the active query + * @param {function} props.reloadQueries - Reload the list of queries from the server + * @param {function} props.getModuleFields - Retrieve a module's fields from the backend and populate them into fulldictionary + * @param {object} props.mapModuleName - Function to map the backend module name to a user friendly name + * @param {object} props.mapCategoryName - Function to map the backend category name to a user friendly name + * @param {FullDictionary} props.fulldictionary - The dictionary of all modules that have been loaded + * @returns {React.ReactElement} - The React element + */ +function QueryList(props: { + queries: FlattenedQuery[], + defaultCollapsed: boolean, + + useAdminName: boolean, + queryAdmin: boolean, + + starQuery?: (queryID: number) => void, + unstarQuery?: (queryID: number) => void, + shareQuery?: (queryID: number) => void, + unshareQuery?: (queryID: number) => void, + + reloadQueries?: () => void, + loadQuery: (fields: APIQueryField[], filters: QueryGroup|null) => void, + + getModuleFields: (module: string) => void, + mapModuleName: (module: string) => string, + mapCategoryName: (module: string, category: string) => string, + fulldictionary:FullDictionary, +}) { + const [nameModalID, setNameModalID] = useState(null); + const [adminModalID, setAdminModalID] = useState(null); + const [queryName, setQueryName] = useState(null); + const [defaultModalQueryName, setDefaultModalQueryName] + = useState(''); + + const [onlyStarred, setOnlyStarred] = useState(false); + const [onlyShared, setOnlyShared] = useState(false); + const [onlyNamed, setOnlyNamed] = useState(false); + const [noDuplicates, setNoDuplicates] = useState(false); + const [queryFilter, setQueryFilter] = useState(''); + const [fullQuery, setFullQuery] + = useState(!props.defaultCollapsed); + const [unpinAdminQuery, setUnpinAdminQuery] = useState(null); + const [adminPinAction, setAdminPinAction] + = useState<'top'|'dashboard'|'top,dashboard'>('top'); + + useEffect(() => { + const modules = new Set(); + props.queries.forEach((query) => { + query.fields.forEach((field) => { + modules.add(field.module); + }); + if (query.criteria) { + /** + * Add all modules used in the QueryGroup to the modules + * set so their fields can be fetched. + * + * @param {QueryGroup} querygroup - The query group from the criteria + * @returns {void} + */ + const addModules = (querygroup: QueryGroup) => { + querygroup.group.forEach((item) => { + if (item instanceof QueryTerm) { + modules.add(item.module); + } else if (item instanceof QueryGroup) { + addModules(item); + } + }); + }; + addModules(query.criteria); + } + }); + modules.forEach((module: string) => { + props.getModuleFields(module); + }); + }, [props.queries]); + + useEffect(() => { + if (!nameModalID || !queryName) { + return; + } + + // Prevent re-triggering by resetting the state + // before fetching, cache the values we need + // to build the URI before setting + const id = nameModalID; + const name = queryName; + + setNameModalID(null); + setQueryName(null); + + fetch( + '/dataquery/queries/' + id + + '?name=' + encodeURIComponent(name), + { + method: 'PATCH', + credentials: 'same-origin', + }, + ).then((response) => { + setQueryName(null); + if (response.ok) { + if (props.reloadQueries) { + props.reloadQueries(); + } + } + }); + }, [queryName]); + + useEffect(() => { + if (!adminModalID || !queryName) { + return; + } + + // Prevent re-triggering by resetting the state + // before fetching, cache the values we need + // to build the URI before setting + const id = adminModalID; + const name = queryName; + + setAdminModalID(null); + setQueryName(null); + + let param; + if (adminPinAction == 'top') { + param = 'adminname=' + encodeURIComponent(name); + } else if (adminPinAction == 'dashboard') { + param = 'dashboardname=' + encodeURIComponent(name); + } else if (adminPinAction == 'top,dashboard') { + param = 'adminname=' + encodeURIComponent(name) + + '&dashboardname=' + encodeURIComponent(name); + } + fetch( + '/dataquery/queries/' + id + + '?' + param, + { + method: 'PATCH', + credentials: 'same-origin', + }, + ).then((response) => { + if (response.ok) { + if (props.reloadQueries) { + props.reloadQueries(); + } + } + }); + }, [queryName]); + + useEffect(() => { + if (!unpinAdminQuery) { + return; + } + + // Prevent re-triggering by resetting the state + // before fetching, cache the values we need + // to build the URI before setting + const id = unpinAdminQuery; + setUnpinAdminQuery(null); + + fetch( + '/dataquery/queries/' + id + + '?adminname=', + { + method: 'PATCH', + credentials: 'same-origin', + }, + ).then((response) => { + if (response.ok) { + if (props.reloadQueries) { + props.reloadQueries(); + } + } + }); + }, [unpinAdminQuery]); + + const nameModal: React.ReactNode = ( + nameModalID == null + ? null + : setQueryName(name)} + closeModal={() => setNameModalID(null) } + defaultName={defaultModalQueryName} + QueryID={nameModalID} + />); + const adminModal = adminModalID == null ? '' : + { + if (topQ && dashboardQ) { + setAdminPinAction('top,dashboard'); + } else if (topQ) { + setAdminPinAction('top'); + } else if (dashboardQ) { + setAdminPinAction('dashboard'); + } else { + throw new Error('Modal promise should not have resolved'); + } + setQueryName(name); + }} + closeModal={() => setAdminModalID(null)} + defaultName={defaultModalQueryName} + QueryID={adminModalID} + />; + + let displayedQueries = props.queries; + if (onlyStarred === true) { + displayedQueries = displayedQueries.filter( + (val) => val.Starred + ); + } + if (onlyShared === true) { + displayedQueries = displayedQueries.filter( + (val) => val.Public + ); + } + if (onlyNamed === true) { + displayedQueries = displayedQueries.filter( + (val) => { + if (val.Name || val.Name == '') { + return true; + } + return false; + } + ); + } + if (noDuplicates === true) { + const queryList: {[queryID: number]: FlattenedQuery} = {}; + const newDisplayedQueries: FlattenedQuery[] = []; + displayedQueries.forEach((val) => { + if (queryList.hasOwnProperty(val.QueryID)) { + return; + } + queryList[val.QueryID] = val; + newDisplayedQueries.push(val); + }); + displayedQueries = newDisplayedQueries; + } + if (queryFilter != '') { + displayedQueries = displayedQueries.filter( + (val) => { + const lowerQF = queryFilter.toLowerCase(); + const nameContains = val.Name + && val.Name.toLowerCase().includes(lowerQF); + const runTimeContains = val.RunTime && + val.RunTime.includes(lowerQF); + const sharedByContains = val.SharedBy && + val.SharedBy.map( (s) => s.toLowerCase()).includes(lowerQF); + let anyFieldMatches = false; + let anyFilterMatches = false; + if (val.fields) { + for (const field of val.fields) { + if (field.field.toLowerCase().includes(lowerQF)) { + anyFieldMatches = true; + break; + } + const description = getDictionaryDescription( + field.module, + field.category, + field.field, + props.fulldictionary, + ); + if (description.toLowerCase().includes(lowerQF)) { + anyFieldMatches = true; + break; + } + } + } + if (val.criteria) { + /** + * Sets the anyFieldMatches variable to true if any + * criteria in the QueryGroup matches the filter criteria. + * + * @param {QueryGroup} group - The query group being checked + * @returns {void} + */ + const itemInGroupMatches = (group: QueryGroup): void => { + for (const field of group.group) { + if (field instanceof QueryTerm) { + if (field.fieldname + && field.fieldname.toLowerCase().includes( + lowerQF + )) { + anyFieldMatches = true; + return; + } + const description = getDictionaryDescription( + field.module, + field.category, + field.fieldname, + props.fulldictionary, + ); + if (description + && description.toLowerCase().includes( + lowerQF + ) + ) { + anyFilterMatches = true; + return; + } + } else if (field instanceof QueryGroup) { + itemInGroupMatches(field); + } + } + }; + itemInGroupMatches(val.criteria); + } + return nameContains + || runTimeContains + || sharedByContains + || anyFieldMatches + || anyFilterMatches; + }); + } + const starFilter = props.starQuery ? + setOnlyStarred(value) + }/> : ; + const shareFilter = props.shareQuery ? + setOnlyShared(value) + }/> + : ; + // Use whether shareQuery prop is defined as proxy + // to determine if this is a shared query or a recent + // query list + const duplicateFilter = props.shareQuery ? + setNoDuplicates(value) + }/> + : ; + return (
    + {nameModal} + {adminModal} +
    + setQueryFilter(value) + }/> +
    + {starFilter} + {shareFilter} + setOnlyNamed(value) + }/> + {duplicateFilter} + + setFullQuery(!value) + }/> +
    +
    + + {displayedQueries.map((query, idx) => { + return { + return; + } + } + + unstarQuery={props.unstarQuery ? + props.unstarQuery : + () => { + return; + } + } + + shareQuery={props.shareQuery ? + props.shareQuery : + () => { + return; + } + } + unshareQuery={ + props.unshareQuery ? + props.unshareQuery : + () => { + return; + } + } + + setNameModalID={setNameModalID} + setDefaultModalQueryName={setDefaultModalQueryName} + setAdminModalID={setAdminModalID} + + queryAdmin={props.queryAdmin} + unpinAdminQuery={setUnpinAdminQuery} + fulldictionary={props.fulldictionary} + />; + })} + +
    ); +} + +/** + * A single list item in a saved/shared query + * + * @param {object} props - React props + * @param {function} props.mapModuleName - Function to map the backend module name to a user friendly name + * @param {function} props.mapCategoryName - Function to map the backend category name to a user friendly name + * @param {FullDictionary} props.fulldictionary - The dictionary of all modules that have been loaded + * @param {QueryGroup} props.criteria - The query criteria. + * @returns {React.ReactElement} - The React element + */ +function QueryListCriteria(props: { + mapModuleName: (module: string) => string, + mapCategoryName: (module: string, category: string) => string, + fulldictionary: FullDictionary, + criteria: QueryGroup +}) { + if (!props.criteria || !props.criteria.group + || props.criteria.group.length == 0) { + return (No filters for query); + } + return (); +} + +/** + * Paginate the results + * + * @param {object} props - React props + * @param {React.ReactElement[]} props.children - The elements to page + * @returns {React.ReactElement} - The React element + */ +function Pager(props: { + children: React.ReactElement[], +}) { + const [pageNum, setPageNum] = useState(1); + const rowsPerPage = 5; + + const start = (pageNum-1)*rowsPerPage; + const end = (pageNum)*rowsPerPage; + const displayedRange = props.children.slice(start, end); + return
    + + {displayedRange} + +
    ; +} + +/** + * Display a single query in a QueryList + * + * @param {object} props - React props + * @param {FlattenedQuery} props.query - The query to display + * @param {boolean} props.includeRuns - True if query run information should be displayed + * @param {function} props.starQuery - Function that will star a query + * @param {function} props.unstarQuery - Function that will unstar a query + * @param {function} props.shareQuery - Function that will share a query + * @param {function} props.unshareQuery - Function that will unshare a query + * @param {function} props.unpinAdminQuery - Function that will unpin a query + * @param {function} props.loadQuery - Load a query to replace the active query + * @param {function} props.setDefaultModalQueryName - Function to set the default name to show in the name query modal + * @param {function} props.setNameModalID - Function that will set the queryID to show a name modal for + * @param {boolean} props.showFullQueryDefault - True if the query should be expanded by default + * @param {boolean} props.queryAdmin - True if the admin query options (ie. pin query) should be shown + * @param {function} props.setAdminModalID - Function that will set the queryID to show an admin modal for + * @param {object} props.mapModuleName - Function to map the backend module name to a user friendly name + * @param {object} props.mapCategoryName - Function to map the backend category name to a user friendly name + * @param {object} props.fulldictionary The dictionary of all modules that have been loaded + * @returns {React.ReactElement} - The React element + */ +function SingleQueryDisplay(props: { + query: FlattenedQuery, + loadQuery: (fields: APIQueryField[], filters: QueryGroup|null) => void, + includeRuns: boolean, + showFullQueryDefault: boolean, + + shareQuery: (queryID: number) => void, + unshareQuery: (queryID: number) => void, + starQuery: (queryID: number) => void, + unstarQuery: (queryID: number) => void, + + useAdminName: boolean, + + queryAdmin: boolean, + unpinAdminQuery: (queryID: number) => void, + setAdminModalID: (queryID: number) => void, + setDefaultModalQueryName: (name: string) => void, + setNameModalID: (queryID: number) => void, + + mapModuleName: (module: string) => string, + mapCategoryName: (module: string, category: string) => string, + fulldictionary:FullDictionary, +}) { + const [showFullQuery, setShowFullQuery] = + useState(props.showFullQueryDefault); + // Reset the collapsed state if the checkbox gets toggled + useEffect(() => { + setShowFullQuery(props.showFullQueryDefault); + }, [props.showFullQueryDefault]); + + let starredIcon; + let sharedIcon; + const query = props.query; + + if (query.Starred) { + starredIcon = props.unstarQuery(query.QueryID) + } + title="Unstar" + className="fa-stack"> + + + ; + } else { + starredIcon = props.starQuery(query.QueryID) + } + className="fa-stack"> + + ; + } + + if (query.Public) { + sharedIcon = + props.unshareQuery(query.QueryID) + } + />; + } else { + sharedIcon = + props.shareQuery(query.QueryID) + } + />; + } + + /** + * Load this query as the current query, replacing whatever query + * is currently loaded. + */ + const loadQuery = () => { + const newfields: APIQueryField[] = query.fields.map( + (field: FlattenedField) => { + const f: APIQueryField = { + module: field.module, + category: field.category, + field: field.field, + }; + if (field.visits) { + f.visits = field.visits.map( + (visit: VisitOption) => visit.value + ); + } + return f; + }); + props.loadQuery( + newfields, + query.criteria || null, + ); + swal.fire({ + type: 'success', + title: 'Query Loaded', + text: 'Successfully loaded query.', + }); + }; + + const loadIcon = ; + + const pinIcon = props.queryAdmin + ? { + props.setDefaultModalQueryName(query.Name || ''); + props.setAdminModalID(query.QueryID); + } + }> + + + :
    ; + + let msg: React.ReactNode = null; + if (query.RunTime) { + let desc = query.Name + ? + {query.Name} +  (Run at {query.RunTime}) + + : You ran this query at {query.RunTime}; + if (!props.includeRuns) { + desc = query.Name + ? + {query.Name} + + : You ran this query; + } + + const nameIcon = { + props.setDefaultModalQueryName(query.Name || ''); + props.setNameModalID(query.QueryID); + }} />; + msg =
    {desc} +  {starredIcon}{sharedIcon}{loadIcon}{nameIcon}{pinIcon} +
    ; + } else if (query.SharedBy) { + const desc = query.Name + ? + {query.Name} +  (Shared by {query.SharedBy.join(', ')}) + + : Query shared by {query.SharedBy.join(', ')}; + msg =
    {desc} +  {loadIcon}{pinIcon} +
    ; + } else if (query.Name || query.AdminName) { + const name = props.useAdminName ? query.AdminName : query.Name; + const unpinIcon = props.queryAdmin + ? { + props.unpinAdminQuery(query.QueryID); + } + }> + + + + :
    ; + msg =
    {name} {loadIcon}{unpinIcon}
    ; + } else { + console.error('Invalid query. Neither shared nor recent', query); + } + + const queryDisplay = !showFullQuery ?
    : +
    +
    +

    Fields

    + {query.fields.map( + (fieldobj, fidx) => + + )} +
    + {query.criteria ? +
    +

    Filters

    + +
    + :
    + } +
    ; + const expandIcon = setShowFullQuery(!showFullQuery)} + >; + return (
    +
    + {expandIcon} + {msg} +
    + {queryDisplay} +
    +
    ); +} + +/** + * Display a list of Query Runs + * + * @param {object} props - React props + * @param {array} props.queryruns - A list of query runs as returned by the API + * @param {boolean} props.queryAdmin - True if the current user can pin study queries + * @param {boolean} props.defaultCollapsed - True if the queries should not be expanded by default + * @param {function} props.starQuery - Function that will star a query + * @param {function} props.unstarQuery - Function that will unstar a query + * @param {function} props.shareQuery - Function that will share a query + * @param {function} props.unshareQuery - Function that will unshare a query + * @param {function} props.reloadQueries - Reload the list of queries from the server + * @param {function} props.loadQuery - Load a query to replace the active query + * @param {function} props.getModuleFields - Retrieve a module's fields from the backend and populate them into fulldictionary + * @param {function} props.mapModuleName - Function to map the backend module name to a user friendly name + * @param {function} props.mapCategoryName - Function to map the backend category name to a user friendly name + * @param {FullDictionary} props.fulldictionary The dictionary of all modules that have been loaded + * @returns {React.ReactElement} - The React element + */ +function QueryRunList(props:{ + queryruns: FlattenedQuery[], + + queryAdmin: boolean, + + defaultCollapsed: boolean, + + starQuery: (queryID: number) => void, + unstarQuery: (queryID: number) => void, + shareQuery: (queryID: number) => void, + unshareQuery: (queryID: number) => void, + + reloadQueries: () => void, + loadQuery: (fields: APIQueryField[], filters: QueryGroup|null) => void, + + getModuleFields: (module: string) => void, + mapModuleName: (module: string) => string, + mapCategoryName: (module: string, category: string) => string, + fulldictionary:FullDictionary, +}) { + // When was written there wasn't a clear distinction between + // runs and queries, so we need to flatten all the information into a single + // object that it thinks is a query and not a query run. + const queries: FlattenedQuery[] = props.queryruns; + + return (); +} + +/** + * An icon to load a query + * + * @param {object} props - React props + * @param {function} props.onClick - Handler to call when icon clicked + * @returns {React.ReactElement} - The React element + */ +function LoadIcon(props: { + onClick?: () => void, +}) { + return + + ; +} + +/** + * An icon to share a query + * + * @param {object} props - React props + * @param {function} props.onClick - Handler to call when icon clicked + * @param {function} props.title - the title to show on hover + * @param {function} props.isShared - True if the query is currently shared + * @returns {React.ReactElement} - The React element + */ +function ShareIcon(props: { + onClick?: () => void, + title?: string, + isShared?: boolean, +}) { + return + + ; +} + +/** + * An icon to name a query + * + * @param {object} props - React props + * @param {function} props.onClick - Handler to call when icon clicked + * @returns {React.ReactElement} - The React element + */ +function NameIcon(props: { + onClick?: () => void +}): React.ReactElement { + return ( + + ); +} + +/** + * Displays the message for the introduction panel + * + * @param {object} props - React props + * @param {function} props.onContinue - Action to take when "Continue" button is pressed + * @param {boolean} props.hasStudyQueries - Whether or not study queries exist + * @returns {React.ReactElement} - The React element + */ +function IntroductionMessage(props: { + onContinue: () => void, + hasStudyQueries: boolean, +}): React.ReactElement { + const studyQueriesParagraph = props.hasStudyQueries ? ( +

    Above, there is also a Study Queries panel. This + are a special type of shared queries that have been pinned + by a study administer to always display at the top of this + page.

    + ) : ''; + return ( +
    +

    The data query tool allows you to query data + within LORIS. There are three steps to defining + a query: +

    +
      +
    1. First, you must select the fields that you're + interested in on the Define Fields + page.
    2. +
    3. Next, you can optionally define filters on the + Define Filters page to restrict + the population that is returned.
    4. +
    5. Finally, you view your query results on + the View Data page
    6. +
    +

    The Next Steps on the bottom right of your + screen always the context-sensitive next steps that you + can do to build your query.

    +

    Your recently run queries will be displayed in the + Recent Queries panel below. Instead of building + a new query, you can reload a query that you've recently run + by clicking on the icon next to the query.

    +

    Queries can be shared with others by clicking the + icon. This will cause the query to be shared with all users who + have access to the fields used by the query. It will display + in a Shared Queries panel below the + Recent Queries.

    +

    You may also give a query a name at any time by clicking the + icon. This makes it easier to find queries you care + about by giving them an easier to remember name that can be used + for filtering. When you share a query, the name will be shared + along with it.

    + {studyQueriesParagraph} +
    + +
    +
    + ); +} +export default Welcome; diff --git a/modules/dataquery/php/dataquery.class.inc b/modules/dataquery/php/dataquery.class.inc new file mode 100644 index 00000000000..28537105030 --- /dev/null +++ b/modules/dataquery/php/dataquery.class.inc @@ -0,0 +1,63 @@ + + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ +namespace LORIS\dataquery; + +/** + * Data Querying Module + * + * PHP Version 7 + * + * @category Module + * @package Loris + * @subpackage DQT + * @author Loris Team + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ +class Dataquery extends \NDB_Page +{ + public $skipTemplate = true; + + /** + * Check user access permission + * + * @param \User $user The user whose access is being checked + * + * @return bool + */ + function _hasAccess(\User $user) : bool + { + // check user permissions + return $user->hasPermission('dataquery_view'); + } + + /** + * Include the column formatter required to display the feedback link colours + * in the candidate_list menu + * + * @return array of javascript to be inserted + */ + function getJSDependencies() + { + $factory = \NDB_Factory::singleton(); + $baseURL = $factory->settings()->getBaseURL(); + $deps = parent::getJSDependencies(); + return array_merge( + $deps, + [ + $baseURL . "/dataquery/js/index.js", + ] + ); + } +} diff --git a/modules/dataquery/php/module.class.inc b/modules/dataquery/php/module.class.inc index ce8ebe98788..a3e0c10aed5 100644 --- a/modules/dataquery/php/module.class.inc +++ b/modules/dataquery/php/module.class.inc @@ -49,4 +49,80 @@ class Module extends \Module { return true; } + + /** + * {@inheritDoc} + * + * @param string $type The type of widgets to get. + * @param \User $user The user widgets are being retrieved for. + * @param array $options A type dependent list of options to provide + * to the widget. + * + * @return \LORIS\GUI\Widget[] + */ + public function getWidgets(string $type, \User $user, array $options) + { + switch ($type) { + case 'dashboard': + $baseURL = \NDB_Factory::singleton()->settings()->getBaseURL(); + $provisioner = ( + new Provisioners\StarredQueries($this->loris, $user) + )->filter( + new \LORIS\Data\Filters\AccessibleResourceFilter() + ); + $results = $provisioner->execute($user); + $starredqueries = []; + foreach ($results as $query) { + $starredqueries[] = $query; + } + $widgets = []; + if (count($starredqueries) > 0) { + $widgets[] = new \LORIS\dashboard\Widget( + new \LORIS\dashboard\WidgetContent( + "Starred Queries", + $this->renderTemplate( + "starredwidget.tpl", + [ + 'baseURL' => $baseURL, + 'starredqueries' => $starredqueries, + ] + ), + "" + ), + new \LORIS\dashboard\WidgetDisplayProps("small"), + ); + } + + $provisioner = ( + new Provisioners\StudyQueries($this->loris, 'dashboard') + )->filter( + new \LORIS\Data\Filters\AccessibleResourceFilter() + ); + + $results = $provisioner->execute($user); + $studyqueries = []; + foreach ($results as $query) { + $studyqueries[] = $query; + + } + if (count($studyqueries) > 0) { + $widgets[] = new \LORIS\dashboard\Widget( + new \LORIS\dashboard\WidgetContent( + "Study Queries", + $this->renderTemplate( + "studyquerieswidget.tpl", + [ + 'baseURL' => $baseURL, + 'queries' => $studyqueries, + ] + ), + "" + ), + new \LORIS\dashboard\WidgetDisplayProps("small"), + ); + } + return $widgets; + } + return []; + } } diff --git a/modules/dataquery/php/provisioners/alluserqueries.class.inc b/modules/dataquery/php/provisioners/alluserqueries.class.inc index 84869e1f6c9..dc99533b056 100644 --- a/modules/dataquery/php/provisioners/alluserqueries.class.inc +++ b/modules/dataquery/php/provisioners/alluserqueries.class.inc @@ -36,7 +36,7 @@ class AllUserQueries extends \LORIS\Data\Provisioners\DBRowProvisioner (dq.QueryID=dsq.QueryID AND PinType='topquery') -- Public queries LEFT JOIN dataquery_shared_queries_rel dshq ON - (dq.QueryID=dshq.QueryID AND dshq.SharedBy != :userid) + (dq.QueryID=dshq.QueryID) LEFT JOIN users u ON (dshq.SharedBy=u.ID) LEFT JOIN dataquery_starred_queries_rel starred ON (starred.QueryID=dq.QueryID AND starred.StarredBy = :userid) diff --git a/modules/dataquery/php/provisioners/starredqueries.class.inc b/modules/dataquery/php/provisioners/starredqueries.class.inc new file mode 100644 index 00000000000..78bb8657d51 --- /dev/null +++ b/modules/dataquery/php/provisioners/starredqueries.class.inc @@ -0,0 +1,61 @@ + + */ + +namespace LORIS\dataquery\Provisioners; +use \LORIS\dataquery\Query; + +/** + * Provisioner to get all starred queries for a given user + * + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + */ +class StarredQueries extends \LORIS\Data\Provisioners\DBRowProvisioner +{ + /** + * Create a StarredQueries provisioner, which gets rows for + * the starred user queries for a given user. + * + * @param protected \LORIS\LorisInstance $loris - The LORIS object + * @param \User $user - The user whose starred + * queries should be retrieved + */ + function __construct(protected \LORIS\LorisInstance $loris, \User $user) + { + parent::__construct( + "SELECT + dpq.QueryID, + COALESCE(dqn.Name, CONCAT('Query ', dpq.QueryID)) as Name + FROM dataquery_starred_queries_rel dpq + JOIN dataquery_queries dq + ON (dq.QueryID=dpq.QueryID) + LEFT JOIN dataquery_query_names dqn + ON (dpq.StarredBy=dqn.UserID AND dpq.QueryID=dqn.QueryID) + WHERE dpq.StarredBy=:userid", + ['userid' => $user->getId()] + ); + } + + /** + * {@inheritDoc} + * + * @param array $row The database row from the LORIS Database class. + * + * @return \LORIS\Data\DataInstance An instance representing this row. + */ + public function getInstance($row) : \LORIS\Data\DataInstance + { + return new Query( + loris: $this->loris, + queryID: $row['QueryID'] !== null + ? intval($row['QueryID']) + : null, + name: $row['Name'], + ); + } +} diff --git a/modules/dataquery/php/provisioners/studyqueries.class.inc b/modules/dataquery/php/provisioners/studyqueries.class.inc new file mode 100644 index 00000000000..8ac9421482f --- /dev/null +++ b/modules/dataquery/php/provisioners/studyqueries.class.inc @@ -0,0 +1,52 @@ + $pintype], + ); + } + + /** + * {@inheritDoc} + * + * @param array $row The database row from the LORIS Database class. + * + * @return \LORIS\Data\DataInstance An instance representing this row. + */ + public function getInstance($row) : \LORIS\Data\DataInstance + { + return new Query( + loris: $this->loris, + queryID: $row['QueryID'] !== null + ? intval($row['QueryID']) + : null, + query: json_decode($row['Query'], true), + name: $row['Name'], + ); + } +} diff --git a/modules/dataquery/php/query.class.inc b/modules/dataquery/php/query.class.inc index 44aa9f7366f..40f4bfab2e2 100644 --- a/modules/dataquery/php/query.class.inc +++ b/modules/dataquery/php/query.class.inc @@ -47,7 +47,7 @@ class Query implements \LORIS\StudyEntities\AccessibleResource, protected \LORIS\LorisInstance $loris, public readonly int $queryID, ?array $query=null, - protected ?string $name=null, + public ?string $name=null, protected ?string $adminname=null, protected ?array $sharedBy=null, protected ?bool $starred=null, diff --git a/modules/dataquery/php/visitlist.class.inc b/modules/dataquery/php/visitlist.class.inc new file mode 100644 index 00000000000..9826e3cfc85 --- /dev/null +++ b/modules/dataquery/php/visitlist.class.inc @@ -0,0 +1,94 @@ +dictionaryitem === null) { + return new \LORIS\Http\Response\JSON\OK( + [ + 'Visits' => array_values(\Utility::getVisitList()), + ], + ); + } + + if ($this->dictionaryitem->getScope()->__toString() !== 'session') { + return new \LORIS\Http\Response\JSON\BadRequest( + 'Visit list only applicable to session scoped variables' + ); + } + + return new \LORIS\Http\Response\JSON\OK( + [ + 'Visits' => + $this->itemmodule + ->getQueryEngine() + ->getVisitList($this->itemcategory, $this->dictionaryitem), + ], + ); + } + + /** + * {@inheritDoc} + * + * @param \User $user - The user loading the page + * @param ServerRequestInterface $request - The page to load resources for + * + * @return void + */ + public function loadResources( + \User $user, + ServerRequestInterface $request, + ) : void { + $queryparams = $request->getQueryParams(); + if (!isset($queryparams['module']) || !isset($queryparams['item'])) { + return; + } + + $modules = $this->loris->getActiveModules(); + + foreach ($modules as $module) { + if ($module->getName() !== $queryparams['module']) { + continue; + } + if (!$module->hasAccess($user)) { + continue; + } + + $this->itemmodule = $module; + $mdict = $module->getQueryEngine()->getDataDictionary(); + + if (count($mdict) > 0) { + foreach ($mdict as $cat) { + foreach ($cat->getItems() as $dictitem) { + if ($dictitem->getName() === $queryparams['item']) { + $this->dictionaryitem = $dictitem; + $this->itemcategory = $cat; + } + } + } + } + } + } +} diff --git a/modules/dataquery/templates/starredwidget.tpl b/modules/dataquery/templates/starredwidget.tpl new file mode 100644 index 00000000000..6641cfd8737 --- /dev/null +++ b/modules/dataquery/templates/starredwidget.tpl @@ -0,0 +1,15 @@ +
    + {foreach from=$starredqueries item=query} + + + + + + {$query->name} + + {/foreach} +
    diff --git a/modules/dataquery/templates/studyquerieswidget.tpl b/modules/dataquery/templates/studyquerieswidget.tpl new file mode 100644 index 00000000000..689f135dce9 --- /dev/null +++ b/modules/dataquery/templates/studyquerieswidget.tpl @@ -0,0 +1,42 @@ + + +
    +Note: matches count only includes candidates that you have access to. Results may vary from other users due to permissions. +
    diff --git a/modules/instruments/php/instrumentqueryengine.class.inc b/modules/instruments/php/instrumentqueryengine.class.inc index cb779a16ed4..6bba9117b99 100644 --- a/modules/instruments/php/instrumentqueryengine.class.inc +++ b/modules/instruments/php/instrumentqueryengine.class.inc @@ -326,8 +326,8 @@ class InstrumentQueryEngine implements \LORIS\Data\Query\QueryEngine ); $insertstmt = "INSERT INTO querycandidates VALUES (" /* see https://github.com/phan/phan/issues/4746 - * @phan-suppress-next-line PhanTypeMismatchArgumentInternal */ - . join('),(', iterator_to_array($candidates)) + * @phan-suppress-next-line PhanParamSpecial1 */ + . join('),(', $candidates) . ')'; $q = $DB->prepare($insertstmt); @@ -408,10 +408,12 @@ class InstrumentQueryEngine implements \LORIS\Data\Query\QueryEngine // Go through each field and put the data in the right // index if applicable. $data = $instrData->current(); - foreach ($data as $key => $val) { - $candidateData[$key][] = $val; + foreach ($data as $fieldkey=> $sessionobjs) { + foreach ($sessionobjs as $sessionID => $val) { + assert(!isset($candidateData[$fieldkey][$sessionID])); + $candidateData[$fieldkey][$sessionID] = $val; + } } - // $candidateData = array_merge($candidateData, $data); $instrData->next(); $instCandidate = $instrData->key(); } @@ -451,8 +453,12 @@ class InstrumentQueryEngine implements \LORIS\Data\Query\QueryEngine if (!isset($candData[$dict->getName()])) { $candData[$dict->getName()] = []; } - $candData[$dict->getName()][] - = $loadedInstrument->getDictionaryValue($dict); + $sid = $loadedInstrument->getSessionID(); + $candData[$dict->getName()][$sid->__toString()] = [ + 'VisitLabel' => $loadedInstrument->getVisitLabel(), + 'SessionID' => $sid->__toString(), + 'value' => $loadedInstrument->getDictionaryValue($dict), + ]; } } yield "$iCandID" => $candData; diff --git a/package-lock.json b/package-lock.json index 65a13bd955e..fae1d75c198 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "loris", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -36,6 +36,7 @@ "@babel/preset-react": "^7.6.3", "@types/c3": "^0.7.8", "@types/d3": "^7.4.0", + "@types/papaparse": "^5.3.11", "@types/react": "^18.0.26", "@types/react-dom": "^18.0.9", "@types/react-redux": "7.1.16", @@ -101,8 +102,7 @@ }, "node_modules/@babel/code-frame": { "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "license": "MIT", "dependencies": { "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" @@ -173,8 +173,7 @@ }, "node_modules/@babel/generator": { "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "license": "MIT", "dependencies": { "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", @@ -288,8 +287,7 @@ }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -307,8 +305,7 @@ }, "node_modules/@babel/helper-function-name": { "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "license": "MIT", "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -319,8 +316,7 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -439,8 +435,7 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -450,16 +445,14 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -499,8 +492,7 @@ }, "node_modules/@babel/highlight": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -512,8 +504,7 @@ }, "node_modules/@babel/parser": { "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -1666,8 +1657,7 @@ }, "node_modules/@babel/template": { "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/parser": "^7.22.15", @@ -1679,8 +1669,7 @@ }, "node_modules/@babel/traverse": { "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", @@ -1699,8 +1688,7 @@ }, "node_modules/@babel/types": { "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20", @@ -1720,8 +1708,7 @@ }, "node_modules/@emotion/babel-plugin": { "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", - "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", @@ -1738,8 +1725,7 @@ }, "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -1749,16 +1735,14 @@ }, "node_modules/@emotion/babel-plugin/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/@emotion/cache": { "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", - "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.8.0", "@emotion/sheet": "^1.2.1", @@ -1769,18 +1753,15 @@ }, "node_modules/@emotion/hash": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + "license": "MIT" }, "node_modules/@emotion/memoize": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "license": "MIT" }, "node_modules/@emotion/react": { "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", - "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.10.6", @@ -1802,8 +1783,7 @@ }, "node_modules/@emotion/serialize": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.0", "@emotion/memoize": "^0.8.0", @@ -1814,31 +1794,26 @@ }, "node_modules/@emotion/sheet": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + "license": "MIT" }, "node_modules/@emotion/unitless": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "license": "MIT", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + "license": "MIT" }, "node_modules/@emotion/weak-memoize": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + "license": "MIT" }, "node_modules/@es-joy/jsdoccomment": { "version": "0.36.1", @@ -1910,13 +1885,11 @@ }, "node_modules/@floating-ui/core": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.4.tgz", - "integrity": "sha512-SQOeVbMwb1di+mVWWJLpsUTToKfqVNioXys011beCAhyOIFtS+GQoW4EQSneuxzmQKddExDwQ+X0hLl4lJJaSQ==" + "license": "MIT" }, "node_modules/@floating-ui/dom": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.4.tgz", - "integrity": "sha512-4+k+BLhtWj+peCU60gp0+rHeR8+Ohqx6kjJf/lHMnJ8JD5Qj6jytcq1+SZzRwD7rvHKRhR7TDiWWddrNrfwQLg==", + "license": "MIT", "dependencies": { "@floating-ui/core": "^1.2.3" } @@ -1998,8 +1971,7 @@ }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2067,9 +2039,8 @@ }, "node_modules/@npmcli/config/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2208,18 +2179,16 @@ }, "node_modules/@types/c3": { "version": "0.7.8", - "resolved": "https://registry.npmjs.org/@types/c3/-/c3-0.7.8.tgz", - "integrity": "sha512-qUhbhHIa7SzpDZVHTUx51XUKPzkG3xLHKZGhwvfIs5Fy3NSc8qtH8I1u6N3Dp44Ih54qyUMw6xTIiDuOUBanxA==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3": "^4" } }, "node_modules/@types/c3/node_modules/@types/d3": { "version": "4.13.12", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-4.13.12.tgz", - "integrity": "sha512-/bbFtkOBc04gGGN8N9rMG5ps3T0eIj5I8bnYe9iIyeM5qoOrydPCbFYlEPUnj2h9ibc2i+QZfDam9jY5XTrTxQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-array": "^1", "@types/d3-axis": "^1", @@ -2255,183 +2224,157 @@ }, "node_modules/@types/c3/node_modules/@types/d3-array": { "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.9.tgz", - "integrity": "sha512-E/7RgPr2ylT5dWG0CswMi9NpFcjIEDqLcUSBgNHe/EMahfqYaTx4zhcggG3khqoEB/leY4Vl6nTSbwLUPjXceA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-axis": { "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.16.tgz", - "integrity": "sha512-p7085weOmo4W+DzlRRVC/7OI/jugaKbVa6WMQGCQscaMylcbuaVEGk7abJLNyGVFLeCBNrHTdDiqRGnzvL0nXQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "^1" } }, "node_modules/@types/c3/node_modules/@types/d3-brush": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-1.1.5.tgz", - "integrity": "sha512-4zGkBafJf5zCsBtLtvDj/pNMo5X9+Ii/1hUz0GvQ+wEwelUBm2AbIDAzJnp2hLDFF307o0fhxmmocHclhXC+tw==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "^1" } }, "node_modules/@types/c3/node_modules/@types/d3-chord": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.11.tgz", - "integrity": "sha512-0DdfJ//bxyW3G9Nefwq/LDgazSKNN8NU0lBT3Cza6uVuInC2awMNsAcv1oKyRFLn9z7kXClH5XjwpveZjuz2eg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-color": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.2.tgz", - "integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-dispatch": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-1.0.9.tgz", - "integrity": "sha512-zJ44YgjqALmyps+II7b1mZLhrtfV/FOxw9owT87mrweGWcg+WK5oiJX2M3SYJ0XUAExBduarysfgbR11YxzojQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-drag": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.5.tgz", - "integrity": "sha512-7NeTnfolst1Js3Vs7myctBkmJWu6DMI3k597AaHUX98saHjHWJ6vouT83UrpE+xfbSceHV+8A0JgxuwgqgmqWw==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "^1" } }, "node_modules/@types/c3/node_modules/@types/d3-dsv": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.2.1.tgz", - "integrity": "sha512-LLmJmjiqp/fTNEdij5bIwUJ6P6TVNk5hKM9/uk5RPO2YNgEu9XvKO0dJ7Iqd3psEdmZN1m7gB1bOsjr4HmO2BA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-ease": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-1.0.11.tgz", - "integrity": "sha512-wUigPL0kleGZ9u3RhzBP07lxxkMcUjL5IODP42mN/05UNL+JJCDnpEPpFbJiPvLcTeRKGIRpBBJyP/1BNwYsVA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-force": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.2.4.tgz", - "integrity": "sha512-fkorLTKvt6AQbFBQwn4aq7h9rJ4c7ZVcPMGB8X6eFFveAyMZcv7t7m6wgF4Eg93rkPgPORU7sAho1QSHNcZu6w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-format": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.4.2.tgz", - "integrity": "sha512-WeGCHAs7PHdZYq6lwl/+jsl+Nfc1J2W1kNcMeIMYzQsT6mtBDBgtJ/rcdjZ0k0rVIvqEZqhhuD5TK/v3P2gFHQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-geo": { "version": "1.12.3", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-1.12.3.tgz", - "integrity": "sha512-yZbPb7/5DyL/pXkeOmZ7L5ySpuGr4H48t1cuALjnJy5sXQqmSSAYBiwa6Ya/XpWKX2rJqGDDubmh3nOaopOpeA==", "dev": true, + "license": "MIT", "dependencies": { "@types/geojson": "*" } }, "node_modules/@types/c3/node_modules/@types/d3-hierarchy": { "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz", - "integrity": "sha512-AbStKxNyWiMDQPGDguG2Kuhlq1Sv539pZSxYbx4UZeYkutpPwXCcgyiRrlV4YH64nIOsKx7XVnOMy9O7rJsXkg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-interpolate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz", - "integrity": "sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-color": "^1" } }, "node_modules/@types/c3/node_modules/@types/d3-path": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-polygon": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-1.0.8.tgz", - "integrity": "sha512-1TOJPXCBJC9V3+K3tGbTqD/CsqLyv/YkTXAcwdsZzxqw5cvpdnCuDl42M4Dvi8XzMxZNCT9pL4ibrK2n4VmAcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-quadtree": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-1.0.9.tgz", - "integrity": "sha512-5E0OJJn2QVavITFEc1AQlI8gLcIoDZcTKOD3feKFckQVmFV4CXhqRFt83tYNVNIN4ZzRkjlAMavJa1ldMhf5rA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-random": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-1.1.3.tgz", - "integrity": "sha512-XXR+ZbFCoOd4peXSMYJzwk0/elP37WWAzS/DG+90eilzVbUSsgKhBcWqylGWe+lA2ubgr7afWAOBaBxRgMUrBQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-scale": { "version": "1.0.17", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-1.0.17.tgz", - "integrity": "sha512-baIP5/gw+PS8Axs1lfZCeIjcOXen/jxQmgFEjbYThwaj2drvivOIrJMh2Ig4MeenrogCH6zkhiOxCPRkvN1scA==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-time": "^1" } }, "node_modules/@types/c3/node_modules/@types/d3-selection": { "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.4.3.tgz", - "integrity": "sha512-GjKQWVZO6Sa96HiKO6R93VBE8DUW+DDkFpIMf9vpY5S78qZTlRRSNUsHr/afDpF7TvLDV7VxrUFOWW7vdIlYkA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-shape": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.8.tgz", - "integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-path": "^1" } }, "node_modules/@types/c3/node_modules/@types/d3-time": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.1.1.tgz", - "integrity": "sha512-ULX7LoqXTCYtM+tLYOaeAJK7IwCT+4Gxlm2MaH0ErKLi07R5lh8NHCAyWcDkCCmx1AfRcBEV6H9QE9R25uP7jw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-time-format": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.3.1.tgz", - "integrity": "sha512-fck0Z9RGfIQn3GJIEKVrp15h9m6Vlg0d5XXeiE/6+CQiBmMDZxfR21XtjEPuDeg7gC3bBM0SdieA5XF3GW1wKA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-timer": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-ZnAbquVqy+4ZjdW0cY6URp+qF/AzTVNda2jYyOzpR2cPT35FTXl78s15Bomph9+ckOiI1TtkljnWkwbIGAb6rg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/c3/node_modules/@types/d3-transition": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-J+a3SuF/E7wXbOSN19p8ZieQSFIm5hU2Egqtndbc54LXaAEOpLfDx4sBu/PKAKzHOdgKK1wkMhINKqNh4aoZAg==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "^1" } }, "node_modules/@types/c3/node_modules/@types/d3-zoom": { "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.8.3.tgz", - "integrity": "sha512-3kHkL6sPiDdbfGhzlp5gIHyu3kULhtnHTTAl3UBZVtWB1PzcLL8vdmz5mTx7plLiUqOA2Y+yT2GKjt/TdA2p7Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-interpolate": "^1", "@types/d3-selection": "^1" @@ -2447,9 +2390,8 @@ }, "node_modules/@types/d3": { "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz", - "integrity": "sha512-jIfNVK0ZlxcuRDKtRS/SypEyOQ6UHaFQBKv032X45VvxSJ6Yi5G9behy9h6tNTHTDGh5Vq+KbmBjUWLgY4meCA==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", @@ -2485,51 +2427,44 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-axis": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.1.tgz", - "integrity": "sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-brush": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.1.tgz", - "integrity": "sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-chord": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-collection": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-collection/-/d3-collection-1.0.10.tgz", - "integrity": "sha512-54Fdv8u5JbuXymtmXm2SYzi1x/Svt+jfWBU5junkhrCewL92VjqtCBDn97coBRVwVFmYNnVTNDyV8gQyPYfm+A==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-contour": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.1.tgz", - "integrity": "sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" @@ -2537,195 +2472,167 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-dispatch": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-drag": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.1.tgz", - "integrity": "sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-dsv": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.0.tgz", - "integrity": "sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-ease": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", - "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-fetch": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-dsv": "*" } }, "node_modules/@types/d3-force": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.3.tgz", - "integrity": "sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-geo": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.2.tgz", - "integrity": "sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/geojson": "*" } }, "node_modules/@types/d3-hierarchy": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.0.tgz", - "integrity": "sha512-g+sey7qrCa3UbsQlMZZBOHROkFqx7KZKvUpRzI/tAp/8erZWpYq7FgNKvYwebi2LaEiVs1klhUfd3WCThxmmWQ==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-color": "*" } }, "node_modules/@types/d3-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", - "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-polygon": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", - "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-quadtree": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", - "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-queue": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-queue/-/d3-queue-3.0.8.tgz", - "integrity": "sha512-1FWOiI/MYwS5Z1Sa9EvS1Xet3isiVIIX5ozD6iGnwHonGcqL+RcC1eThXN5VfDmAiYt9Me9EWNEv/9J9k9RIKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-random": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-request": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-4nRKDUBg3EBx8VowpMvM3NAVMiMMI1qFUOYv3OJsclGjHX6xjtu09nsWhRQ0fvSUla3MEjb5Ch4IeaYarMEi1w==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-dsv": "^1" } }, "node_modules/@types/d3-request/node_modules/@types/d3-dsv": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.2.1.tgz", - "integrity": "sha512-LLmJmjiqp/fTNEdij5bIwUJ6P6TVNk5hKM9/uk5RPO2YNgEu9XvKO0dJ7Iqd3psEdmZN1m7gB1bOsjr4HmO2BA==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-time": "*" } }, "node_modules/@types/d3-scale-chromatic": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-selection": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.3.tgz", - "integrity": "sha512-Mw5cf6nlW1MlefpD9zrshZ+DAWL4IQ5LnWfRheW6xwsdaWOb6IRRu2H7XPAQcyXEx1D7XQWgdoKR83ui1/HlEA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-shape": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.0.tgz", - "integrity": "sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-path": "*" } }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-time-format": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", - "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-timer": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", - "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-transition": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.2.tgz", - "integrity": "sha512-jo5o/Rf+/u6uerJ/963Dc39NI16FQzqwOc54bwvksGAdVfvDrqDpVeq95bEvPtBwLCVZutAEyAtmSyEMxN7vxQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-voronoi": { "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.9.tgz", - "integrity": "sha512-DExNQkaHd1F3dFPvGA/Aw2NGyjMln6E9QzsiqOcBgnE+VInYnFBHBBySbZQts6z6xD+5jTfKCP7M4OqMyVjdwQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/d3-zoom": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz", - "integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" @@ -2769,9 +2676,8 @@ }, "node_modules/@types/geojson": { "version": "7946.0.10", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", - "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/hast": { "version": "2.3.4", @@ -2838,10 +2744,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/papaparse": { + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.11.tgz", + "integrity": "sha512-ISil0lMkpRDrBTKRPnUgVb5IqxWwj19gWBrX/ROk3pbkkslBN3URa713r/BSfAUj+w9gTPg3S3f45aMToVfh1w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/parse-json": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + "license": "MIT" }, "node_modules/@types/parse5": { "version": "6.0.3", @@ -2882,8 +2796,7 @@ }, "node_modules/@types/react-transition-group": { "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "license": "MIT", "dependencies": { "@types/react": "*" } @@ -2948,9 +2861,8 @@ }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3096,9 +3008,8 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3169,9 +3080,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3655,8 +3565,7 @@ }, "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==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -4341,8 +4250,7 @@ }, "node_modules/cosmiconfig": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -4356,8 +4264,7 @@ }, "node_modules/cosmiconfig/node_modules/yaml": { "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", "engines": { "node": ">= 6" } @@ -4402,9 +4309,8 @@ }, "node_modules/css-loader": { "version": "6.8.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", - "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.21", @@ -4428,9 +4334,8 @@ }, "node_modules/css-loader/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -4443,9 +4348,8 @@ }, "node_modules/cssesc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -4915,8 +4819,7 @@ }, "node_modules/dom-helpers": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" @@ -5291,9 +5194,8 @@ }, "node_modules/eslint-plugin-jsdoc/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5525,9 +5427,8 @@ }, "node_modules/eslint/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5798,8 +5699,7 @@ }, "node_modules/find-root": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + "license": "MIT" }, "node_modules/find-up": { "version": "4.1.0", @@ -6425,9 +6325,8 @@ }, "node_modules/icss-utils": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -7255,9 +7154,8 @@ }, "node_modules/make-dir/node_modules/semver": { "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -7611,8 +7509,7 @@ }, "node_modules/memoize-one": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + "license": "MIT" }, "node_modules/memory-fs": { "version": "0.5.0", @@ -8465,8 +8362,6 @@ }, "node_modules/nanoid": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true, "funding": [ { @@ -8474,6 +8369,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -8619,9 +8515,8 @@ }, "node_modules/normalize-package-data/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -8853,9 +8748,8 @@ }, "node_modules/package-json/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -9019,8 +8913,7 @@ }, "node_modules/picocolors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -9061,8 +8954,6 @@ }, "node_modules/postcss": { "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -9078,6 +8969,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -9089,9 +8981,8 @@ }, "node_modules/postcss-modules-extract-imports": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -9101,9 +8992,8 @@ }, "node_modules/postcss-modules-local-by-default": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -9118,9 +9008,8 @@ }, "node_modules/postcss-modules-scope": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", "dev": true, + "license": "ISC", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -9133,9 +9022,8 @@ }, "node_modules/postcss-modules-values": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -9148,9 +9036,8 @@ }, "node_modules/postcss-selector-parser": { "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -9161,9 +9048,8 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -9596,8 +9482,7 @@ }, "node_modules/react-select": { "version": "5.7.0", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.0.tgz", - "integrity": "sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.0", "@emotion/cache": "^11.4.0", @@ -9616,8 +9501,7 @@ }, "node_modules/react-transition-group": { "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -9771,9 +9655,8 @@ }, "node_modules/read-pkg/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -10346,8 +10229,7 @@ }, "node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -10368,9 +10250,8 @@ }, "node_modules/semver-diff/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -10508,9 +10389,8 @@ }, "node_modules/source-map-js": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -10834,8 +10714,7 @@ }, "node_modules/stylis": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", - "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + "license": "MIT" }, "node_modules/supports-color": { "version": "5.5.0", @@ -10859,8 +10738,7 @@ }, "node_modules/swagger-ui-dist": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz", - "integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ==" + "license": "Apache-2.0" }, "node_modules/sweetalert2": { "version": "8.19.0", @@ -11153,9 +11031,8 @@ }, "node_modules/ts-loader/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -11760,9 +11637,8 @@ }, "node_modules/update-notifier/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -11782,8 +11658,7 @@ }, "node_modules/use-isomorphic-layout-effect": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" }, @@ -12011,8 +11886,7 @@ }, "node_modules/webpack": { "version": "5.76.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz", - "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==", + "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -12283,9 +12157,8 @@ }, "node_modules/word-wrap": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -12404,9 +12277,8 @@ }, "node_modules/yaml": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", "dev": true, + "license": "ISC", "engines": { "node": ">= 14" } @@ -12439,7880 +12311,5 @@ "url": "https://github.com/sponsors/wooorm" } } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/cli": { - "version": "7.19.3", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.8", - "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", - "chokidar": "^3.4.0", - "commander": "^4.0.1", - "convert-source-map": "^1.1.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.2.0", - "make-dir": "^2.1.0", - "slash": "^2.0.0" - } - }, - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - } - }, - "@babel/compat-data": { - "version": "7.19.3" - }, - "@babel/core": { - "version": "7.19.3", - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.3", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.3", - "@babel/types": "^7.19.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - } - }, - "@babel/eslint-parser": { - "version": "7.19.1", - "dev": true, - "requires": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "requires": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.19.3", - "requires": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.19.0", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.19.0", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.1.0" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.19.0" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-replace-supers": { - "version": "7.19.1", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" - }, - "@babel/helper-validator-option": { - "version": "7.18.6" - }, - "@babel/helper-wrap-function": { - "version": "7.19.0", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/helpers": { - "version": "7.19.0", - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", - "@babel/plugin-proposal-optional-chaining": "^7.18.9" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.19.1", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/compat-data": "^7.18.8", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.18.8" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-import-assertions": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.19.0", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.18.13", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.18.8", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.19.0", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-identifier": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.1", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.18.8", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.19.0", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.19.0" - } - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/plugin-transform-react-jsx": "^7.18.6" - } - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "regenerator-transform": "^0.15.0" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.19.1", - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.19.0", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/preset-env": { - "version": "7.19.3", - "dev": true, - "requires": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.1", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-classes": "^7.19.0", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.18.13", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.0", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.8", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.19.3", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-react": { - "version": "7.18.6", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-react-display-name": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.6", - "@babel/plugin-transform-react-jsx-development": "^7.18.6", - "@babel/plugin-transform-react-pure-annotations": "^7.18.6" - } - }, - "@babel/runtime": { - "version": "7.19.0", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - }, - "@discoveryjs/json-ext": { - "version": "0.5.7", - "dev": true - }, - "@emotion/babel-plugin": { - "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", - "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/serialize": "^1.1.1", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.1.3" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - } - } - }, - "@emotion/cache": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", - "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", - "requires": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.1", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.1.3" - } - }, - "@emotion/hash": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" - }, - "@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" - }, - "@emotion/react": { - "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", - "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", - "requires": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.10.6", - "@emotion/cache": "^11.10.5", - "@emotion/serialize": "^1.1.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "hoist-non-react-statics": "^3.3.1" - } - }, - "@emotion/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", - "requires": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", - "csstype": "^3.0.2" - } - }, - "@emotion/sheet": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" - }, - "@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" - }, - "@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", - "requires": {} - }, - "@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" - }, - "@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" - }, - "@es-joy/jsdoccomment": { - "version": "0.36.1", - "dev": true, - "requires": { - "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" - } - }, - "@eslint/eslintrc": { - "version": "0.4.3", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "13.17.0", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "dev": true - } - } - }, - "@floating-ui/core": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.4.tgz", - "integrity": "sha512-SQOeVbMwb1di+mVWWJLpsUTToKfqVNioXys011beCAhyOIFtS+GQoW4EQSneuxzmQKddExDwQ+X0hLl4lJJaSQ==" - }, - "@floating-ui/dom": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.4.tgz", - "integrity": "sha512-4+k+BLhtWj+peCU60gp0+rHeR8+Ohqx6kjJf/lHMnJ8JD5Qj6jytcq1+SZzRwD7rvHKRhR7TDiWWddrNrfwQLg==", - "requires": { - "@floating-ui/core": "^1.2.3" - } - }, - "@fortawesome/fontawesome-free": { - "version": "5.15.4" - }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0" - }, - "@jridgewell/set-array": { - "version": "1.1.2" - }, - "@jridgewell/source-map": { - "version": "0.3.2", - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@nicolo-ribaudo/chokidar-2": { - "version": "2.1.8-no-fsevents.3", - "dev": true, - "optional": true - }, - "@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "dev": true, - "requires": { - "eslint-scope": "5.1.1" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@npmcli/config": { - "version": "6.1.3", - "dev": true, - "requires": { - "@npmcli/map-workspaces": "^3.0.2", - "ini": "^3.0.0", - "nopt": "^7.0.0", - "proc-log": "^3.0.0", - "read-package-json-fast": "^3.0.2", - "semver": "^7.3.5", - "walk-up-path": "^1.0.0" - }, - "dependencies": { - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@npmcli/map-workspaces": { - "version": "3.0.2", - "dev": true, - "requires": { - "@npmcli/name-from-folder": "^2.0.0", - "glob": "^8.0.1", - "minimatch": "^6.1.6", - "read-package-json-fast": "^3.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "8.1.0", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "dependencies": { - "minimatch": { - "version": "5.1.6", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "minimatch": { - "version": "6.1.8", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "@npmcli/name-from-folder": { - "version": "2.0.0", - "dev": true - }, - "@pnpm/network.ca-file": { - "version": "1.0.2", - "dev": true, - "requires": { - "graceful-fs": "4.2.10" - } - }, - "@pnpm/npm-conf": { - "version": "1.0.5", - "dev": true, - "requires": { - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - } - }, - "@sindresorhus/is": { - "version": "5.3.0", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "5.0.1", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.1" - } - }, - "@types/acorn": { - "version": "4.0.6", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "@types/c3": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/@types/c3/-/c3-0.7.8.tgz", - "integrity": "sha512-qUhbhHIa7SzpDZVHTUx51XUKPzkG3xLHKZGhwvfIs5Fy3NSc8qtH8I1u6N3Dp44Ih54qyUMw6xTIiDuOUBanxA==", - "dev": true, - "requires": { - "@types/d3": "^4" - }, - "dependencies": { - "@types/d3": { - "version": "4.13.12", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-4.13.12.tgz", - "integrity": "sha512-/bbFtkOBc04gGGN8N9rMG5ps3T0eIj5I8bnYe9iIyeM5qoOrydPCbFYlEPUnj2h9ibc2i+QZfDam9jY5XTrTxQ==", - "dev": true, - "requires": { - "@types/d3-array": "^1", - "@types/d3-axis": "^1", - "@types/d3-brush": "^1", - "@types/d3-chord": "^1", - "@types/d3-collection": "*", - "@types/d3-color": "^1", - "@types/d3-dispatch": "^1", - "@types/d3-drag": "^1", - "@types/d3-dsv": "^1", - "@types/d3-ease": "^1", - "@types/d3-force": "^1", - "@types/d3-format": "^1", - "@types/d3-geo": "^1", - "@types/d3-hierarchy": "^1", - "@types/d3-interpolate": "^1", - "@types/d3-path": "^1", - "@types/d3-polygon": "^1", - "@types/d3-quadtree": "^1", - "@types/d3-queue": "*", - "@types/d3-random": "^1", - "@types/d3-request": "*", - "@types/d3-scale": "^1", - "@types/d3-selection": "^1", - "@types/d3-shape": "^1", - "@types/d3-time": "^1", - "@types/d3-time-format": "^2", - "@types/d3-timer": "^1", - "@types/d3-transition": "^1", - "@types/d3-voronoi": "*", - "@types/d3-zoom": "^1" - } - }, - "@types/d3-array": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.9.tgz", - "integrity": "sha512-E/7RgPr2ylT5dWG0CswMi9NpFcjIEDqLcUSBgNHe/EMahfqYaTx4zhcggG3khqoEB/leY4Vl6nTSbwLUPjXceA==", - "dev": true - }, - "@types/d3-axis": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.16.tgz", - "integrity": "sha512-p7085weOmo4W+DzlRRVC/7OI/jugaKbVa6WMQGCQscaMylcbuaVEGk7abJLNyGVFLeCBNrHTdDiqRGnzvL0nXQ==", - "dev": true, - "requires": { - "@types/d3-selection": "^1" - } - }, - "@types/d3-brush": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-1.1.5.tgz", - "integrity": "sha512-4zGkBafJf5zCsBtLtvDj/pNMo5X9+Ii/1hUz0GvQ+wEwelUBm2AbIDAzJnp2hLDFF307o0fhxmmocHclhXC+tw==", - "dev": true, - "requires": { - "@types/d3-selection": "^1" - } - }, - "@types/d3-chord": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.11.tgz", - "integrity": "sha512-0DdfJ//bxyW3G9Nefwq/LDgazSKNN8NU0lBT3Cza6uVuInC2awMNsAcv1oKyRFLn9z7kXClH5XjwpveZjuz2eg==", - "dev": true - }, - "@types/d3-color": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.2.tgz", - "integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA==", - "dev": true - }, - "@types/d3-dispatch": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-1.0.9.tgz", - "integrity": "sha512-zJ44YgjqALmyps+II7b1mZLhrtfV/FOxw9owT87mrweGWcg+WK5oiJX2M3SYJ0XUAExBduarysfgbR11YxzojQ==", - "dev": true - }, - "@types/d3-drag": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.5.tgz", - "integrity": "sha512-7NeTnfolst1Js3Vs7myctBkmJWu6DMI3k597AaHUX98saHjHWJ6vouT83UrpE+xfbSceHV+8A0JgxuwgqgmqWw==", - "dev": true, - "requires": { - "@types/d3-selection": "^1" - } - }, - "@types/d3-dsv": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.2.1.tgz", - "integrity": "sha512-LLmJmjiqp/fTNEdij5bIwUJ6P6TVNk5hKM9/uk5RPO2YNgEu9XvKO0dJ7Iqd3psEdmZN1m7gB1bOsjr4HmO2BA==", - "dev": true - }, - "@types/d3-ease": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-1.0.11.tgz", - "integrity": "sha512-wUigPL0kleGZ9u3RhzBP07lxxkMcUjL5IODP42mN/05UNL+JJCDnpEPpFbJiPvLcTeRKGIRpBBJyP/1BNwYsVA==", - "dev": true - }, - "@types/d3-force": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.2.4.tgz", - "integrity": "sha512-fkorLTKvt6AQbFBQwn4aq7h9rJ4c7ZVcPMGB8X6eFFveAyMZcv7t7m6wgF4Eg93rkPgPORU7sAho1QSHNcZu6w==", - "dev": true - }, - "@types/d3-format": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.4.2.tgz", - "integrity": "sha512-WeGCHAs7PHdZYq6lwl/+jsl+Nfc1J2W1kNcMeIMYzQsT6mtBDBgtJ/rcdjZ0k0rVIvqEZqhhuD5TK/v3P2gFHQ==", - "dev": true - }, - "@types/d3-geo": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-1.12.3.tgz", - "integrity": "sha512-yZbPb7/5DyL/pXkeOmZ7L5ySpuGr4H48t1cuALjnJy5sXQqmSSAYBiwa6Ya/XpWKX2rJqGDDubmh3nOaopOpeA==", - "dev": true, - "requires": { - "@types/geojson": "*" - } - }, - "@types/d3-hierarchy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz", - "integrity": "sha512-AbStKxNyWiMDQPGDguG2Kuhlq1Sv539pZSxYbx4UZeYkutpPwXCcgyiRrlV4YH64nIOsKx7XVnOMy9O7rJsXkg==", - "dev": true - }, - "@types/d3-interpolate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz", - "integrity": "sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==", - "dev": true, - "requires": { - "@types/d3-color": "^1" - } - }, - "@types/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==", - "dev": true - }, - "@types/d3-polygon": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-1.0.8.tgz", - "integrity": "sha512-1TOJPXCBJC9V3+K3tGbTqD/CsqLyv/YkTXAcwdsZzxqw5cvpdnCuDl42M4Dvi8XzMxZNCT9pL4ibrK2n4VmAcw==", - "dev": true - }, - "@types/d3-quadtree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-1.0.9.tgz", - "integrity": "sha512-5E0OJJn2QVavITFEc1AQlI8gLcIoDZcTKOD3feKFckQVmFV4CXhqRFt83tYNVNIN4ZzRkjlAMavJa1ldMhf5rA==", - "dev": true - }, - "@types/d3-random": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-1.1.3.tgz", - "integrity": "sha512-XXR+ZbFCoOd4peXSMYJzwk0/elP37WWAzS/DG+90eilzVbUSsgKhBcWqylGWe+lA2ubgr7afWAOBaBxRgMUrBQ==", - "dev": true - }, - "@types/d3-scale": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-1.0.17.tgz", - "integrity": "sha512-baIP5/gw+PS8Axs1lfZCeIjcOXen/jxQmgFEjbYThwaj2drvivOIrJMh2Ig4MeenrogCH6zkhiOxCPRkvN1scA==", - "dev": true, - "requires": { - "@types/d3-time": "^1" - } - }, - "@types/d3-selection": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.4.3.tgz", - "integrity": "sha512-GjKQWVZO6Sa96HiKO6R93VBE8DUW+DDkFpIMf9vpY5S78qZTlRRSNUsHr/afDpF7TvLDV7VxrUFOWW7vdIlYkA==", - "dev": true - }, - "@types/d3-shape": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.8.tgz", - "integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==", - "dev": true, - "requires": { - "@types/d3-path": "^1" - } - }, - "@types/d3-time": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.1.1.tgz", - "integrity": "sha512-ULX7LoqXTCYtM+tLYOaeAJK7IwCT+4Gxlm2MaH0ErKLi07R5lh8NHCAyWcDkCCmx1AfRcBEV6H9QE9R25uP7jw==", - "dev": true - }, - "@types/d3-time-format": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.3.1.tgz", - "integrity": "sha512-fck0Z9RGfIQn3GJIEKVrp15h9m6Vlg0d5XXeiE/6+CQiBmMDZxfR21XtjEPuDeg7gC3bBM0SdieA5XF3GW1wKA==", - "dev": true - }, - "@types/d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-ZnAbquVqy+4ZjdW0cY6URp+qF/AzTVNda2jYyOzpR2cPT35FTXl78s15Bomph9+ckOiI1TtkljnWkwbIGAb6rg==", - "dev": true - }, - "@types/d3-transition": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-J+a3SuF/E7wXbOSN19p8ZieQSFIm5hU2Egqtndbc54LXaAEOpLfDx4sBu/PKAKzHOdgKK1wkMhINKqNh4aoZAg==", - "dev": true, - "requires": { - "@types/d3-selection": "^1" - } - }, - "@types/d3-zoom": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.8.3.tgz", - "integrity": "sha512-3kHkL6sPiDdbfGhzlp5gIHyu3kULhtnHTTAl3UBZVtWB1PzcLL8vdmz5mTx7plLiUqOA2Y+yT2GKjt/TdA2p7Q==", - "dev": true, - "requires": { - "@types/d3-interpolate": "^1", - "@types/d3-selection": "^1" - } - } - } - }, - "@types/concat-stream": { - "version": "2.0.0", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/d3": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz", - "integrity": "sha512-jIfNVK0ZlxcuRDKtRS/SypEyOQ6UHaFQBKv032X45VvxSJ6Yi5G9behy9h6tNTHTDGh5Vq+KbmBjUWLgY4meCA==", - "dev": true, - "requires": { - "@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": "*" - } - }, - "@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==", - "dev": true - }, - "@types/d3-axis": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.1.tgz", - "integrity": "sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==", - "dev": true, - "requires": { - "@types/d3-selection": "*" - } - }, - "@types/d3-brush": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.1.tgz", - "integrity": "sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==", - "dev": true, - "requires": { - "@types/d3-selection": "*" - } - }, - "@types/d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==", - "dev": true - }, - "@types/d3-collection": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-collection/-/d3-collection-1.0.10.tgz", - "integrity": "sha512-54Fdv8u5JbuXymtmXm2SYzi1x/Svt+jfWBU5junkhrCewL92VjqtCBDn97coBRVwVFmYNnVTNDyV8gQyPYfm+A==", - "dev": true - }, - "@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==", - "dev": true - }, - "@types/d3-contour": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.1.tgz", - "integrity": "sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==", - "dev": true, - "requires": { - "@types/d3-array": "*", - "@types/geojson": "*" - } - }, - "@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==", - "dev": true - }, - "@types/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==", - "dev": true - }, - "@types/d3-drag": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.1.tgz", - "integrity": "sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==", - "dev": true, - "requires": { - "@types/d3-selection": "*" - } - }, - "@types/d3-dsv": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.0.tgz", - "integrity": "sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==", - "dev": true - }, - "@types/d3-ease": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", - "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==", - "dev": true - }, - "@types/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==", - "dev": true, - "requires": { - "@types/d3-dsv": "*" - } - }, - "@types/d3-force": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.3.tgz", - "integrity": "sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==", - "dev": true - }, - "@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==", - "dev": true - }, - "@types/d3-geo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.2.tgz", - "integrity": "sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==", - "dev": true, - "requires": { - "@types/geojson": "*" - } - }, - "@types/d3-hierarchy": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.0.tgz", - "integrity": "sha512-g+sey7qrCa3UbsQlMZZBOHROkFqx7KZKvUpRzI/tAp/8erZWpYq7FgNKvYwebi2LaEiVs1klhUfd3WCThxmmWQ==", - "dev": true - }, - "@types/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", - "dev": true, - "requires": { - "@types/d3-color": "*" - } - }, - "@types/d3-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", - "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", - "dev": true - }, - "@types/d3-polygon": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", - "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==", - "dev": true - }, - "@types/d3-quadtree": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", - "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==", - "dev": true - }, - "@types/d3-queue": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-queue/-/d3-queue-3.0.8.tgz", - "integrity": "sha512-1FWOiI/MYwS5Z1Sa9EvS1Xet3isiVIIX5ozD6iGnwHonGcqL+RcC1eThXN5VfDmAiYt9Me9EWNEv/9J9k9RIKQ==", - "dev": true - }, - "@types/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==", - "dev": true - }, - "@types/d3-request": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-4nRKDUBg3EBx8VowpMvM3NAVMiMMI1qFUOYv3OJsclGjHX6xjtu09nsWhRQ0fvSUla3MEjb5Ch4IeaYarMEi1w==", - "dev": true, - "requires": { - "@types/d3-dsv": "^1" - }, - "dependencies": { - "@types/d3-dsv": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.2.1.tgz", - "integrity": "sha512-LLmJmjiqp/fTNEdij5bIwUJ6P6TVNk5hKM9/uk5RPO2YNgEu9XvKO0dJ7Iqd3psEdmZN1m7gB1bOsjr4HmO2BA==", - "dev": true - } - } - }, - "@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==", - "dev": true, - "requires": { - "@types/d3-time": "*" - } - }, - "@types/d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", - "dev": true - }, - "@types/d3-selection": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.3.tgz", - "integrity": "sha512-Mw5cf6nlW1MlefpD9zrshZ+DAWL4IQ5LnWfRheW6xwsdaWOb6IRRu2H7XPAQcyXEx1D7XQWgdoKR83ui1/HlEA==", - "dev": true - }, - "@types/d3-shape": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.0.tgz", - "integrity": "sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==", - "dev": true, - "requires": { - "@types/d3-path": "*" - } - }, - "@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==", - "dev": true - }, - "@types/d3-time-format": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", - "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==", - "dev": true - }, - "@types/d3-timer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", - "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==", - "dev": true - }, - "@types/d3-transition": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.2.tgz", - "integrity": "sha512-jo5o/Rf+/u6uerJ/963Dc39NI16FQzqwOc54bwvksGAdVfvDrqDpVeq95bEvPtBwLCVZutAEyAtmSyEMxN7vxQ==", - "dev": true, - "requires": { - "@types/d3-selection": "*" - } - }, - "@types/d3-voronoi": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.9.tgz", - "integrity": "sha512-DExNQkaHd1F3dFPvGA/Aw2NGyjMln6E9QzsiqOcBgnE+VInYnFBHBBySbZQts6z6xD+5jTfKCP7M4OqMyVjdwQ==", - "dev": true - }, - "@types/d3-zoom": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz", - "integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==", - "dev": true, - "requires": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" - } - }, - "@types/debug": { - "version": "4.1.7", - "dev": true, - "requires": { - "@types/ms": "*" - } - }, - "@types/eslint": { - "version": "7.29.0", - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.4", - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "1.0.0" - }, - "@types/estree-jsx": { - "version": "1.0.0", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "@types/geojson": { - "version": "7946.0.10", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", - "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==", - "dev": true - }, - "@types/hast": { - "version": "2.3.4", - "dev": true, - "requires": { - "@types/unist": "*" - } - }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "dev": true, - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "dev": true - }, - "@types/is-empty": { - "version": "1.2.1", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.11" - }, - "@types/mdast": { - "version": "3.0.10", - "requires": { - "@types/unist": "*" - } - }, - "@types/minimist": { - "version": "1.2.2", - "dev": true - }, - "@types/ms": { - "version": "0.7.31", - "dev": true - }, - "@types/nlcst": { - "version": "1.0.0", - "dev": true, - "requires": { - "@types/unist": "*" - } - }, - "@types/node": { - "version": "18.13.0" - }, - "@types/normalize-package-data": { - "version": "2.4.1", - "dev": true - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "@types/parse5": { - "version": "6.0.3", - "dev": true - }, - "@types/prop-types": { - "version": "15.7.5" - }, - "@types/react": { - "version": "18.0.28", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.0.11", - "dev": true, - "requires": { - "@types/react": "*" - } - }, - "@types/react-redux": { - "version": "7.1.16", - "dev": true, - "requires": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, - "@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.2" - }, - "@types/semver": { - "version": "7.3.13", - "dev": true - }, - "@types/supports-color": { - "version": "8.1.1", - "dev": true - }, - "@types/unist": { - "version": "2.0.6" - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.45.0", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/type-utils": "5.45.0", - "@typescript-eslint/utils": "5.45.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "ignore": { - "version": "5.2.1", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/parser": { - "version": "5.45.0", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.45.0", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/visitor-keys": "5.45.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.45.0", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.45.0", - "@typescript-eslint/utils": "5.45.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.45.0", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.45.0", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/visitor-keys": "5.45.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "globby": { - "version": "11.1.0", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "ignore": { - "version": "5.2.1", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "slash": { - "version": "3.0.0", - "dev": true - } - } - }, - "@typescript-eslint/utils": { - "version": "5.45.0", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "dependencies": { - "eslint-utils": { - "version": "3.0.0", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.45.0", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.45.0", - "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.3.0", - "dev": true - } - } - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1" - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1" - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1" - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1" - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1" - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webpack-cli/configtest": { - "version": "1.2.0", - "dev": true, - "requires": {} - }, - "@webpack-cli/info": { - "version": "1.5.0", - "dev": true, - "requires": { - "envinfo": "^7.7.3" - } - }, - "@webpack-cli/serve": { - "version": "1.7.0", - "dev": true, - "requires": {} - }, - "@xtuc/ieee754": { - "version": "1.2.0" - }, - "@xtuc/long": { - "version": "4.2.2" - }, - "abbrev": { - "version": "2.0.0", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "dev": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "2.1.1", - "requires": { - "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.11.0", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0" - } - } - }, - "ajv-keywords": { - "version": "3.5.2", - "requires": {} - }, - "alex": { - "version": "11.0.0", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "@types/nlcst": "^1.0.0", - "meow": "^11.0.0", - "rehype-parse": "^8.0.0", - "rehype-retext": "^3.0.0", - "remark-frontmatter": "^4.0.0", - "remark-gfm": "^3.0.0", - "remark-mdx": "2.0.0", - "remark-message-control": "^7.0.0", - "remark-parse": "^10.0.0", - "remark-retext": "^5.0.0", - "retext-english": "^4.0.0", - "retext-equality": "~6.6.0", - "retext-profanities": "~7.2.0", - "unified": "^10.0.0", - "unified-diff": "^4.0.0", - "unified-engine": "^10.0.0", - "update-notifier": "^6.0.0", - "vfile": "^5.0.0", - "vfile-reporter": "^7.0.0", - "vfile-sort": "^3.0.0" - } - }, - "ansi-align": { - "version": "3.0.1", - "dev": true, - "requires": { - "string-width": "^4.1.0" - } - }, - "ansi-colors": { - "version": "4.1.3", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.2", - "dev": true, - "optional": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "1.0.10", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-includes": { - "version": "3.1.5", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array-iterate": { - "version": "1.1.4", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "dev": true - }, - "array.prototype.flatmap": { - "version": "1.3.0", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - } - }, - "arrify": { - "version": "2.0.1", - "dev": true - }, - "asap": { - "version": "2.0.6" - }, - "astral-regex": { - "version": "2.0.0", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "dev": true - }, - "babel-loader": { - "version": "8.2.5", - "dev": true, - "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "make-dir": { - "version": "3.1.0", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - } - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "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==", - "requires": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - } - }, - "bail": { - "version": "2.0.2", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "dev": true, - "optional": true - }, - "boxen": { - "version": "7.0.1", - "dev": true, - "requires": { - "ansi-align": "^3.0.1", - "camelcase": "^7.0.0", - "chalk": "^5.0.1", - "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "dev": true - }, - "camelcase": { - "version": "7.0.1", - "dev": true - }, - "chalk": { - "version": "5.2.0", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "type-fest": { - "version": "2.19.0", - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.4", - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "bubble-stream-error": { - "version": "1.0.0", - "dev": true, - "requires": { - "once": "^1.3.3", - "sliced": "^1.0.1" - } - }, - "buffer-from": { - "version": "1.1.2" - }, - "c3": { - "version": "0.7.20", - "dev": true, - "requires": { - "d3": "^5.8.0" - } - }, - "cacheable-lookup": { - "version": "7.0.0", - "dev": true - }, - "cacheable-request": { - "version": "10.2.7", - "dev": true, - "requires": { - "@types/http-cache-semantics": "^4.0.1", - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.2", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", - "responselike": "^3.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0" - }, - "camelcase-keys": { - "version": "8.0.2", - "dev": true, - "requires": { - "camelcase": "^7.0.0", - "map-obj": "^4.3.0", - "quick-lru": "^6.1.1", - "type-fest": "^2.13.0" - }, - "dependencies": { - "camelcase": { - "version": "7.0.1", - "dev": true - }, - "type-fest": { - "version": "2.19.0", - "dev": true - } - } - }, - "caniuse-lite": { - "version": "1.0.30001414" - }, - "ccount": { - "version": "2.0.1", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "character-entities": { - "version": "2.0.2", - "dev": true - }, - "character-entities-html4": { - "version": "2.1.0", - "dev": true - }, - "character-entities-legacy": { - "version": "3.0.0", - "dev": true - }, - "character-reference-invalid": { - "version": "2.0.1", - "dev": true - }, - "chokidar": { - "version": "3.5.3", - "dev": true, - "optional": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.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" - } - }, - "chrome-trace-event": { - "version": "1.0.3" - }, - "ci-info": { - "version": "3.8.0", - "dev": true - }, - "cli-boxes": { - "version": "3.0.0", - "dev": true - }, - "clone-deep": { - "version": "4.0.1", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3" - }, - "colorette": { - "version": "2.0.19", - "dev": true - }, - "comma-separated-tokens": { - "version": "2.0.2", - "dev": true - }, - "commander": { - "version": "4.1.1", - "dev": true - }, - "comment-parser": { - "version": "1.3.1", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "dev": true - }, - "concat-stream": { - "version": "2.0.0", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "config-chain": { - "version": "1.1.13", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "dev": true - } - } - }, - "configstore": { - "version": "6.0.0", - "dev": true, - "requires": { - "dot-prop": "^6.0.1", - "graceful-fs": "^4.2.6", - "unique-string": "^3.0.0", - "write-file-atomic": "^3.0.3", - "xdg-basedir": "^5.0.1" - } - }, - "convert-source-map": { - "version": "1.8.0", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copy-webpack-plugin": { - "version": "11.0.0", - "requires": { - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.1", - "globby": "^13.1.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.11.0", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "glob-parent": { - "version": "6.0.2", - "requires": { - "is-glob": "^4.0.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0" - }, - "schema-utils": { - "version": "4.0.0", - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - } - } - }, - "core-js": { - "version": "1.2.7" - }, - "core-js-compat": { - "version": "3.25.4", - "requires": { - "browserslist": "^4.21.4" - } - }, - "core-util-is": { - "version": "1.0.3" - }, - "cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "dependencies": { - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - } - } - }, - "cross-spawn": { - "version": "7.0.3", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "4.0.0", - "dev": true, - "requires": { - "type-fest": "^1.0.1" - }, - "dependencies": { - "type-fest": { - "version": "1.4.0", - "dev": true - } - } - }, - "css-loader": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", - "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", - "dev": true, - "requires": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.21", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.3", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" - }, - "dependencies": { - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "csstype": { - "version": "3.1.1" - }, - "cuss": { - "version": "2.1.0", - "dev": true - }, - "d3": { - "version": "5.16.0", - "dev": true, - "requires": { - "d3-array": "1", - "d3-axis": "1", - "d3-brush": "1", - "d3-chord": "1", - "d3-collection": "1", - "d3-color": "1", - "d3-contour": "1", - "d3-dispatch": "1", - "d3-drag": "1", - "d3-dsv": "1", - "d3-ease": "1", - "d3-fetch": "1", - "d3-force": "1", - "d3-format": "1", - "d3-geo": "1", - "d3-hierarchy": "1", - "d3-interpolate": "1", - "d3-path": "1", - "d3-polygon": "1", - "d3-quadtree": "1", - "d3-random": "1", - "d3-scale": "2", - "d3-scale-chromatic": "1", - "d3-selection": "1", - "d3-shape": "1", - "d3-time": "1", - "d3-time-format": "2", - "d3-timer": "1", - "d3-transition": "1", - "d3-voronoi": "1", - "d3-zoom": "1" - } - }, - "d3-array": { - "version": "1.2.4", - "dev": true - }, - "d3-axis": { - "version": "1.0.12", - "dev": true - }, - "d3-brush": { - "version": "1.1.6", - "dev": true, - "requires": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "d3-chord": { - "version": "1.0.6", - "dev": true, - "requires": { - "d3-array": "1", - "d3-path": "1" - } - }, - "d3-collection": { - "version": "1.0.7", - "dev": true - }, - "d3-color": { - "version": "1.4.1", - "dev": true - }, - "d3-contour": { - "version": "1.3.2", - "dev": true, - "requires": { - "d3-array": "^1.1.1" - } - }, - "d3-dispatch": { - "version": "1.0.6", - "dev": true - }, - "d3-drag": { - "version": "1.2.5", - "dev": true, - "requires": { - "d3-dispatch": "1", - "d3-selection": "1" - } - }, - "d3-dsv": { - "version": "1.2.0", - "dev": true, - "requires": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "dev": true - } - } - }, - "d3-ease": { - "version": "1.0.7", - "dev": true - }, - "d3-fetch": { - "version": "1.2.0", - "dev": true, - "requires": { - "d3-dsv": "1" - } - }, - "d3-force": { - "version": "1.2.1", - "dev": true, - "requires": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" - } - }, - "d3-format": { - "version": "1.4.5", - "dev": true - }, - "d3-geo": { - "version": "1.12.1", - "dev": true, - "requires": { - "d3-array": "1" - } - }, - "d3-hierarchy": { - "version": "1.1.9", - "dev": true - }, - "d3-interpolate": { - "version": "1.4.0", - "dev": true, - "requires": { - "d3-color": "1" - } - }, - "d3-path": { - "version": "1.0.9", - "dev": true - }, - "d3-polygon": { - "version": "1.0.6", - "dev": true - }, - "d3-quadtree": { - "version": "1.0.7", - "dev": true - }, - "d3-random": { - "version": "1.1.2", - "dev": true - }, - "d3-scale": { - "version": "2.2.2", - "dev": true, - "requires": { - "d3-array": "^1.2.0", - "d3-collection": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" - } - }, - "d3-scale-chromatic": { - "version": "1.5.0", - "dev": true, - "requires": { - "d3-color": "1", - "d3-interpolate": "1" - } - }, - "d3-selection": { - "version": "1.4.2", - "dev": true - }, - "d3-shape": { - "version": "1.3.7", - "dev": true, - "requires": { - "d3-path": "1" - } - }, - "d3-time": { - "version": "1.1.0", - "dev": true - }, - "d3-time-format": { - "version": "2.3.0", - "dev": true, - "requires": { - "d3-time": "1" - } - }, - "d3-timer": { - "version": "1.0.10", - "dev": true - }, - "d3-transition": { - "version": "1.3.2", - "dev": true, - "requires": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - } - }, - "d3-voronoi": { - "version": "1.1.4", - "dev": true - }, - "d3-zoom": { - "version": "1.8.3", - "dev": true, - "requires": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "debug": { - "version": "4.3.4", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "6.0.0", - "dev": true - }, - "decamelize-keys": { - "version": "1.1.1", - "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "decamelize": { - "version": "1.2.0", - "dev": true - }, - "map-obj": { - "version": "1.0.1", - "dev": true - } - } - }, - "decode-named-character-reference": { - "version": "1.0.2", - "dev": true, - "requires": { - "character-entities": "^2.0.0" - } - }, - "decompress-response": { - "version": "6.0.0", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "dev": true - } - } - }, - "deep-extend": { - "version": "0.6.0", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "dev": true - }, - "defer-to-connect": { - "version": "2.0.1", - "dev": true - }, - "define-properties": { - "version": "1.1.4", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "dequal": { - "version": "2.0.3", - "dev": true - }, - "diff": { - "version": "5.1.0", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "requires": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "dom-serializer": { - "version": "2.0.0", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0" - }, - "domhandler": { - "version": "5.0.3", - "requires": { - "domelementtype": "^2.3.0" - } - }, - "dompurify": { - "version": "2.4.1" - }, - "domutils": { - "version": "3.0.1", - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" - } - }, - "dot-prop": { - "version": "6.0.1", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer": { - "version": "0.1.2", - "dev": true - }, - "eastasianwidth": { - "version": "0.2.0", - "dev": true - }, - "electron-to-chromium": { - "version": "1.4.270" - }, - "emoji-regex": { - "version": "8.0.0", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "dev": true - }, - "encoding": { - "version": "0.1.13", - "requires": { - "iconv-lite": "^0.6.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "end-of-stream": { - "version": "1.4.4", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.5.0", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - } - }, - "enquirer": { - "version": "2.3.6", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "entities": { - "version": "4.4.0" - }, - "envinfo": { - "version": "7.8.1", - "dev": true - }, - "errno": { - "version": "0.1.8", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "error-ex": { - "version": "1.3.2", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.20.3", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.6", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - } - }, - "es-module-lexer": { - "version": "0.9.3" - }, - "es-shim-unscopables": { - "version": "1.0.0", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1" - }, - "escape-goat": { - "version": "4.0.0", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5" - }, - "eslint": { - "version": "7.32.0", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "ansi-styles": { - "version": "4.3.0", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "dev": true - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "dev": true - }, - "globals": { - "version": "13.17.0", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "has-flag": { - "version": "4.0.0", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.20.2", - "dev": true - } - } - }, - "eslint-config-google": { - "version": "0.9.1", - "dev": true, - "requires": {} - }, - "eslint-plugin-jsdoc": { - "version": "39.6.4", - "dev": true, - "requires": { - "@es-joy/jsdoccomment": "~0.36.1", - "comment-parser": "1.3.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "semver": "^7.3.8", - "spdx-expression-parse": "^3.0.1" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "eslint-plugin-no-jquery": { - "version": "2.7.0", - "dev": true, - "requires": {} - }, - "eslint-plugin-react": { - "version": "7.31.8", - "dev": true, - "requires": { - "array-includes": "^3.1.5", - "array.prototype.flatmap": "^1.3.0", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.1", - "object.values": "^1.1.5", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.7" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "resolve": { - "version": "2.0.0-next.4", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "dependencies": { - "estraverse": { - "version": "4.3.0" - } - } - }, - "eslint-utils": { - "version": "2.1.0", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "dev": true - }, - "eslint-webpack-plugin": { - "version": "2.1.0", - "dev": true, - "requires": { - "@types/eslint": "^7.2.0", - "arrify": "^2.0.1", - "fs-extra": "^9.0.1", - "micromatch": "^4.0.2", - "schema-utils": "^2.7.0" - } - }, - "espree": { - "version": "7.3.1", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0" - }, - "estree-util-is-identifier-name": { - "version": "2.1.0", - "dev": true - }, - "estree-util-visit": { - "version": "1.2.1", - "dev": true, - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/unist": "^2.0.0" - } - }, - "esutils": { - "version": "2.0.3", - "dev": true - }, - "event-stream": { - "version": "3.1.7", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.2", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - } - }, - "events": { - "version": "3.3.0" - }, - "extend": { - "version": "3.0.2" - }, - "fast-deep-equal": { - "version": "3.1.3" - }, - "fast-glob": { - "version": "3.2.12", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0" - }, - "fast-levenshtein": { - "version": "2.0.6", - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.16", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "requires": { - "reusify": "^1.0.4" - } - }, - "fault": { - "version": "2.0.1", - "dev": true, - "requires": { - "format": "^0.2.0" - } - }, - "fbjs": { - "version": "0.8.18", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.30" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-cache-dir": { - "version": "3.3.2", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "dependencies": { - "make-dir": { - "version": "3.1.0", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - } - } - }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, - "find-up": { - "version": "4.1.0", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "dev": true - }, - "form-data-encoder": { - "version": "2.1.4", - "dev": true - }, - "format": { - "version": "0.2.2", - "dev": true - }, - "from": { - "version": "0.1.7", - "dev": true - }, - "fs-extra": { - "version": "9.1.0", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs-readdir-recursive": { - "version": "1.1.0", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "dev": true - }, - "function-bind": { - "version": "1.1.1" - }, - "function.prototype.name": { - "version": "1.1.5", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "dev": true - }, - "functions-have-names": { - "version": "1.2.3", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2" - }, - "get-intrinsic": { - "version": "1.1.3", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-stream": { - "version": "6.0.1", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "git-diff-tree": { - "version": "1.1.0", - "dev": true, - "requires": { - "git-spawned-stream": "1.0.1", - "pump-chain": "1.0.0", - "split-transform-stream": "0.1.1", - "through2": "2.0.0" - } - }, - "git-spawned-stream": { - "version": "1.0.1", - "dev": true, - "requires": { - "debug": "^4.1.0", - "spawn-to-readstream": "~0.1.3" - } - }, - "glob": { - "version": "7.2.3", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.4.1" - }, - "global-dirs": { - "version": "3.0.1", - "dev": true, - "requires": { - "ini": "2.0.0" - }, - "dependencies": { - "ini": { - "version": "2.0.0", - "dev": true - } - } - }, - "globals": { - "version": "11.12.0" - }, - "globby": { - "version": "13.1.2", - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.2.0" - }, - "slash": { - "version": "4.0.0" - } - } - }, - "got": { - "version": "12.5.3", - "dev": true, - "requires": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.1", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10" - }, - "hard-rejection": { - "version": "2.1.0", - "dev": true - }, - "has": { - "version": "1.0.3", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "dev": true - }, - "has-flag": { - "version": "3.0.0" - }, - "has-property-descriptors": { - "version": "1.0.0", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-yarn": { - "version": "3.0.0", - "dev": true - }, - "hast-util-embedded": { - "version": "2.0.0", - "dev": true, - "requires": { - "hast-util-is-element": "^2.0.0" - } - }, - "hast-util-from-parse5": { - "version": "7.1.0", - "dev": true, - "requires": { - "@types/hast": "^2.0.0", - "@types/parse5": "^6.0.0", - "@types/unist": "^2.0.0", - "hastscript": "^7.0.0", - "property-information": "^6.0.0", - "vfile": "^5.0.0", - "vfile-location": "^4.0.0", - "web-namespaces": "^2.0.0" - } - }, - "hast-util-has-property": { - "version": "2.0.0", - "dev": true - }, - "hast-util-is-body-ok-link": { - "version": "2.0.0", - "dev": true, - "requires": { - "@types/hast": "^2.0.0", - "hast-util-has-property": "^2.0.0", - "hast-util-is-element": "^2.0.0" - } - }, - "hast-util-is-element": { - "version": "2.1.2", - "dev": true, - "requires": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0" - } - }, - "hast-util-parse-selector": { - "version": "3.1.0", - "dev": true, - "requires": { - "@types/hast": "^2.0.0" - } - }, - "hast-util-phrasing": { - "version": "2.0.1", - "dev": true, - "requires": { - "hast-util-embedded": "^2.0.0", - "hast-util-has-property": "^2.0.0", - "hast-util-is-body-ok-link": "^2.0.0", - "hast-util-is-element": "^2.0.0" - } - }, - "hast-util-to-nlcst": { - "version": "2.2.0", - "dev": true, - "requires": { - "@types/hast": "^2.0.0", - "@types/nlcst": "^1.0.0", - "@types/unist": "^2.0.0", - "hast-util-embedded": "^2.0.0", - "hast-util-is-element": "^2.0.0", - "hast-util-phrasing": "^2.0.0", - "hast-util-to-string": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "nlcst-to-string": "^3.0.0", - "unist-util-position": "^4.0.0", - "vfile": "^5.0.0", - "vfile-location": "^4.0.0" - } - }, - "hast-util-to-string": { - "version": "2.0.0", - "dev": true, - "requires": { - "@types/hast": "^2.0.0" - } - }, - "hast-util-whitespace": { - "version": "2.0.0", - "dev": true - }, - "hastscript": { - "version": "7.0.2", - "dev": true, - "requires": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" - } - }, - "hoist-non-react-statics": { - "version": "3.3.2", - "requires": { - "react-is": "^16.7.0" - } - }, - "hosted-git-info": { - "version": "5.2.1", - "dev": true, - "requires": { - "lru-cache": "^7.5.1" - }, - "dependencies": { - "lru-cache": { - "version": "7.14.1", - "dev": true - } - } - }, - "html-to-react": { - "version": "1.5.0", - "requires": { - "domhandler": "^5.0", - "htmlparser2": "^8.0", - "lodash.camelcase": "^4.3.0" - } - }, - "htmlparser2": { - "version": "8.0.1", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "entities": "^4.3.0" - } - }, - "http-cache-semantics": { - "version": "4.1.1", - "dev": true - }, - "http2-wrapper": { - "version": "2.2.0", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - }, - "dependencies": { - "quick-lru": { - "version": "5.1.1", - "dev": true - } - } - }, - "iconv-lite": { - "version": "0.4.24", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} - }, - "ignore": { - "version": "4.0.6", - "dev": true - }, - "immediate": { - "version": "3.0.6" - }, - "import-fresh": { - "version": "3.3.0", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-lazy": { - "version": "4.0.0", - "dev": true - }, - "import-local": { - "version": "3.1.0", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "import-meta-resolve": { - "version": "2.2.1", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "dev": true - }, - "indent-string": { - "version": "5.0.0", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4" - }, - "ini": { - "version": "3.0.1", - "dev": true - }, - "internal-slot": { - "version": "1.0.3", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "interpret": { - "version": "2.2.0", - "dev": true - }, - "is-alphabetical": { - "version": "2.0.1", - "dev": true - }, - "is-alphanumerical": { - "version": "2.0.1", - "dev": true, - "requires": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1" - }, - "is-bigint": { - "version": "1.0.4", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-buffer": { - "version": "2.0.5" - }, - "is-callable": { - "version": "1.2.7", - "dev": true - }, - "is-ci": { - "version": "3.0.1", - "dev": true, - "requires": { - "ci-info": "^3.2.0" - } - }, - "is-core-module": { - "version": "2.10.0", - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-decimal": { - "version": "2.0.1", - "dev": true - }, - "is-empty": { - "version": "1.2.0", - "dev": true - }, - "is-extglob": { - "version": "2.1.1" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-hexadecimal": { - "version": "2.0.1", - "dev": true - }, - "is-installed-globally": { - "version": "0.4.0", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "dev": true - }, - "is-npm": { - "version": "6.0.0", - "dev": true - }, - "is-number": { - "version": "7.0.0" - }, - "is-number-object": { - "version": "1.0.7", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.1.4", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "1.1.0" - }, - "is-string": { - "version": "1.0.7", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-yarn-global": { - "version": "0.4.1", - "dev": true - }, - "isarray": { - "version": "1.0.0" - }, - "isexe": { - "version": "2.0.0", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "dev": true - }, - "isomorphic-fetch": { - "version": "2.2.1", - "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, - "jest-worker": { - "version": "27.5.1", - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0" - }, - "supports-color": { - "version": "8.1.1", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-tokens": { - "version": "4.0.0" - }, - "js-yaml": { - "version": "3.14.1", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsdoc-type-pratt-parser": { - "version": "3.1.0", - "dev": true - }, - "jsesc": { - "version": "2.5.2" - }, - "json-buffer": { - "version": "3.0.1", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1" - }, - "json-schema-traverse": { - "version": "0.4.1" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true - }, - "json5": { - "version": "2.2.3" - }, - "jsonfile": { - "version": "6.1.0", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jstat": { - "version": "1.9.5" - }, - "jsx-ast-utils": { - "version": "3.3.3", - "dev": true, - "requires": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - } - }, - "jszip": { - "version": "3.10.1", - "requires": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "keyv": { - "version": "4.5.2", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "dev": true - }, - "kleur": { - "version": "4.1.5", - "dev": true - }, - "latest-version": { - "version": "7.0.0", - "dev": true, - "requires": { - "package-json": "^8.1.0" - } - }, - "levn": { - "version": "0.4.1", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lie": { - "version": "3.3.0", - "requires": { - "immediate": "~3.0.5" - } - }, - "limit-spawn": { - "version": "0.0.3", - "dev": true - }, - "lines-and-columns": { - "version": "1.2.4" - }, - "load-plugin": { - "version": "5.1.0", - "dev": true, - "requires": { - "@npmcli/config": "^6.0.0", - "import-meta-resolve": "^2.0.0" - } - }, - "loader-runner": { - "version": "4.3.0" - }, - "loader-utils": { - "version": "2.0.4", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "locate-path": { - "version": "5.0.0", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash.camelcase": { - "version": "4.3.0" - }, - "lodash.debounce": { - "version": "4.0.8" - }, - "lodash.merge": { - "version": "4.6.2", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "dev": true - }, - "longest-streak": { - "version": "3.0.1", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lowercase-keys": { - "version": "3.0.0", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true - } - } - }, - "map-obj": { - "version": "4.3.0", - "dev": true - }, - "map-stream": { - "version": "0.1.0", - "dev": true - }, - "markdown-table": { - "version": "3.0.2", - "dev": true - }, - "mdast-add-list-metadata": { - "version": "1.0.1", - "requires": { - "unist-util-visit-parents": "1.1.2" - } - }, - "mdast-comment-marker": { - "version": "2.1.0", - "dev": true, - "requires": { - "mdast-util-mdx-expression": "^1.1.0" - } - }, - "mdast-util-find-and-replace": { - "version": "2.2.1", - "dev": true, - "requires": { - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "5.0.0", - "dev": true - }, - "unist-util-visit-parents": { - "version": "5.1.1", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - } - } - } - }, - "mdast-util-from-markdown": { - "version": "1.2.0", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "mdast-util-to-string": "^3.1.0", - "micromark": "^3.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "uvu": "^0.5.0" - } - }, - "mdast-util-frontmatter": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-extension-frontmatter": "^1.0.0" - } - }, - "mdast-util-gfm": { - "version": "2.0.1", - "dev": true, - "requires": { - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-gfm-autolink-literal": "^1.0.0", - "mdast-util-gfm-footnote": "^1.0.0", - "mdast-util-gfm-strikethrough": "^1.0.0", - "mdast-util-gfm-table": "^1.0.0", - "mdast-util-gfm-task-list-item": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - } - }, - "mdast-util-gfm-autolink-literal": { - "version": "1.0.2", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "ccount": "^2.0.0", - "mdast-util-find-and-replace": "^2.0.0", - "micromark-util-character": "^1.0.0" - } - }, - "mdast-util-gfm-footnote": { - "version": "1.0.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0", - "micromark-util-normalize-identifier": "^1.0.0" - } - }, - "mdast-util-gfm-strikethrough": { - "version": "1.0.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0" - } - }, - "mdast-util-gfm-table": { - "version": "1.0.6", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.3.0" - } - }, - "mdast-util-gfm-task-list-item": { - "version": "1.0.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0" - } - }, - "mdast-util-mdx": { - "version": "2.0.1", - "dev": true, - "requires": { - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-mdx-expression": "^1.0.0", - "mdast-util-mdx-jsx": "^2.0.0", - "mdast-util-mdxjs-esm": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - } - }, - "mdast-util-mdx-expression": { - "version": "1.3.1", - "dev": true, - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - } - }, - "mdast-util-mdx-jsx": { - "version": "2.1.2", - "dev": true, - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "ccount": "^2.0.0", - "mdast-util-from-markdown": "^1.1.0", - "mdast-util-to-markdown": "^1.3.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^4.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - } - }, - "mdast-util-mdxjs-esm": { - "version": "1.3.1", - "dev": true, - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - } - }, - "mdast-util-to-markdown": { - "version": "1.3.0", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "longest-streak": "^3.0.0", - "mdast-util-to-string": "^3.0.0", - "micromark-util-decode-string": "^1.0.0", - "unist-util-visit": "^4.0.0", - "zwitch": "^2.0.0" - }, - "dependencies": { - "unist-util-visit": { - "version": "4.1.1", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - } - }, - "unist-util-visit-parents": { - "version": "5.1.1", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - } - } - } - }, - "mdast-util-to-nlcst": { - "version": "5.2.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "@types/nlcst": "^1.0.0", - "@types/unist": "^2.0.0", - "nlcst-to-string": "^3.0.0", - "unist-util-position": "^4.0.0", - "vfile": "^5.0.0", - "vfile-location": "^4.0.0" - } - }, - "mdast-util-to-string": { - "version": "3.1.0", - "dev": true - }, - "memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" - }, - "memory-fs": { - "version": "0.5.0", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "meow": { - "version": "11.0.0", - "dev": true, - "requires": { - "@types/minimist": "^1.2.2", - "camelcase-keys": "^8.0.2", - "decamelize": "^6.0.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^4.0.1", - "read-pkg-up": "^9.1.0", - "redent": "^4.0.0", - "trim-newlines": "^4.0.2", - "type-fest": "^3.1.0", - "yargs-parser": "^21.1.1" - } - }, - "merge-stream": { - "version": "2.0.0" - }, - "merge2": { - "version": "1.4.1" - }, - "micromark": { - "version": "3.0.10", - "dev": true, - "requires": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "micromark-core-commonmark": "^1.0.1", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "micromark-core-commonmark": { - "version": "1.0.6", - "dev": true, - "requires": { - "decode-named-character-reference": "^1.0.0", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.0", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-html-tag-name": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "micromark-extension-frontmatter": { - "version": "1.0.0", - "dev": true, - "requires": { - "fault": "^2.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "micromark-extension-gfm": { - "version": "2.0.1", - "dev": true, - "requires": { - "micromark-extension-gfm-autolink-literal": "^1.0.0", - "micromark-extension-gfm-footnote": "^1.0.0", - "micromark-extension-gfm-strikethrough": "^1.0.0", - "micromark-extension-gfm-table": "^1.0.0", - "micromark-extension-gfm-tagfilter": "^1.0.0", - "micromark-extension-gfm-task-list-item": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-extension-gfm-autolink-literal": { - "version": "1.0.3", - "dev": true, - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-gfm-footnote": { - "version": "1.0.4", - "dev": true, - "requires": { - "micromark-core-commonmark": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-gfm-strikethrough": { - "version": "1.0.4", - "dev": true, - "requires": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-gfm-table": { - "version": "1.0.5", - "dev": true, - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-gfm-tagfilter": { - "version": "1.0.1", - "dev": true, - "requires": { - "micromark-util-types": "^1.0.0" - } - }, - "micromark-extension-gfm-task-list-item": { - "version": "1.0.3", - "dev": true, - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-mdx-expression": { - "version": "1.0.4", - "dev": true, - "requires": { - "micromark-factory-mdx-expression": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-mdx-jsx": { - "version": "1.0.3", - "dev": true, - "requires": { - "@types/acorn": "^4.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "micromark-factory-mdx-expression": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - } - }, - "micromark-extension-mdx-md": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-types": "^1.0.0" - } - }, - "micromark-extension-mdxjs": { - "version": "1.0.0", - "dev": true, - "requires": { - "acorn": "^8.0.0", - "acorn-jsx": "^5.0.0", - "micromark-extension-mdx-expression": "^1.0.0", - "micromark-extension-mdx-jsx": "^1.0.0", - "micromark-extension-mdx-md": "^1.0.0", - "micromark-extension-mdxjs-esm": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-types": "^1.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.8.2", - "dev": true - } - } - }, - "micromark-extension-mdxjs-esm": { - "version": "1.0.3", - "dev": true, - "requires": { - "micromark-core-commonmark": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-position-from-estree": "^1.1.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - } - }, - "micromark-factory-destination": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-factory-label": { - "version": "1.0.2", - "dev": true, - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-factory-mdx-expression": { - "version": "1.0.7", - "dev": true, - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-position-from-estree": "^1.0.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - } - }, - "micromark-factory-space": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-factory-title": { - "version": "1.0.2", - "dev": true, - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-factory-whitespace": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-util-character": { - "version": "1.1.0", - "dev": true, - "requires": { - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-util-chunked": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-symbol": "^1.0.0" - } - }, - "micromark-util-classify-character": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-util-combine-extensions": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-util-decode-numeric-character-reference": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-symbol": "^1.0.0" - } - }, - "micromark-util-decode-string": { - "version": "1.0.2", - "dev": true, - "requires": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "micromark-util-encode": { - "version": "1.0.1", - "dev": true - }, - "micromark-util-events-to-acorn": { - "version": "1.2.1", - "dev": true, - "requires": { - "@types/acorn": "^4.0.0", - "@types/estree": "^1.0.0", - "estree-util-visit": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0", - "vfile-location": "^4.0.0", - "vfile-message": "^3.0.0" - } - }, - "micromark-util-html-tag-name": { - "version": "1.1.0", - "dev": true - }, - "micromark-util-normalize-identifier": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-symbol": "^1.0.0" - } - }, - "micromark-util-resolve-all": { - "version": "1.0.0", - "dev": true, - "requires": { - "micromark-util-types": "^1.0.0" - } - }, - "micromark-util-sanitize-uri": { - "version": "1.1.0", - "dev": true, - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "micromark-util-subtokenize": { - "version": "1.0.2", - "dev": true, - "requires": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-util-symbol": { - "version": "1.0.1", - "dev": true - }, - "micromark-util-types": { - "version": "1.0.2", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime-db": { - "version": "1.52.0" - }, - "mime-types": { - "version": "2.1.35", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-response": { - "version": "4.0.0", - "dev": true - }, - "min-indent": { - "version": "1.0.1", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "dev": true - }, - "minimist-options": { - "version": "4.1.0", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "dependencies": { - "arrify": { - "version": "1.0.1", - "dev": true - } - } - }, - "mri": { - "version": "1.2.0", - "dev": true - }, - "ms": { - "version": "2.1.2" - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "dev": true - }, - "natural-compare-lite": { - "version": "1.4.0", - "dev": true - }, - "neo-async": { - "version": "2.6.2" - }, - "nlcst-is-literal": { - "version": "2.1.1", - "dev": true, - "requires": { - "@types/nlcst": "^1.0.0", - "@types/unist": "^2.0.0", - "nlcst-to-string": "^3.0.0" - } - }, - "nlcst-normalize": { - "version": "3.1.1", - "dev": true, - "requires": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0" - } - }, - "nlcst-search": { - "version": "3.1.1", - "dev": true, - "requires": { - "@types/nlcst": "^1.0.0", - "@types/unist": "^2.0.0", - "nlcst-is-literal": "^2.0.0", - "nlcst-normalize": "^3.0.0", - "unist-util-visit": "^4.0.0" - }, - "dependencies": { - "unist-util-visit": { - "version": "4.1.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - } - }, - "unist-util-visit-parents": { - "version": "5.1.3", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - } - } - } - }, - "nlcst-to-string": { - "version": "3.1.0", - "dev": true, - "requires": { - "@types/nlcst": "^1.0.0" - } - }, - "node-fetch": { - "version": "1.7.3", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, - "node-releases": { - "version": "2.0.6" - }, - "nopt": { - "version": "7.0.0", - "dev": true, - "requires": { - "abbrev": "^2.0.0" - } - }, - "normalize-package-data": { - "version": "4.0.1", - "dev": true, - "requires": { - "hosted-git-info": "^5.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "dependencies": { - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "normalize-path": { - "version": "3.0.0" - }, - "normalize-url": { - "version": "8.0.0", - "dev": true - }, - "npm-normalize-package-bin": { - "version": "3.0.0", - "dev": true - }, - "object-assign": { - "version": "4.1.1" - }, - "object-inspect": { - "version": "1.12.2", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "dev": true - }, - "object.assign": { - "version": "4.1.4", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.5", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.fromentries": { - "version": "2.0.5", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.hasown": { - "version": "1.1.1", - "dev": true, - "requires": { - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "object.values": { - "version": "1.1.5", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "once": { - "version": "1.4.0", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-cancelable": { - "version": "3.0.0", - "dev": true - }, - "p-limit": { - "version": "4.0.0", - "dev": true, - "requires": { - "yocto-queue": "^1.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - } - } - }, - "p-try": { - "version": "2.2.0", - "dev": true - }, - "package-json": { - "version": "8.1.0", - "dev": true, - "requires": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" - }, - "dependencies": { - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "pako": { - "version": "1.0.11" - }, - "papaparse": { - "version": "5.3.2" - }, - "parent-module": { - "version": "1.0.1", - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-english": { - "version": "5.0.0", - "dev": true, - "requires": { - "nlcst-to-string": "^2.0.0", - "parse-latin": "^5.0.0", - "unist-util-modify-children": "^2.0.0", - "unist-util-visit-children": "^1.0.0" - }, - "dependencies": { - "nlcst-to-string": { - "version": "2.0.4", - "dev": true - } - } - }, - "parse-entities": { - "version": "4.0.1", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "character-entities": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse-latin": { - "version": "5.0.0", - "dev": true, - "requires": { - "nlcst-to-string": "^2.0.0", - "unist-util-modify-children": "^2.0.0", - "unist-util-visit-children": "^1.0.0" - }, - "dependencies": { - "nlcst-to-string": { - "version": "2.0.4", - "dev": true - } - } - }, - "parse5": { - "version": "6.0.1", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "dev": true - }, - "path-parse": { - "version": "1.0.7" - }, - "path-type": { - "version": "4.0.0" - }, - "pause-stream": { - "version": "0.0.11", - "dev": true, - "requires": { - "through": "~2.3" - } - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.1" - }, - "pify": { - "version": "4.0.1", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "pluralize": { - "version": "8.0.0", - "dev": true - }, - "postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, - "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "requires": {} - }, - "postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "dev": true - }, - "proc-log": { - "version": "3.0.0", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1" - }, - "progress": { - "version": "2.0.3", - "dev": true - }, - "promise": { - "version": "7.3.1", - "requires": { - "asap": "~2.0.3" - } - }, - "prop-types": { - "version": "15.8.1", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "property-information": { - "version": "6.1.1", - "dev": true - }, - "proto-list": { - "version": "1.2.4", - "dev": true - }, - "prr": { - "version": "1.0.1", - "dev": true - }, - "pump": { - "version": "1.0.3", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pump-chain": { - "version": "1.0.0", - "dev": true, - "requires": { - "bubble-stream-error": "^1.0.0", - "pump": "^1.0.1", - "sliced": "^1.0.1" - } - }, - "punycode": { - "version": "2.1.1" - }, - "pupa": { - "version": "3.1.0", - "dev": true, - "requires": { - "escape-goat": "^4.0.0" - } - }, - "queue-microtask": { - "version": "1.2.3" - }, - "quick-lru": { - "version": "6.1.1", - "dev": true - }, - "quotation": { - "version": "2.0.2", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "rc": { - "version": "1.2.8", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "dev": true - } - } - }, - "react": { - "version": "18.2.0", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "react-addons-create-fragment": { - "version": "15.6.2", - "requires": { - "fbjs": "^0.8.4", - "loose-envify": "^1.3.1", - "object-assign": "^4.1.0" - } - }, - "react-dom": { - "version": "18.2.0", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "react-is": { - "version": "16.13.1" - }, - "react-markdown": { - "version": "5.0.3", - "requires": { - "@types/mdast": "^3.0.3", - "@types/unist": "^2.0.3", - "html-to-react": "^1.3.4", - "mdast-add-list-metadata": "1.0.1", - "prop-types": "^15.7.2", - "react-is": "^16.8.6", - "remark-parse": "^9.0.0", - "unified": "^9.0.0", - "unist-util-visit": "^2.0.0", - "xtend": "^4.0.1" - }, - "dependencies": { - "bail": { - "version": "1.0.5" - }, - "character-entities": { - "version": "1.2.4" - }, - "character-entities-legacy": { - "version": "1.1.4" - }, - "character-reference-invalid": { - "version": "1.1.4" - }, - "is-alphabetical": { - "version": "1.0.4" - }, - "is-alphanumerical": { - "version": "1.0.4", - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "is-decimal": { - "version": "1.0.4" - }, - "is-hexadecimal": { - "version": "1.0.4" - }, - "is-plain-obj": { - "version": "2.1.0" - }, - "mdast-util-from-markdown": { - "version": "0.8.5", - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-to-string": "^2.0.0", - "micromark": "~2.11.0", - "parse-entities": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - } - }, - "mdast-util-to-string": { - "version": "2.0.0" - }, - "micromark": { - "version": "2.11.4", - "requires": { - "debug": "^4.0.0", - "parse-entities": "^2.0.0" - } - }, - "parse-entities": { - "version": "2.0.0", - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, - "remark-parse": { - "version": "9.0.0", - "requires": { - "mdast-util-from-markdown": "^0.8.0" - } - }, - "trough": { - "version": "1.0.5" - }, - "unified": { - "version": "9.2.2", - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - } - }, - "unist-util-stringify-position": { - "version": "2.0.3", - "requires": { - "@types/unist": "^2.0.2" - } - }, - "vfile": { - "version": "4.2.1", - "requires": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - } - }, - "vfile-message": { - "version": "2.0.4", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - } - } - } - }, - "react-select": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.0.tgz", - "integrity": "sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ==", - "requires": { - "@babel/runtime": "^7.12.0", - "@emotion/cache": "^11.4.0", - "@emotion/react": "^11.8.1", - "@floating-ui/dom": "^1.0.1", - "@types/react-transition-group": "^4.4.0", - "memoize-one": "^6.0.0", - "prop-types": "^15.6.0", - "react-transition-group": "^4.3.0", - "use-isomorphic-layout-effect": "^1.1.2" - } - }, - "react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "requires": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - } - }, - "read-package-json-fast": { - "version": "3.0.2", - "dev": true, - "requires": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "dependencies": { - "json-parse-even-better-errors": { - "version": "3.0.0", - "dev": true - } - } - }, - "read-pkg": { - "version": "7.1.0", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^2.0.0" - }, - "dependencies": { - "hosted-git-info": { - "version": "4.1.0", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "normalize-package-data": { - "version": "3.0.3", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - } - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "type-fest": { - "version": "2.19.0", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "9.1.0", - "dev": true, - "requires": { - "find-up": "^6.3.0", - "read-pkg": "^7.1.0", - "type-fest": "^2.5.0" - }, - "dependencies": { - "find-up": { - "version": "6.3.0", - "dev": true, - "requires": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - } - }, - "locate-path": { - "version": "7.2.0", - "dev": true, - "requires": { - "p-locate": "^6.0.0" - } - }, - "p-locate": { - "version": "6.0.0", - "dev": true, - "requires": { - "p-limit": "^4.0.0" - } - }, - "path-exists": { - "version": "5.0.0", - "dev": true - }, - "type-fest": { - "version": "2.19.0", - "dev": true - } - } - }, - "readable-stream": { - "version": "2.3.7", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "dev": true, - "optional": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "rechoir": { - "version": "0.7.1", - "dev": true, - "requires": { - "resolve": "^1.9.0" - } - }, - "redent": { - "version": "4.0.0", - "dev": true, - "requires": { - "indent-string": "^5.0.0", - "strip-indent": "^4.0.0" - } - }, - "redux": { - "version": "4.2.0", - "dev": true, - "requires": { - "@babel/runtime": "^7.9.2" - } - }, - "regenerate": { - "version": "1.4.2", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "10.1.0", - "dev": true, - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9" - }, - "regenerator-transform": { - "version": "0.15.0", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "regexpp": { - "version": "3.2.0", - "dev": true - }, - "regexpu-core": { - "version": "5.2.1", - "dev": true, - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsgen": "^0.7.1", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "registry-auth-token": { - "version": "5.0.1", - "dev": true, - "requires": { - "@pnpm/npm-conf": "^1.0.4" - } - }, - "registry-url": { - "version": "6.0.1", - "dev": true, - "requires": { - "rc": "1.2.8" - } - }, - "regjsgen": { - "version": "0.7.1", - "dev": true - }, - "regjsparser": { - "version": "0.9.1", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "dev": true - } - } - }, - "rehype-parse": { - "version": "8.0.4", - "dev": true, - "requires": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^7.0.0", - "parse5": "^6.0.0", - "unified": "^10.0.0" - } - }, - "rehype-retext": { - "version": "3.0.2", - "dev": true, - "requires": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0", - "hast-util-to-nlcst": "^2.0.0", - "unified": "^10.0.0" - } - }, - "remark-frontmatter": { - "version": "4.0.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-frontmatter": "^1.0.0", - "micromark-extension-frontmatter": "^1.0.0", - "unified": "^10.0.0" - } - }, - "remark-gfm": { - "version": "3.0.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-gfm": "^2.0.0", - "micromark-extension-gfm": "^2.0.0", - "unified": "^10.0.0" - } - }, - "remark-mdx": { - "version": "2.0.0", - "dev": true, - "requires": { - "mdast-util-mdx": "^2.0.0", - "micromark-extension-mdxjs": "^1.0.0" - } - }, - "remark-message-control": { - "version": "7.1.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "mdast-comment-marker": "^2.0.0", - "unified": "^10.0.0", - "unified-message-control": "^4.0.0", - "vfile": "^5.0.0" - } - }, - "remark-parse": { - "version": "10.0.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "unified": "^10.0.0" - } - }, - "remark-retext": { - "version": "5.0.1", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "mdast-util-to-nlcst": "^5.0.0", - "unified": "^10.0.0" - } - }, - "require-from-string": { - "version": "2.0.2" - }, - "resolve": { - "version": "1.22.1", - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "dev": true - }, - "resolve-cwd": { - "version": "3.0.0", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0" - }, - "responselike": { - "version": "3.0.0", - "dev": true, - "requires": { - "lowercase-keys": "^3.0.0" - } - }, - "retext-english": { - "version": "4.1.0", - "dev": true, - "requires": { - "@types/nlcst": "^1.0.0", - "parse-english": "^5.0.0", - "unherit": "^3.0.0", - "unified": "^10.0.0" - } - }, - "retext-equality": { - "version": "6.6.0", - "dev": true, - "requires": { - "@types/nlcst": "^1.0.0", - "@types/unist": "^2.0.6", - "nlcst-normalize": "^3.0.0", - "nlcst-search": "^3.0.0", - "nlcst-to-string": "^3.0.0", - "quotation": "^2.0.0", - "unified": "^10.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0" - }, - "dependencies": { - "unist-util-visit": { - "version": "4.1.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - } - }, - "unist-util-visit-parents": { - "version": "5.1.3", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - } - } - } - }, - "retext-profanities": { - "version": "7.2.2", - "dev": true, - "requires": { - "@types/nlcst": "^1.0.0", - "cuss": "^2.0.0", - "nlcst-search": "^3.0.0", - "nlcst-to-string": "^3.0.0", - "pluralize": "^8.0.0", - "quotation": "^2.0.0", - "unified": "^10.0.0", - "unist-util-position": "^4.0.0" - } - }, - "reusify": { - "version": "1.0.4" - }, - "rimraf": { - "version": "3.0.2", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rw": { - "version": "1.3.3", - "dev": true - }, - "sade": { - "version": "1.8.1", - "dev": true, - "requires": { - "mri": "^1.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2" - }, - "safe-regex-test": { - "version": "1.0.0", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2" - }, - "scheduler": { - "version": "0.23.0", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "schema-utils": { - "version": "2.7.1", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - }, - "semver-diff": { - "version": "4.0.0", - "dev": true, - "requires": { - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "serialize-javascript": { - "version": "6.0.0", - "requires": { - "randombytes": "^2.1.0" - } - }, - "setimmediate": { - "version": "1.0.5" - }, - "shallow-clone": { - "version": "3.0.1", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "shebang-command": { - "version": "2.0.0", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "dev": true - }, - "slash": { - "version": "2.0.0", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "dev": true - } - } - }, - "sliced": { - "version": "1.0.1", - "dev": true - }, - "source-map": { - "version": "0.6.1" - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "space-separated-tokens": { - "version": "2.0.1", - "dev": true - }, - "spawn-to-readstream": { - "version": "0.1.3", - "dev": true, - "requires": { - "limit-spawn": "0.0.3", - "through2": "~0.4.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "dev": true - }, - "object-keys": { - "version": "0.4.0", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "dev": true - }, - "through2": { - "version": "0.4.2", - "dev": true, - "requires": { - "readable-stream": "~1.0.17", - "xtend": "~2.1.1" - } - }, - "xtend": { - "version": "2.1.2", - "dev": true, - "requires": { - "object-keys": "~0.4.0" - } - } - } - }, - "spdx-correct": { - "version": "3.1.1", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.12", - "dev": true - }, - "split": { - "version": "0.2.10", - "dev": true, - "requires": { - "through": "2" - } - }, - "split-transform-stream": { - "version": "0.1.1", - "dev": true, - "requires": { - "bubble-stream-error": "~0.0.1", - "event-stream": "~3.1.5", - "through2": "~0.4.2" - }, - "dependencies": { - "bubble-stream-error": { - "version": "0.0.1", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "dev": true - }, - "object-keys": { - "version": "0.4.0", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "dev": true - }, - "through2": { - "version": "0.4.2", - "dev": true, - "requires": { - "readable-stream": "~1.0.17", - "xtend": "~2.1.1" - } - }, - "xtend": { - "version": "2.1.2", - "dev": true, - "requires": { - "object-keys": "~0.4.0" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "dev": true - }, - "stream-combiner": { - "version": "0.0.4", - "dev": true, - "requires": { - "duplexer": "~0.1.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "4.2.3", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.matchall": { - "version": "4.0.7", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.1", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.5", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.5", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "stringify-entities": { - "version": "4.0.3", - "dev": true, - "requires": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - } - }, - "strip-ansi": { - "version": "6.0.1", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-indent": { - "version": "4.0.0", - "dev": true, - "requires": { - "min-indent": "^1.0.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "dev": true - }, - "style-loader": { - "version": "1.3.0", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^2.7.0" - } - }, - "stylis": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", - "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" - }, - "supports-color": { - "version": "5.5.0", - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0" - }, - "swagger-ui-dist": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz", - "integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ==" - }, - "sweetalert2": { - "version": "8.19.0" - }, - "table": { - "version": "6.8.0", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.11.0", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "dev": true - } - } - }, - "tapable": { - "version": "1.1.3", - "dev": true - }, - "terser": { - "version": "5.15.1", - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "acorn": { - "version": "8.8.1" - }, - "commander": { - "version": "2.20.3" - } - } - }, - "terser-webpack-plugin": { - "version": "5.3.6", - "requires": { - "@jridgewell/trace-mapping": "^0.3.14", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" - }, - "dependencies": { - "schema-utils": { - "version": "3.1.1", - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "dev": true - }, - "through": { - "version": "2.3.8", - "dev": true - }, - "through2": { - "version": "2.0.0", - "dev": true, - "requires": { - "readable-stream": "~2.0.0", - "xtend": "~4.0.0" - }, - "dependencies": { - "process-nextick-args": { - "version": "1.0.7", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "0.10.31", - "dev": true - } - } - }, - "to-fast-properties": { - "version": "2.0.0" - }, - "to-regex-range": { - "version": "5.0.1", - "requires": { - "is-number": "^7.0.0" - } - }, - "to-vfile": { - "version": "7.2.3", - "dev": true, - "requires": { - "is-buffer": "^2.0.0", - "vfile": "^5.1.0" - } - }, - "trim-newlines": { - "version": "4.0.2", - "dev": true - }, - "trough": { - "version": "2.1.0", - "dev": true - }, - "ts-loader": { - "version": "8.4.0", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "enhanced-resolve": "^4.0.0", - "loader-utils": "^2.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "tslib": { - "version": "1.14.1", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type-check": { - "version": "0.4.0", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "3.5.7", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "4.8.4", - "dev": true - }, - "ua-parser-js": { - "version": "0.7.33" - }, - "unbox-primitive": { - "version": "1.0.2", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "unherit": { - "version": "3.0.0", - "dev": true - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "dev": true - }, - "unified": { - "version": "10.1.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "dependencies": { - "is-plain-obj": { - "version": "4.1.0", - "dev": true - } - } - }, - "unified-diff": { - "version": "4.0.1", - "dev": true, - "requires": { - "git-diff-tree": "^1.0.0", - "vfile-find-up": "^6.0.0" - } - }, - "unified-engine": { - "version": "10.1.0", - "dev": true, - "requires": { - "@types/concat-stream": "^2.0.0", - "@types/debug": "^4.0.0", - "@types/is-empty": "^1.0.0", - "@types/node": "^18.0.0", - "@types/unist": "^2.0.0", - "concat-stream": "^2.0.0", - "debug": "^4.0.0", - "fault": "^2.0.0", - "glob": "^8.0.0", - "ignore": "^5.0.0", - "is-buffer": "^2.0.0", - "is-empty": "^1.0.0", - "is-plain-obj": "^4.0.0", - "load-plugin": "^5.0.0", - "parse-json": "^6.0.0", - "to-vfile": "^7.0.0", - "trough": "^2.0.0", - "unist-util-inspect": "^7.0.0", - "vfile-message": "^3.0.0", - "vfile-reporter": "^7.0.0", - "vfile-statistics": "^2.0.0", - "yaml": "^2.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "8.1.0", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "ignore": { - "version": "5.2.4", - "dev": true - }, - "is-plain-obj": { - "version": "4.1.0", - "dev": true - }, - "lines-and-columns": { - "version": "2.0.3", - "dev": true - }, - "minimatch": { - "version": "5.1.6", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "parse-json": { - "version": "6.0.2", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.0", - "error-ex": "^1.3.2", - "json-parse-even-better-errors": "^2.3.1", - "lines-and-columns": "^2.0.2" - } - } - } - }, - "unified-message-control": { - "version": "4.0.0", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit": "^3.0.0", - "vfile": "^5.0.0", - "vfile-location": "^4.0.0", - "vfile-message": "^3.0.0" - }, - "dependencies": { - "unist-util-visit": { - "version": "3.1.0", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^4.0.0" - } - }, - "unist-util-visit-parents": { - "version": "4.1.1", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - } - } - } - }, - "unique-string": { - "version": "3.0.0", - "dev": true, - "requires": { - "crypto-random-string": "^4.0.0" - } - }, - "unist-util-inspect": { - "version": "7.0.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0" - } - }, - "unist-util-is": { - "version": "5.1.1", - "dev": true - }, - "unist-util-modify-children": { - "version": "2.0.0", - "dev": true, - "requires": { - "array-iterate": "^1.0.0" - } - }, - "unist-util-position": { - "version": "4.0.3", - "dev": true, - "requires": { - "@types/unist": "^2.0.0" - } - }, - "unist-util-position-from-estree": { - "version": "1.1.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0" - } - }, - "unist-util-remove-position": { - "version": "4.0.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-visit": "^4.0.0" - }, - "dependencies": { - "unist-util-visit": { - "version": "4.1.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - } - }, - "unist-util-visit-parents": { - "version": "5.1.3", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - } - } - } - }, - "unist-util-stringify-position": { - "version": "3.0.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0" - } - }, - "unist-util-visit": { - "version": "2.0.3", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" - }, - "dependencies": { - "unist-util-is": { - "version": "4.1.0" - }, - "unist-util-visit-parents": { - "version": "3.1.1", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" - } - } - } - }, - "unist-util-visit-children": { - "version": "1.1.4", - "dev": true - }, - "unist-util-visit-parents": { - "version": "1.1.2" - }, - "universalify": { - "version": "2.0.0", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.9", - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "update-notifier": { - "version": "6.0.2", - "dev": true, - "requires": { - "boxen": "^7.0.0", - "chalk": "^5.0.1", - "configstore": "^6.0.0", - "has-yarn": "^3.0.0", - "import-lazy": "^4.0.0", - "is-ci": "^3.0.1", - "is-installed-globally": "^0.4.0", - "is-npm": "^6.0.0", - "is-yarn-global": "^0.4.0", - "latest-version": "^7.0.0", - "pupa": "^3.1.0", - "semver": "^7.3.7", - "semver-diff": "^4.0.0", - "xdg-basedir": "^5.1.0" - }, - "dependencies": { - "chalk": { - "version": "5.2.0", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "uri-js": { - "version": "4.4.1", - "requires": { - "punycode": "^2.1.0" - } - }, - "use-isomorphic-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", - "requires": {} - }, - "util-deprecate": { - "version": "1.0.2" - }, - "uvu": { - "version": "0.5.6", - "dev": true, - "requires": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" - } - }, - "v8-compile-cache": { - "version": "2.3.0", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vfile": { - "version": "5.3.5", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - } - }, - "vfile-find-up": { - "version": "6.0.0", - "dev": true, - "requires": { - "to-vfile": "^7.0.0", - "vfile": "^5.0.0" - } - }, - "vfile-location": { - "version": "4.0.1", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "vfile": "^5.0.0" - } - }, - "vfile-message": { - "version": "3.1.2", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" - } - }, - "vfile-reporter": { - "version": "7.0.5", - "dev": true, - "requires": { - "@types/supports-color": "^8.0.0", - "string-width": "^5.0.0", - "supports-color": "^9.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile": "^5.0.0", - "vfile-message": "^3.0.0", - "vfile-sort": "^3.0.0", - "vfile-statistics": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "supports-color": { - "version": "9.3.1", - "dev": true - } - } - }, - "vfile-sort": { - "version": "3.0.1", - "dev": true, - "requires": { - "vfile": "^5.0.0", - "vfile-message": "^3.0.0" - } - }, - "vfile-statistics": { - "version": "2.0.1", - "dev": true, - "requires": { - "vfile": "^5.0.0", - "vfile-message": "^3.0.0" - } - }, - "walk-up-path": { - "version": "1.0.0", - "dev": true - }, - "watchpack": { - "version": "2.4.0", - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "web-namespaces": { - "version": "2.0.1", - "dev": true - }, - "webpack": { - "version": "5.76.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz", - "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==", - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "@types/estree": { - "version": "0.0.51" - }, - "acorn": { - "version": "8.8.1" - }, - "acorn-import-assertions": { - "version": "1.8.0", - "requires": {} - }, - "enhanced-resolve": { - "version": "5.10.0", - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "schema-utils": { - "version": "3.1.1", - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "tapable": { - "version": "2.2.1" - } - } - }, - "webpack-cli": { - "version": "4.10.0", - "dev": true, - "requires": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "cross-spawn": "^7.0.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "dev": true - } - } - }, - "webpack-merge": { - "version": "5.8.0", - "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - } - }, - "webpack-sources": { - "version": "3.2.3" - }, - "whatwg-fetch": { - "version": "3.6.2" - }, - "which": { - "version": "2.0.2", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "widest-line": { - "version": "4.0.1", - "dev": true, - "requires": { - "string-width": "^5.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "wildcard": { - "version": "2.0.0", - "dev": true - }, - "word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", - "dev": true - }, - "wrap-ansi": { - "version": "8.1.0", - "dev": true, - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "dev": true - }, - "ansi-styles": { - "version": "6.2.1", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "5.1.0", - "dev": true - }, - "xtend": { - "version": "4.0.2" - }, - "yallist": { - "version": "4.0.0", - "dev": true - }, - "yaml": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", - "dev": true - }, - "yargs-parser": { - "version": "21.1.1", - "dev": true - }, - "yocto-queue": { - "version": "1.0.0", - "dev": true - }, - "zwitch": { - "version": "2.0.2", - "dev": true - } } } diff --git a/package.json b/package.json index c37d0353770..a048d2be0f4 100644 --- a/package.json +++ b/package.json @@ -31,10 +31,11 @@ "@babel/eslint-parser": "^7.19.1", "@babel/preset-env": "^7.9.6", "@babel/preset-react": "^7.6.3", - "@types/react": "^18.0.26", - "@types/react-dom": "^18.0.9", "@types/c3": "^0.7.8", "@types/d3": "^7.4.0", + "@types/papaparse": "^5.3.11", + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.9", "@types/react-redux": "7.1.16", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", diff --git a/php/libraries/NDB_BVL_Instrument.class.inc b/php/libraries/NDB_BVL_Instrument.class.inc index b29043e4591..b2a1ab26cfd 100644 --- a/php/libraries/NDB_BVL_Instrument.class.inc +++ b/php/libraries/NDB_BVL_Instrument.class.inc @@ -4,7 +4,7 @@ use \Psr\Http\Server\RequestHandlerInterface; use \Psr\Http\Message\ResponseInterface; use \Loris\StudyEntities\Candidate\CandID; -use \LORIS\instruments\DictionaryItem; +use \LORIS\Data\Dictionary\DictionaryItem; /** * Base class for all LORIS behavioural instruments. @@ -1407,7 +1407,7 @@ abstract class NDB_BVL_Instrument extends NDB_Page $allValues = $this->getInstanceData(); $fieldName = substr($field->getName(), strlen($this->testName)+1); - return $allValues[$fieldName]; + return $allValues[$fieldName] ?? ''; } private ?SessionID $sessionID; diff --git a/smarty/templates/main.tpl b/smarty/templates/main.tpl index 323deca0e32..ec4b517917c 100644 --- a/smarty/templates/main.tpl +++ b/smarty/templates/main.tpl @@ -27,12 +27,14 @@ {$study_title}