@vitessce/vit-s 3.6.7 → 3.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"TitleInfo.d.ts","sourceRoot":"","sources":["../src/TitleInfo.js"],"names":[],"mappings":"AA6JA,mDA6DC"}
1
+ {"version":3,"file":"TitleInfo.d.ts","sourceRoot":"","sources":["../src/TitleInfo.js"],"names":[],"mappings":"AAmNA,mDAoEC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useState, useMemo } from 'react';
3
3
  import clsx from 'clsx';
4
- import { makeStyles, MenuItem, IconButton, Link, CloudDownload as CloudDownloadIcon, ArrowDropDown as ArrowDropDownIcon, ArrowDropUp as ArrowDropUpIcon, Settings as SettingsIcon, Close as CloseIcon, Help as HelpIcon, } from '@vitessce/styles';
4
+ import { makeStyles, MenuItem, IconButton, Link, List, Alert, CloudDownload as CloudDownloadIcon, ArrowDropDown as ArrowDropDownIcon, ArrowDropUp as ArrowDropUpIcon, Settings as SettingsIcon, Close as CloseIcon, Help as HelpIcon, Warning as WarningIcon, } from '@vitessce/styles';
5
5
  import { TOOLTIP_ANCESTOR } from './classNames.js';
6
6
  import LoadingIndicator from './LoadingIndicator.js';
7
7
  import { PopperMenu } from './shared-mui/components.js';
@@ -46,6 +46,18 @@ const useStyles = makeStyles()(theme => ({
46
46
  boxShadow: '0 0 10px rgba(0, 0, 0, 0.2)',
47
47
  border: '10px solid grey',
48
48
  },
49
+ errorList: {
50
+ width: '100%',
51
+ maxWidth: 300,
52
+ padding: '0 4px',
53
+ },
54
+ errorListAlert: {
55
+ marginTop: '2px',
56
+ marginBottom: '2px',
57
+ },
58
+ errorListItemText: {
59
+ fontSize: '12px',
60
+ },
49
61
  }));
50
62
  function SettingsIconWithArrow({ open }) {
51
63
  return (_jsxs(_Fragment, { children: [_jsx(SettingsIcon, {}), open ? _jsx(ArrowDropUpIcon, {}) : _jsx(ArrowDropDownIcon, {})] }));
@@ -55,7 +67,7 @@ function PlotOptions(props) {
55
67
  const [open, setOpen] = useState(false);
56
68
  const { classes } = useStyles();
57
69
  const buttonIcon = useMemo(() => (_jsx(SettingsIconWithArrow, { open: open })), [open]);
58
- return (options ? (_jsx(PopperMenu, { open: open, setOpen: setOpen, buttonIcon: buttonIcon, buttonClassName: classes.iconButton, placement: "bottom-end", "aria-label": "Open plot options menu", children: options })) : null);
70
+ return (options ? (_jsx(PopperMenu, { open: open, setOpen: setOpen, buttonIcon: buttonIcon, buttonClassName: classes.iconButton, placement: "bottom-end", title: "Plot Options", "aria-label": "Open plot options menu", children: options })) : null);
59
71
  }
60
72
  function CloudDownloadIconWithArrow({ open }) {
61
73
  return (_jsxs(_Fragment, { children: [_jsx(CloudDownloadIcon, {}), open ? _jsx(ArrowDropUpIcon, {}) : _jsx(ArrowDropDownIcon, {})] }));
@@ -65,25 +77,34 @@ function DownloadOptions(props) {
65
77
  const [open, setOpen] = useState(false);
66
78
  const { classes } = useStyles();
67
79
  const buttonIcon = useMemo(() => (_jsx(CloudDownloadIconWithArrow, { open: open })), [open]);
68
- return (urls && urls.length ? (_jsx(PopperMenu, { open: open, setOpen: setOpen, buttonIcon: buttonIcon, buttonClassName: classes.iconButton, placement: "bottom-end", "aria-label": "Open download options menu", children: urls.map(({ url, name }) => (_jsx(MenuItem, { dense: true, "aria-label": `Click to download ${name}`, children: _jsxs(Link, { underline: "always", href: url, target: "_blank", rel: "noopener", className: classes.downloadLink, children: ["Download ", name] }) }, `${url}_${name}`))) })) : null);
80
+ return (urls && urls.length ? (_jsx(PopperMenu, { open: open, setOpen: setOpen, buttonIcon: buttonIcon, buttonClassName: classes.iconButton, placement: "bottom-end", title: "Download Options", "aria-label": "Open download options menu", children: urls.map(({ url, name }) => (_jsx(MenuItem, { dense: true, "aria-label": `Click to download ${name}`, children: _jsxs(Link, { underline: "always", href: url, target: "_blank", rel: "noopener", className: classes.downloadLink, children: ["Download ", name] }) }, `${url}_${name}`))) })) : null);
69
81
  }
70
82
  function HelpButton(props) {
71
83
  const { helpText } = props;
72
84
  const [open, setOpen] = useState(false);
73
85
  const { classes } = useStyles();
74
- return (_jsx(PopperMenu, { open: open, setOpen: setOpen, buttonIcon: _jsx(HelpIcon, {}), buttonClassName: classes.iconButton, placement: "bottom-end", "aria-label": "Open help info", withPaper: false, children: _jsx("span", { className: classes.helpTextSpan, children: helpText }) }));
86
+ return (_jsx(PopperMenu, { open: open, setOpen: setOpen, buttonIcon: _jsx(HelpIcon, {}), buttonClassName: classes.iconButton, placement: "bottom-end", title: "Help Info", "aria-label": "Open help info", withPaper: false, children: _jsx("span", { className: classes.helpTextSpan, children: helpText }) }));
87
+ }
88
+ function ErrorInfo(props) {
89
+ const { errors } = props;
90
+ const [open, setOpen] = useState(false);
91
+ const { classes } = useStyles();
92
+ return (_jsx(PopperMenu, { open: open, setOpen: setOpen, buttonIcon: _jsx(WarningIcon, { color: "error" }), buttonClassName: classes.iconButton, placement: "bottom-end", title: "View Errors", "aria-label": "Open error info", children: _jsx(List, { className: classes.errorList, children: errors.map((error, index) => (_jsxs(Alert
93
+ // eslint-disable-next-line react/no-array-index-key
94
+ , { severity: "error", className: classes.errorListAlert, slots: { message: 'span' }, slotProps: { message: { className: classes.errorListItemText } }, children: [error.name, ": ", error.message] }, `${index}-${error.name}-${error.message}`))) }) }));
75
95
  }
76
96
  function ClosePaneButton(props) {
77
97
  const { removeGridComponent } = props;
78
98
  const { classes } = useStyles();
79
- return (_jsx(IconButton, { onClick: removeGridComponent, size: "small", className: classes.iconButton, title: "close", "aria-label": "Close panel button", children: _jsx(CloseIcon, {}) }));
99
+ return (_jsx(IconButton, { onClick: removeGridComponent, size: "small", className: classes.iconButton, title: "Close View", "aria-label": "Close panel button", children: _jsx(CloseIcon, {}) }));
80
100
  }
81
101
  export function TitleInfo(props) {
82
- const { title, info, children, isScroll, isSpatial, removeGridComponent, urls, isReady, options, closeButtonVisible = true, downloadButtonVisible = true, helpText, withPadding = true, } = props;
102
+ const { title, info, children, isScroll, isSpatial, removeGridComponent, urls, isReady, options, closeButtonVisible = true, downloadButtonVisible = true, helpText, withPadding = true, errors: errorsProp, } = props;
103
+ const errors = errorsProp?.filter(Boolean);
83
104
  const { classes } = useTitleStyles();
84
105
  return (
85
106
  // d-flex without wrapping div is not always full height; I don't understand the root cause.
86
- _jsxs(_Fragment, { children: [_jsxs("div", { className: classes.title, role: "banner", children: [_jsx("div", { className: classes.titleLeft, role: "heading", "aria-level": "1", children: title }), _jsx("div", { className: classes.titleInfo, title: info, role: "note", children: info }), _jsxs("div", { className: classes.titleButtons, role: "toolbar", "aria-label": "Plot options and controls", children: [_jsx(PlotOptions, { options: options }), downloadButtonVisible ? (_jsx(DownloadOptions, { urls: urls })) : null, helpText ? (_jsx(HelpButton, { helpText: helpText })) : null, closeButtonVisible && removeGridComponent ? (_jsx(ClosePaneButton, { removeGridComponent: removeGridComponent })) : null] })] }), _jsxs("div", { className: clsx(TOOLTIP_ANCESTOR, classes.card, {
107
+ _jsxs(_Fragment, { children: [_jsxs("div", { className: classes.title, role: "banner", children: [_jsx("div", { className: classes.titleLeft, role: "heading", "aria-level": "1", children: title }), _jsx("div", { className: classes.titleInfo, title: info, role: "note", children: info }), _jsxs("div", { className: classes.titleButtons, role: "toolbar", "aria-label": "Plot options and controls", children: [_jsx(PlotOptions, { options: options }), downloadButtonVisible ? (_jsx(DownloadOptions, { urls: urls })) : null, Array.isArray(errors) && errors.length > 0 ? (_jsx(ErrorInfo, { errors: errors })) : null, helpText ? (_jsx(HelpButton, { helpText: helpText })) : null, closeButtonVisible && removeGridComponent ? (_jsx(ClosePaneButton, { removeGridComponent: removeGridComponent })) : null] })] }), _jsxs("div", { className: clsx(TOOLTIP_ANCESTOR, classes.card, {
87
108
  [classes.scrollCard]: isScroll,
88
109
  [classes.spatialCard]: isSpatial,
89
110
  [classes.noScrollCard]: !isScroll && !isSpatial,
@@ -1 +1 @@
1
- {"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AAoCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,4BApCG;IAAsB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGW,cAAc,EAApC,SAAS,GAAC,IAAI;IAEC,kBAAkB,EAAjC,OAAO;IAEM,SAAS,EAAtB,KAAK;IACQ,SAAS,EAAtB,KAAK;IACQ,cAAc,EAA3B,KAAK;IACQ,iBAAiB,EAA9B,KAAK;IACc,OAAO,EAA1B,IAAI,GAAC,MAAM;IACI,QAAQ,EAAvB,OAAO;IACQ,SAAS,EAAxB,OAAO;IACY,QAAQ,EAA3B,IAAI,GAAC,MAAM;CAErB,eAiPA"}
1
+ {"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AAqCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,4BApCG;IAAsB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGW,cAAc,EAApC,SAAS,GAAC,IAAI;IAEC,kBAAkB,EAAjC,OAAO;IAEM,SAAS,EAAtB,KAAK;IACQ,SAAS,EAAtB,KAAK;IACQ,cAAc,EAA3B,KAAK;IACQ,iBAAiB,EAA9B,KAAK;IACc,OAAO,EAA1B,IAAI,GAAC,MAAM;IACI,QAAQ,EAAvB,OAAO;IACQ,SAAS,EAAxB,OAAO;IACY,QAAQ,EAA3B,IAAI,GAAC,MAAM;CAErB,eA0PA"}
package/dist-tsc/VitS.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useState, useEffect, useMemo, useCallback, useLayoutEffect } from 'react';
3
3
  import { ThemeProvider, CacheProvider, createCache, } from '@vitessce/styles';
4
- import { QueryClient, QueryClientProvider, } from '@tanstack/react-query';
4
+ import { QueryCache, QueryClient, QueryClientProvider, } from '@tanstack/react-query';
5
5
  import { isEqual } from 'lodash-es';
6
6
  import { buildConfigSchema, latestConfigSchema } from '@vitessce/schemas';
7
- import { setLogLevel, setDebugMode, DEFAULT_LOG_LEVEL, DEFAULT_DEBUG_MODE, } from '@vitessce/globals';
7
+ import { log, setLogLevel, setDebugMode, DEFAULT_LOG_LEVEL, DEFAULT_DEBUG_MODE, } from '@vitessce/globals';
8
8
  import { muiTheme } from './shared-mui/styles.js';
9
9
  import { ViewConfigProvider, createViewConfigStore, AuxiliaryProvider, createAuxiliaryStore, } from './state/hooks.js';
10
10
  import VitessceGrid from './VitessceGrid.js';
@@ -140,6 +140,15 @@ export function VitS(props) {
140
140
  retry: 2,
141
141
  },
142
142
  },
143
+ // Reference: https://tkdodo.eu/blog/react-query-error-handling#the-global-callbacks
144
+ queryCache: new QueryCache({
145
+ onError: (error) => {
146
+ log.error(error);
147
+ if (onWarn) {
148
+ onWarn(error.message);
149
+ }
150
+ },
151
+ }),
143
152
  // TODO: should the queryClient be shared? Or have an option to be shared
144
153
  // (e.g., based on remountOnUidChange)?
145
154
  }), [configKey]);
@@ -1,9 +1,3 @@
1
- /**
2
- * Warn via publishing to the console
3
- * and to the global warning store.
4
- * @param {AbstractLoaderError} error An error instance.
5
- */
6
- export function warn(error: AbstractLoaderError, setWarning: any): void;
7
1
  /**
8
2
  * Initialize values in the coordination space.
9
3
  * @param {object} values Object where
@@ -34,7 +28,7 @@ export function dataQueryFn(ctx: any): Promise<any>;
34
28
  * @param {object} initialCoordinationValues Object where
35
29
  * keys are coordination type names with the prefix 'initialize',
36
30
  * values are initialization preferences as boolean values.
37
- * @returns {array} [data, status, urls] where
31
+ * @returns {array} [data, status, urls, error] where
38
32
  * cells is an object and cellsCount is the
39
33
  * number of items in the cells object.
40
34
  */
@@ -56,11 +50,11 @@ export function useDataType(dataType: any, loaders: object, dataset: string, isR
56
50
  * @param {object} initialCoordinationValues Object where
57
51
  * keys are coordination type names with the prefix 'initialize',
58
52
  * values are initialization preferences as boolean values.
59
- * @returns {array} [cells, cellsCount] where
60
- * cells is an object and cellsCount is the
61
- * number of items in the cells object.
53
+ * @param {object} matchOnObj Coordination values used to obtain a matching loader.
54
+ * @param {function} mergeCoordination Function to merge coordination values.
55
+ * @param {string} viewUid The view UID to use for merging coordination values.
56
+ * @returns {array} [data, status, urls, errors]
62
57
  */
63
- export function useDataTypeMulti(dataType: any, loaders: object, dataset: string, isRequired: boolean, coordinationSetters: object, initialCoordinationValues: object, matchOnObj: any, mergeCoordination: any, viewUid: any): array;
58
+ export function useDataTypeMulti(dataType: any, loaders: object, dataset: string, isRequired: boolean, coordinationSetters: object, initialCoordinationValues: object, matchOnObj: object, mergeCoordination: Function, viewUid: string): array;
64
59
  export function useHasLoader(loaders: any, dataset: any, dataType: any, matchOn: any): boolean;
65
- import { AbstractLoaderError } from '@vitessce/abstract';
66
60
  //# sourceMappingURL=data-hook-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-hook-utils.d.ts","sourceRoot":"","sources":["../src/data-hook-utils.js"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,4BAFW,mBAAmB,yBAS7B;AAED;;;;;;;;;;GAUG;AACH,8CATW,MAAM,WAGN,MAAM,iBAGN,MAAM,QAiBhB;AAGD,oDAuBC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,oDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,iBAGJ,KAAK,CAiDjB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,yDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,0DAGJ,KAAK,CAsFjB;AAED,+FAGC;oCA1PM,oBAAoB"}
1
+ {"version":3,"file":"data-hook-utils.d.ts","sourceRoot":"","sources":["../src/data-hook-utils.js"],"names":[],"mappings":"AAeA;;;;;;;;;;GAUG;AACH,8CATW,MAAM,WAGN,MAAM,iBAGN,MAAM,QAiBhB;AAGD,oDAuBC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,oDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,iBAGJ,KAAK,CAwCjB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,yDAjBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,cAGN,MAAM,wCAEN,MAAM,GACJ,KAAK,CA2EjB;AAED,+FAGC"}
@@ -1,23 +1,9 @@
1
1
  import { useEffect, useMemo } from 'react';
2
2
  import { useQuery, useQueries } from '@tanstack/react-query';
3
3
  import { capitalize, getInitialCoordinationScopePrefix, } from '@vitessce/utils';
4
- import { log } from '@vitessce/globals';
5
4
  import { STATUS } from '@vitessce/constants-internal';
6
- import { AbstractLoaderError, LoaderNotFoundError, } from '@vitessce/abstract';
7
- import { getMatchingLoader, useMatchingLoader, useSetWarning, } from './state/hooks.js';
8
- /**
9
- * Warn via publishing to the console
10
- * and to the global warning store.
11
- * @param {AbstractLoaderError} error An error instance.
12
- */
13
- export function warn(error, setWarning) {
14
- setWarning(error.message);
15
- log.warn(error.message);
16
- log.error(error.stack);
17
- if (error instanceof AbstractLoaderError) {
18
- error.warnInConsole();
19
- }
20
- }
5
+ import { LoaderNotFoundError, } from '@vitessce/error';
6
+ import { getMatchingLoader, useMatchingLoader, } from './state/hooks.js';
21
7
  /**
22
8
  * Initialize values in the coordination space.
23
9
  * @param {object} values Object where
@@ -63,7 +49,7 @@ export async function dataQueryFn(ctx) {
63
49
  // No loader was found.
64
50
  if (isRequired) {
65
51
  // Status: error
66
- throw new LoaderNotFoundError(loaders, dataset, dataType, matchOn);
52
+ throw new LoaderNotFoundError(`Loader not found for parameters: ${dataset}, ${dataType}, ${JSON.stringify(matchOn)}`);
67
53
  }
68
54
  else {
69
55
  // Status: success
@@ -87,12 +73,11 @@ export async function dataQueryFn(ctx) {
87
73
  * @param {object} initialCoordinationValues Object where
88
74
  * keys are coordination type names with the prefix 'initialize',
89
75
  * values are initialization preferences as boolean values.
90
- * @returns {array} [data, status, urls] where
76
+ * @returns {array} [data, status, urls, error] where
91
77
  * cells is an object and cellsCount is the
92
78
  * number of items in the cells object.
93
79
  */
94
80
  export function useDataType(dataType, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
95
- const setWarning = useSetWarning();
96
81
  const placeholderObject = useMemo(() => ({}), []);
97
82
  const dataQuery = useQuery({
98
83
  // TODO: only enable when loaders has been initialized?
@@ -113,17 +98,11 @@ export function useDataType(dataType, loaders, dataset, isRequired, coordination
113
98
  const loadedData = data?.data || placeholderObject;
114
99
  const coordinationValues = data?.coordinationValues;
115
100
  const urls = data?.urls;
116
- const requestInit = data?.requestInit;
117
101
  useEffect(() => {
118
102
  initCoordinationSpace(coordinationValues, coordinationSetters, initialCoordinationValues);
119
103
  }, [coordinationValues]);
120
- useEffect(() => {
121
- if (error) {
122
- warn(error, setWarning);
123
- }
124
- }, [error, setWarning]);
125
104
  const dataStatus = isFetching ? STATUS.LOADING : status;
126
- return [loadedData, dataStatus, urls, requestInit];
105
+ return [loadedData, dataStatus, urls, error];
127
106
  }
128
107
  /**
129
108
  * Get data from a cells data type loader,
@@ -142,13 +121,13 @@ export function useDataType(dataType, loaders, dataset, isRequired, coordination
142
121
  * @param {object} initialCoordinationValues Object where
143
122
  * keys are coordination type names with the prefix 'initialize',
144
123
  * values are initialization preferences as boolean values.
145
- * @returns {array} [cells, cellsCount] where
146
- * cells is an object and cellsCount is the
147
- * number of items in the cells object.
124
+ * @param {object} matchOnObj Coordination values used to obtain a matching loader.
125
+ * @param {function} mergeCoordination Function to merge coordination values.
126
+ * @param {string} viewUid The view UID to use for merging coordination values.
127
+ * @returns {array} [data, status, urls, errors]
148
128
  */
149
129
  export function useDataTypeMulti(dataType, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOnObj, mergeCoordination, viewUid) {
150
130
  const placeholderObject = useMemo(() => ({}), []);
151
- const setWarning = useSetWarning();
152
131
  const matchOnEntries = matchOnObj ? Object.entries(matchOnObj) : [];
153
132
  const dataQueries = useQueries({
154
133
  // eslint-disable-next-line no-unused-vars
@@ -169,6 +148,7 @@ export function useDataTypeMulti(dataType, loaders, dataset, isRequired, coordin
169
148
  });
170
149
  const anyLoading = dataQueries.some(q => q.isFetching);
171
150
  const anyError = dataQueries.some(q => q.isError);
151
+ const errors = anyError ? dataQueries.filter(q => q.isError).map(q => q.error) : [];
172
152
  // eslint-disable-next-line no-nested-ternary
173
153
  const dataStatus = anyLoading ? STATUS.LOADING : (anyError ? STATUS.ERROR : STATUS.SUCCESS);
174
154
  const isSuccess = dataStatus === STATUS.SUCCESS;
@@ -189,18 +169,11 @@ export function useDataTypeMulti(dataType, loaders, dataset, isRequired, coordin
189
169
  // Deliberate dependency omissions: use indirect dependencies for efficiency.
190
170
  // eslint-disable-next-line react-hooks/exhaustive-deps
191
171
  }, [isSuccess]);
192
- useEffect(() => {
193
- dataQueries.map(q => q.error).filter(e => Boolean(e)).forEach((error) => {
194
- warn(error, setWarning);
195
- });
196
- // Deliberate dependency omissions: use indirect dependencies for efficiency.
197
- // eslint-disable-next-line react-hooks/exhaustive-deps
198
- }, [anyError, setWarning]);
199
172
  // Convert data to object keyed by scopeKey.
200
173
  const data = useMemo(() => Object.fromEntries(matchOnEntries.map(([scopeKey], i) => ([scopeKey, dataQueries[i].data?.data]))), [matchOnObj, dataStatus]);
201
174
  // Convert data to object keyed by scopeKey.
202
175
  const urls = useMemo(() => Object.fromEntries(matchOnEntries.map(([scopeKey], i) => ([scopeKey, dataQueries[i].data?.urls]))), [dataQueries]);
203
- return [data, dataStatus, urls];
176
+ return [data, dataStatus, urls, errors];
204
177
  }
205
178
  export function useHasLoader(loaders, dataset, dataType, matchOn) {
206
179
  const loader = useMatchingLoader(loaders, dataset, dataType, matchOn);
@@ -69,9 +69,55 @@ export function nestFeatureSelectionQueryResults(queryKeyScopeTuples: array, fla
69
69
  * @returns The nested object.
70
70
  */
71
71
  export function nestQueryResults(queryKeyScopeTuples: array, flatQueryResults: array): {};
72
- export function useFeatureSelectionMultiLevel(loaders: any, dataset: any, isRequired: any, matchOnObj: any, selections: any, depth: any): any[];
73
- export function useObsFeatureMatrixIndicesMultiLevel(loaders: any, dataset: any, isRequired: any, matchOnObj: any, depth: any): any[];
74
- export function useObsLocationsMultiLevel(loaders: any, dataset: any, isRequired: any, matchOnObj: any, depth: any): any[];
75
- export function useObsSetsMultiLevel(loaders: any, dataset: any, isRequired: any, matchOnObj: any, depth: any): any[];
76
- export function useObsLabelsMultiLevel(loaders: any, dataset: any, isRequired: any, matchOnObj: any, depth: any): any[];
72
+ /**
73
+ * Get feature values for a multi-level feature selection.
74
+ * @param {object} loaders
75
+ * @param {string} dataset
76
+ * @param {boolean} isRequired
77
+ * @param {object} matchOnObj
78
+ * @param {array} selections
79
+ * @param {number} depth
80
+ * @returns [data, geneName, extents, normData, status, errors]
81
+ */
82
+ export function useFeatureSelectionMultiLevel(loaders: object, dataset: string, isRequired: boolean, matchOnObj: object, selections: array, depth: number): any[];
83
+ /**
84
+ * Get matrix indices for a multi-level coordination.
85
+ * @param {object} loaders
86
+ * @param {string} dataset
87
+ * @param {boolean} isRequired
88
+ * @param {object} matchOnObj
89
+ * @param {number} depth
90
+ * @returns [data, dataStatus, errors]
91
+ */
92
+ export function useObsFeatureMatrixIndicesMultiLevel(loaders: object, dataset: string, isRequired: boolean, matchOnObj: object, depth: number): any[];
93
+ /**
94
+ * Wrapper around useDataTypeMultiLevel.
95
+ * @param {object} loaders
96
+ * @param {string} dataset
97
+ * @param {boolean} isRequired
98
+ * @param {object} matchOnObj
99
+ * @param {number} depth
100
+ * @returns {array} [data, status, errors]
101
+ */
102
+ export function useObsLocationsMultiLevel(loaders: object, dataset: string, isRequired: boolean, matchOnObj: object, depth: number): array;
103
+ /**
104
+ * Wrapper around useDataTypeMultiLevel.
105
+ * @param {object} loaders
106
+ * @param {string} dataset
107
+ * @param {boolean} isRequired
108
+ * @param {object} matchOnObj
109
+ * @param {number} depth
110
+ * @returns {array} [data, status, errors]
111
+ */
112
+ export function useObsSetsMultiLevel(loaders: object, dataset: string, isRequired: boolean, matchOnObj: object, depth: number): array;
113
+ /**
114
+ * Wrapper around useDataTypeMultiLevel.
115
+ * @param {object} loaders
116
+ * @param {string} dataset
117
+ * @param {boolean} isRequired
118
+ * @param {object} matchOnObj
119
+ * @param {number} depth
120
+ * @returns {array} [data, status, errors]
121
+ */
122
+ export function useObsLabelsMultiLevel(loaders: object, dataset: string, isRequired: boolean, matchOnObj: object, depth: number): array;
77
123
  //# sourceMappingURL=data-hooks-multilevel-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-hooks-multilevel-utils.d.ts","sourceRoot":"","sources":["../src/data-hooks-multilevel-utils.js"],"names":[],"mappings":"AA+CA;;;;;;;;;;;;;GAaG;AACH,mEAPW,MAAM,cACN,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAmBhB;AA8BD;;;;;;;;;;;;GAYG;AACH,gEANW,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAiBhB;AA+BD;;;;;;;;;;;;GAYG;AACH,mDANW,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAiBhB;AAuBD;;;;;;;;;;GAUG;AACH,oDALW,MAAM,EAAE,WACR,MAAM,+BAOhB;AAED;;;;;;GAMG;AACH,sEALW,KAAK,oBACL,KAAK,MAcf;AAED;;;;;;GAMG;AACH,sDALW,KAAK,oBACL,KAAK,MAgBf;AA+DD,gJA6DC;AAuCD,sIAuDC;AAyDD,2HAQC;AAED,sHAQC;AAED,wHAQC"}
1
+ {"version":3,"file":"data-hooks-multilevel-utils.d.ts","sourceRoot":"","sources":["../src/data-hooks-multilevel-utils.js"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;GAaG;AACH,mEAPW,MAAM,cACN,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAmBhB;AA8BD;;;;;;;;;;;;GAYG;AACH,gEANW,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAiBhB;AA+BD;;;;;;;;;;;;GAYG;AACH,mDANW,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAiBhB;AAuBD;;;;;;;;;;GAUG;AACH,oDALW,MAAM,EAAE,WACR,MAAM,+BAOhB;AAED;;;;;;GAMG;AACH,sEALW,KAAK,oBACL,KAAK,MAcf;AAED;;;;;;GAMG;AACH,sDALW,KAAK,oBACL,KAAK,MAgBf;AA+DD;;;;;;;;;GASG;AACH,uDARW,MAAM,WACN,MAAM,cACN,OAAO,cACP,MAAM,cACN,KAAK,SACL,MAAM,SAoDhB;AAuCD;;;;;;;;GAQG;AACH,8DAPW,MAAM,WACN,MAAM,cACN,OAAO,cACP,MAAM,SACN,MAAM,SA8ChB;AAuDD;;;;;;;;GAQG;AACH,mDAPW,MAAM,WACN,MAAM,cACN,OAAO,cACP,MAAM,SACN,MAAM,GACJ,KAAK,CAUjB;AAED;;;;;;;;GAQG;AACH,8CAPW,MAAM,WACN,MAAM,cACN,OAAO,cACP,MAAM,SACN,MAAM,GACJ,KAAK,CAUjB;AAED;;;;;;;;GAQG;AACH,gDAPW,MAAM,WACN,MAAM,cACN,OAAO,cACP,MAAM,SACN,MAAM,GACJ,KAAK,CAUjB"}
@@ -1,10 +1,10 @@
1
- import { useEffect, useMemo } from 'react';
1
+ import { useMemo } from 'react';
2
2
  import { useQueries } from '@tanstack/react-query';
3
3
  import { extent } from 'd3-array';
4
4
  import { DataType, STATUS } from '@vitessce/constants-internal';
5
- import { LoaderNotFoundError, } from '@vitessce/abstract';
6
- import { getMatchingLoader, useSetWarning, } from './state/hooks.js';
7
- import { warn, dataQueryFn, } from './data-hook-utils.js';
5
+ import { LoaderNotFoundError, } from '@vitessce/error';
6
+ import { getMatchingLoader, } from './state/hooks.js';
7
+ import { dataQueryFn, } from './data-hook-utils.js';
8
8
  function getFeatureSelectionQueryKeyScopeTuplesAux(allSelections, allMatchOnObj, depth, dataset, dataType, isRequired, prevLevelScopes, currSelection, currMatchOn) {
9
9
  // Base case
10
10
  if (depth === 0) {
@@ -230,14 +230,23 @@ async function featureSelectionQueryFn(ctx) {
230
230
  }
231
231
  // No loader was found.
232
232
  if (isRequired) {
233
- throw new LoaderNotFoundError(loaders, dataset, dataType, matchOn);
233
+ throw new LoaderNotFoundError(`Loader not found for parameters: ${dataset}, ${dataType}, ${JSON.stringify(matchOn)}`);
234
234
  }
235
235
  else {
236
236
  return { data: null, dataKey: null };
237
237
  }
238
238
  }
239
+ /**
240
+ * Get feature values for a multi-level feature selection.
241
+ * @param {object} loaders
242
+ * @param {string} dataset
243
+ * @param {boolean} isRequired
244
+ * @param {object} matchOnObj
245
+ * @param {array} selections
246
+ * @param {number} depth
247
+ * @returns [data, geneName, extents, normData, status, errors]
248
+ */
239
249
  export function useFeatureSelectionMultiLevel(loaders, dataset, isRequired, matchOnObj, selections, depth) {
240
- const setWarning = useSetWarning();
241
250
  // Create a flat list of tuples (queryKey, scopeInfo).
242
251
  const queryKeyScopeTuples = useMemo(() => getFeatureSelectionQueryKeyScopeTuples(selections, matchOnObj, depth, dataset, DataType.OBS_FEATURE_MATRIX, isRequired), [selections, matchOnObj, depth, dataset]);
243
252
  const featureQueries = useQueries({
@@ -251,22 +260,13 @@ export function useFeatureSelectionMultiLevel(loaders, dataset, isRequired, matc
251
260
  });
252
261
  const anyLoading = featureQueries.some(q => q.isFetching);
253
262
  const anyError = featureQueries.some(q => q.isError);
263
+ const errors = anyError ? featureQueries.filter(q => q.isError).map(q => q.error) : [];
254
264
  // eslint-disable-next-line no-nested-ternary
255
265
  const dataStatus = anyLoading ? STATUS.LOADING : (anyError ? STATUS.ERROR : STATUS.SUCCESS);
256
266
  const flatGeneData = featureQueries.map(q => q.data?.data || null);
257
267
  const flatLoadedGeneName = featureQueries.map(q => q.data?.dataKey || null);
258
268
  const flatExtents = featureQueries.map(q => q.data?.dataExtent || null);
259
269
  const flatNormData = featureQueries.map(q => q.data?.normData || null);
260
- useEffect(() => {
261
- featureQueries
262
- .map(q => q.error)
263
- .filter(e => Boolean(e))
264
- .forEach((error) => {
265
- warn(error, setWarning);
266
- });
267
- // Deliberate dependency omissions: use indirect dependencies for efficiency.
268
- // eslint-disable-next-line react-hooks/exhaustive-deps
269
- }, [anyError, setWarning]);
270
270
  // Need to re-nest the geneData and the loadedGeneName info.
271
271
  const [geneData, loadedGeneName, extents, normData] = useMemo(() => {
272
272
  const nestedGeneData = nestFeatureSelectionQueryResults(queryKeyScopeTuples, flatGeneData);
@@ -282,7 +282,7 @@ export function useFeatureSelectionMultiLevel(loaders, dataset, isRequired, matc
282
282
  // Reference: https://github.com/TanStack/query/issues/3049#issuecomment-1253201068
283
283
  // eslint-disable-next-line react-hooks/exhaustive-deps
284
284
  }, [featureQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
285
- return [geneData, loadedGeneName, extents, normData, dataStatus];
285
+ return [geneData, loadedGeneName, extents, normData, dataStatus, errors];
286
286
  }
287
287
  async function matrixIndicesQueryFn(ctx) {
288
288
  // (copied from useFeatureSelection queryFn)
@@ -317,14 +317,22 @@ async function matrixIndicesQueryFn(ctx) {
317
317
  }
318
318
  // No loader was found.
319
319
  if (isRequired) {
320
- throw new LoaderNotFoundError(loaders, dataset, dataType, matchOn);
320
+ throw new LoaderNotFoundError(`Loader not found for parameters: ${dataset}, ${dataType}, ${JSON.stringify(matchOn)}`);
321
321
  }
322
322
  else {
323
323
  return { data: null, dataKey: null };
324
324
  }
325
325
  }
326
+ /**
327
+ * Get matrix indices for a multi-level coordination.
328
+ * @param {object} loaders
329
+ * @param {string} dataset
330
+ * @param {boolean} isRequired
331
+ * @param {object} matchOnObj
332
+ * @param {number} depth
333
+ * @returns [data, dataStatus, errors]
334
+ */
326
335
  export function useObsFeatureMatrixIndicesMultiLevel(loaders, dataset, isRequired, matchOnObj, depth) {
327
- const setWarning = useSetWarning();
328
336
  // Create a flat list of tuples (queryKey, scopeInfo).
329
337
  const queryKeyScopeTuples = useMemo(() => getMatrixIndicesQueryKeyScopeTuples(matchOnObj, depth, dataset, DataType.OBS_FEATURE_MATRIX, isRequired), [matchOnObj, depth, dataset]);
330
338
  const indicesQueries = useQueries({
@@ -338,19 +346,10 @@ export function useObsFeatureMatrixIndicesMultiLevel(loaders, dataset, isRequire
338
346
  });
339
347
  const anyLoading = indicesQueries.some(q => q.isFetching);
340
348
  const anyError = indicesQueries.some(q => q.isError);
349
+ const errors = anyError ? indicesQueries.filter(q => q.isError).map(q => q.error) : [];
341
350
  // eslint-disable-next-line no-nested-ternary
342
351
  const dataStatus = anyLoading ? STATUS.LOADING : (anyError ? STATUS.ERROR : STATUS.SUCCESS);
343
352
  const flatIndicesData = indicesQueries.map(q => q.data?.data || null);
344
- useEffect(() => {
345
- indicesQueries
346
- .map(q => q.error)
347
- .filter(e => Boolean(e))
348
- .forEach((error) => {
349
- warn(error, setWarning);
350
- });
351
- // Deliberate dependency omissions: use indirect dependencies for efficiency.
352
- // eslint-disable-next-line react-hooks/exhaustive-deps
353
- }, [anyError, setWarning]);
354
353
  // Need to re-nest the geneData and the loadedGeneName info.
355
354
  const indicesData = useMemo(() => {
356
355
  const nestedIndicesData = nestQueryResults(queryKeyScopeTuples, flatIndicesData);
@@ -365,10 +364,19 @@ export function useObsFeatureMatrixIndicesMultiLevel(loaders, dataset, isRequire
365
364
  // so we also use queryKeyScopeTuples as a dependency.
366
365
  // eslint-disable-next-line react-hooks/exhaustive-deps
367
366
  }, [indicesQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
368
- return [indicesData, dataStatus];
367
+ return [indicesData, dataStatus, errors];
369
368
  }
369
+ /**
370
+ * Get data for multi-level coordination.
371
+ * @param {object} loaders
372
+ * @param {string} dataset
373
+ * @param {boolean} isRequired
374
+ * @param {object} matchOnObj
375
+ * @param {number} depth
376
+ * @param {string} dataType
377
+ * @returns {array} [data, status, errors]
378
+ */
370
379
  function useDataTypeMultiLevel(loaders, dataset, isRequired, matchOnObj, depth, dataType) {
371
- const setWarning = useSetWarning();
372
380
  // Create a flat list of tuples (queryKey, scopeInfo).
373
381
  const queryKeyScopeTuples = useMemo(() => getQueryKeyScopeTuples(matchOnObj, depth, dataset, dataType, isRequired), [matchOnObj, depth, dataset]);
374
382
  const locationsQueries = useQueries({
@@ -382,19 +390,10 @@ function useDataTypeMultiLevel(loaders, dataset, isRequired, matchOnObj, depth,
382
390
  });
383
391
  const anyLoading = locationsQueries.some(q => q.isFetching);
384
392
  const anyError = locationsQueries.some(q => q.isError);
393
+ const errors = anyError ? locationsQueries.filter(q => q.isError).map(q => q.error) : [];
385
394
  // eslint-disable-next-line no-nested-ternary
386
395
  const dataStatus = anyLoading ? STATUS.LOADING : (anyError ? STATUS.ERROR : STATUS.SUCCESS);
387
396
  const flatIndicesData = locationsQueries.map(q => q.data?.data || null);
388
- useEffect(() => {
389
- locationsQueries
390
- .map(q => q.error)
391
- .filter(e => Boolean(e))
392
- .forEach((error) => {
393
- warn(error, setWarning);
394
- });
395
- // Deliberate dependency omissions: use indirect dependencies for efficiency.
396
- // eslint-disable-next-line react-hooks/exhaustive-deps
397
- }, [anyError, setWarning]);
398
397
  // Need to re-nest the geneData and the loadedGeneName info.
399
398
  const locationsData = useMemo(() => {
400
399
  const nestedIndicesData = nestQueryResults(queryKeyScopeTuples, flatIndicesData);
@@ -407,14 +406,41 @@ function useDataTypeMultiLevel(loaders, dataset, isRequired, matchOnObj, depth,
407
406
  // Reference: https://github.com/TanStack/query/issues/3049#issuecomment-1253201068
408
407
  // eslint-disable-next-line react-hooks/exhaustive-deps
409
408
  }, [locationsQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
410
- return [locationsData, dataStatus];
409
+ return [locationsData, dataStatus, errors];
411
410
  }
411
+ /**
412
+ * Wrapper around useDataTypeMultiLevel.
413
+ * @param {object} loaders
414
+ * @param {string} dataset
415
+ * @param {boolean} isRequired
416
+ * @param {object} matchOnObj
417
+ * @param {number} depth
418
+ * @returns {array} [data, status, errors]
419
+ */
412
420
  export function useObsLocationsMultiLevel(loaders, dataset, isRequired, matchOnObj, depth) {
413
421
  return useDataTypeMultiLevel(loaders, dataset, isRequired, matchOnObj, depth, DataType.OBS_LOCATIONS);
414
422
  }
423
+ /**
424
+ * Wrapper around useDataTypeMultiLevel.
425
+ * @param {object} loaders
426
+ * @param {string} dataset
427
+ * @param {boolean} isRequired
428
+ * @param {object} matchOnObj
429
+ * @param {number} depth
430
+ * @returns {array} [data, status, errors]
431
+ */
415
432
  export function useObsSetsMultiLevel(loaders, dataset, isRequired, matchOnObj, depth) {
416
433
  return useDataTypeMultiLevel(loaders, dataset, isRequired, matchOnObj, depth, DataType.OBS_SETS);
417
434
  }
435
+ /**
436
+ * Wrapper around useDataTypeMultiLevel.
437
+ * @param {object} loaders
438
+ * @param {string} dataset
439
+ * @param {boolean} isRequired
440
+ * @param {object} matchOnObj
441
+ * @param {number} depth
442
+ * @returns {array} [data, status, errors]
443
+ */
418
444
  export function useObsLabelsMultiLevel(loaders, dataset, isRequired, matchOnObj, depth) {
419
445
  return useDataTypeMultiLevel(loaders, dataset, isRequired, matchOnObj, depth, DataType.OBS_LABELS);
420
446
  }
@@ -1,8 +1,64 @@
1
- export function useSegmentationMultiFeatureSelection(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
2
- export function useSpotMultiFeatureSelection(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
3
- export function useSegmentationMultiObsFeatureMatrixIndices(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
4
- export function useSpotMultiObsFeatureMatrixIndices(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
5
- export function usePointMultiObsLabels(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
6
- export function useSegmentationMultiObsLocations(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
7
- export function useSegmentationMultiObsSets(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
1
+ /**
2
+ * Wrapper around useFeatureSelectionMultiLevel.
3
+ * @param {object} coordinationScopes
4
+ * @param {object} coordinationScopesBy
5
+ * @param {object} loaders
6
+ * @param {string} dataset
7
+ * @returns {array} [featureData, loadedSelections, extents, normData, featureStatus, errors]
8
+ */
9
+ export function useSegmentationMultiFeatureSelection(coordinationScopes: object, coordinationScopesBy: object, loaders: object, dataset: string): array;
10
+ /**
11
+ * Wrapper around useFeatureSelectionMultiLevel.
12
+ * @param {object} coordinationScopes
13
+ * @param {object} coordinationScopesBy
14
+ * @param {object} loaders
15
+ * @param {string} dataset
16
+ * @returns {array} [featureData, loadedSelections, extents, normData, featureStatus, errors]
17
+ */
18
+ export function useSpotMultiFeatureSelection(coordinationScopes: object, coordinationScopesBy: object, loaders: object, dataset: string): array;
19
+ /**
20
+ * Wrapper around useObsFeatureMatrixIndicesMultiLevel.
21
+ * @param {object} coordinationScopes
22
+ * @param {object} coordinationScopesBy
23
+ * @param {object} loaders
24
+ * @param {string} dataset
25
+ * @returns {array} [indicesData, status, errors]
26
+ */
27
+ export function useSegmentationMultiObsFeatureMatrixIndices(coordinationScopes: object, coordinationScopesBy: object, loaders: object, dataset: string): array;
28
+ /**
29
+ * Wrapper around useObsFeatureMatrixIndicesMultiLevel.
30
+ * @param {object} coordinationScopes
31
+ * @param {object} coordinationScopesBy
32
+ * @param {object} loaders
33
+ * @param {string} dataset
34
+ * @returns {array} [indicesData, status, errors]
35
+ */
36
+ export function useSpotMultiObsFeatureMatrixIndices(coordinationScopes: object, coordinationScopesBy: object, loaders: object, dataset: string): array;
37
+ /**
38
+ * Wrapper around useObsLabelsMultiLevel.
39
+ * @param {object} coordinationScopes
40
+ * @param {object} coordinationScopesBy
41
+ * @param {object} loaders
42
+ * @param {string} dataset
43
+ * @returns {array} [data, status, errors]
44
+ */
45
+ export function usePointMultiObsLabels(coordinationScopes: object, coordinationScopesBy: object, loaders: object, dataset: string): array;
46
+ /**
47
+ * Wrapper around useObsLocationsMultiLevel.
48
+ * @param {object} coordinationScopes
49
+ * @param {object} coordinationScopesBy
50
+ * @param {object} loaders
51
+ * @param {string} dataset
52
+ * @returns {array} [data, status, errors]
53
+ */
54
+ export function useSegmentationMultiObsLocations(coordinationScopes: object, coordinationScopesBy: object, loaders: object, dataset: string): array;
55
+ /**
56
+ * Wrapper around useObsSetsMultiLevel.
57
+ * @param {object} coordinationScopes
58
+ * @param {object} coordinationScopesBy
59
+ * @param {object} loaders
60
+ * @param {string} dataset
61
+ * @returns {array} [data, status, errors]
62
+ */
63
+ export function useSegmentationMultiObsSets(coordinationScopes: object, coordinationScopesBy: object, loaders: object, dataset: string): array;
8
64
  //# sourceMappingURL=data-hooks-multilevel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-hooks-multilevel.d.ts","sourceRoot":"","sources":["../src/data-hooks-multilevel.js"],"names":[],"mappings":"AAeA,4IAoDC;AAED,oIA4CC;AAED,mJAuBC;AAED,2IAsBC;AAED,8HAqBC;AAED,wIAqBC;AAED,mIAqBC"}
1
+ {"version":3,"file":"data-hooks-multilevel.d.ts","sourceRoot":"","sources":["../src/data-hooks-multilevel.js"],"names":[],"mappings":"AAeA;;;;;;;GAOG;AACH,yEANW,MAAM,wBACN,MAAM,WACN,MAAM,WACN,MAAM,GACJ,KAAK,CAsDjB;AAED;;;;;;;GAOG;AACH,iEANW,MAAM,wBACN,MAAM,WACN,MAAM,WACN,MAAM,GACJ,KAAK,CA8CjB;AAED;;;;;;;GAOG;AACH,gFANW,MAAM,wBACN,MAAM,WACN,MAAM,WACN,MAAM,GACJ,KAAK,CAyBjB;AAED;;;;;;;GAOG;AACH,wEANW,MAAM,wBACN,MAAM,WACN,MAAM,WACN,MAAM,GACJ,KAAK,CAwBjB;AAED;;;;;;;GAOG;AACH,2DANW,MAAM,wBACN,MAAM,WACN,MAAM,WACN,MAAM,GACJ,KAAK,CAuBjB;AAED;;;;;;;GAOG;AACH,qEANW,MAAM,wBACN,MAAM,WACN,MAAM,WACN,MAAM,GACJ,KAAK,CAuBjB;AAED;;;;;;;GAOG;AACH,gEANW,MAAM,wBACN,MAAM,WACN,MAAM,WACN,MAAM,GACJ,KAAK,CAuBjB"}