@jax-data-science/sci-image-visualizer 0.10.0 → 0.12.0
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.
- package/esm2022/index.mjs +7 -1
- package/esm2022/lib/contracts/image.contract.mjs +1 -1
- package/esm2022/lib/contracts/ports/region-io.port.mjs +1 -1
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +70 -2
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2 -2
- package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +11 -1
- package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +18 -2
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +9 -1
- package/esm2022/lib/implementations/osd/osd-tile-loading.mjs +71 -0
- package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +1 -1
- package/esm2022/lib/implementations/osd/slice-cache.mjs +35 -6
- package/esm2022/lib/region-editor/region-editor.component.mjs +152 -4
- package/esm2022/lib/region-editor/region-persistence.service.mjs +9 -1
- package/esm2022/lib/region-import/label-classes.mjs +149 -0
- package/esm2022/lib/region-import/label-volume.mjs +225 -0
- package/esm2022/lib/region-import/ome-zarr-labels.mjs +253 -0
- package/esm2022/lib/region-import/open-annotations.mjs +289 -0
- package/esm2022/lib/region-import/region-import.mjs +71 -0
- package/esm2022/lib/region-import/zarr-codecs.mjs +167 -0
- package/esm2022/lib/region-import/zip.mjs +157 -0
- package/esm2022/lib/routing-visualizer.service.mjs +112 -7
- package/esm2022/lib/store/region-source-scope.mjs +19 -4
- package/esm2022/lib/store/region-store.service.mjs +64 -14
- package/esm2022/lib/visualizer/region-load.mjs +16 -1
- package/esm2022/lib/visualizer.component.mjs +28 -2
- package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-a68Hw5rw.mjs} +2057 -196
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-a68Hw5rw.mjs.map +1 -0
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-CvadfzjS.mjs} +4 -2
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-CvadfzjS.mjs.map} +1 -1
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3 -1
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/index.d.ts +12 -0
- package/lib/contracts/image.contract.d.ts +7 -0
- package/lib/contracts/ports/region-io.port.d.ts +24 -0
- package/lib/contracts/region-editor-api.contract.d.ts +19 -1
- package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +40 -1
- package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +5 -0
- package/lib/implementations/osd/openseadragon-viewer-options.d.ts +2 -0
- package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +2 -0
- package/lib/implementations/osd/osd-tile-loading.d.ts +43 -0
- package/lib/implementations/osd/osd-viewer-like.d.ts +14 -0
- package/lib/implementations/osd/slice-cache.d.ts +13 -3
- package/lib/region-editor/region-editor.component.d.ts +27 -0
- package/lib/region-editor/region-persistence.service.d.ts +5 -1
- package/lib/region-import/label-classes.d.ts +39 -0
- package/lib/region-import/label-volume.d.ts +35 -0
- package/lib/region-import/ome-zarr-labels.d.ts +36 -0
- package/lib/region-import/open-annotations.d.ts +73 -0
- package/lib/region-import/region-import.d.ts +46 -0
- package/lib/region-import/zarr-codecs.d.ts +14 -0
- package/lib/region-import/zip.d.ts +31 -0
- package/lib/routing-visualizer.service.d.ts +39 -1
- package/lib/store/region-source-scope.d.ts +8 -2
- package/lib/store/region-store.service.d.ts +15 -5
- package/lib/visualizer.component.d.ts +9 -0
- package/package.json +2 -1
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs.map +0 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Annotations opened by themselves, with no image under them: a label volume (`.nii`, `.nii.gz`,
|
|
3
|
+
* `.nrrd`, with the ontology JSON chosen with it), an OME-Zarr store's label image, a folder of
|
|
4
|
+
* per-slice GeoJSON (with its `regionset.json`), one GeoJSON (z-indexed by `geometry.plane.z` or
|
|
5
|
+
* not), or a `.zip` of any of these.
|
|
6
|
+
*
|
|
7
|
+
* {@link openAnnotations} builds the image they are shown on, which every view takes as it takes
|
|
8
|
+
* any other (OpenSeadragon, napari, Plotly; a stack when there are several slices; the Volume and
|
|
9
|
+
* Isosurface views and their 3D region surfaces): a label volume's slices in gray levels, its
|
|
10
|
+
* regions filled over them in their classes' colours, else a blank stack the size of the regions.
|
|
11
|
+
* The image carries the annotations as its own region sources, one per slice
|
|
12
|
+
* ({@link IImageInfo.regionSlices}), traced or parsed the first time a slice is shown.
|
|
13
|
+
* The host publishes it as it publishes any image, and disposes it when another replaces it.
|
|
14
|
+
*
|
|
15
|
+
* {@link readAnnotationSlices} is the part the Region Editor's import shares: the sources, by slice.
|
|
16
|
+
*/
|
|
17
|
+
import { encode as encodePng } from 'fast-png';
|
|
18
|
+
import { openGeoJsonRegionSource } from '../region-source/worker-region-source';
|
|
19
|
+
import { ATLAS_STYLE, labelClasses, labelSliceGeoJson } from './label-classes';
|
|
20
|
+
import { readLabelVolume } from './label-volume';
|
|
21
|
+
import { hasZarrMetadata, readOmeZarrLabels } from './ome-zarr-labels';
|
|
22
|
+
import { folderSliceGeoJson, planRegionImport } from './region-import';
|
|
23
|
+
import { expandZips } from './zip';
|
|
24
|
+
/** The longest side an image built for annotations may have: OpenSeadragon's non-tiled limit. */
|
|
25
|
+
export const ANNOTATION_IMAGE_MAX_DIM = 8192;
|
|
26
|
+
/**
|
|
27
|
+
* The annotations among `files` (zips expanded), as one region source per slice; null when there
|
|
28
|
+
* are none to read. A label image's slices are traced, and a GeoJSON parsed, when the slice is
|
|
29
|
+
* first shown.
|
|
30
|
+
*/
|
|
31
|
+
export async function readAnnotationSlices(chosen, decoders = {}) {
|
|
32
|
+
const files = await expandZips(chosen, decoders.inflateRaw);
|
|
33
|
+
const openGeoJson = decoders.openGeoJson ?? ((text) => openGeoJsonRegionSource(text));
|
|
34
|
+
if (hasZarrMetadata(files)) {
|
|
35
|
+
const zarr = await readOmeZarrLabels(files, decoders.inflate);
|
|
36
|
+
if (!zarr)
|
|
37
|
+
throw new Error('The zarr store has no label image (an OME-Zarr labels/ group).');
|
|
38
|
+
return labelSlices('labels', zarr.name, zarr.stack, styled(zarr.classes, decoders), openGeoJson);
|
|
39
|
+
}
|
|
40
|
+
const plan = planRegionImport(files);
|
|
41
|
+
if (!plan)
|
|
42
|
+
return null;
|
|
43
|
+
if (plan.kind === 'volume') {
|
|
44
|
+
const volume = await readLabelVolume(plan.volume.name, await plan.volume.bytes(), decoders.gunzip);
|
|
45
|
+
const classes = labelClasses(plan.ontology ? JSON.parse(await plan.ontology.text()) : undefined);
|
|
46
|
+
return labelSlices('labels', stem(plan.volume.name), stackOf(volume), styled(classes, decoders), openGeoJson);
|
|
47
|
+
}
|
|
48
|
+
if (plan.kind === 'folder') {
|
|
49
|
+
const regionSet = plan.regionSet ? JSON.parse(await plan.regionSet.text()) : null;
|
|
50
|
+
const openers = new Map();
|
|
51
|
+
plan.slices.forEach((file, z) => openers.set(z, async () => openGeoJson(await folderSliceGeoJson(file, regionSet))));
|
|
52
|
+
const folder = plan.slices[0].name.split('/').slice(-2, -1)[0] || 'regions';
|
|
53
|
+
return {
|
|
54
|
+
kind: 'folder',
|
|
55
|
+
name: folder,
|
|
56
|
+
slices: plan.slices.length,
|
|
57
|
+
openers,
|
|
58
|
+
summary: `${plan.slices.length} slice files`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const slices = splitByPlane(await plan.file.text());
|
|
62
|
+
const openers = new Map();
|
|
63
|
+
slices.forEach((text, z) => openers.set(z, () => openGeoJson(text)));
|
|
64
|
+
return {
|
|
65
|
+
kind: 'single',
|
|
66
|
+
name: stem(plan.file.name),
|
|
67
|
+
slices: slices.length,
|
|
68
|
+
openers,
|
|
69
|
+
summary: slices.length > 1 ? `${slices.length} slices` : 'one plane',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
let opened = 0;
|
|
73
|
+
/**
|
|
74
|
+
* The image `files`' annotations are shown on by themselves (see the module comment). Throws when
|
|
75
|
+
* there are none, or when their regions span more than {@link ANNOTATION_IMAGE_MAX_DIM} pixels
|
|
76
|
+
* (they are then imported onto the image they were drawn on).
|
|
77
|
+
*/
|
|
78
|
+
export async function openAnnotations(files, decoders = {}) {
|
|
79
|
+
const set = await readAnnotationSlices(files, { outlineLabels: true, ...decoders });
|
|
80
|
+
if (!set) {
|
|
81
|
+
throw new Error('Choose a label volume (.nii, .nii.gz, .nrrd, with its ontology JSON), an OME-Zarr store, ' +
|
|
82
|
+
'GeoJSON files or a folder of them, or a .zip of any of these.');
|
|
83
|
+
}
|
|
84
|
+
let urls = [];
|
|
85
|
+
let width;
|
|
86
|
+
let height;
|
|
87
|
+
let openers = set.openers;
|
|
88
|
+
// Releases the sources measuring opened that the store has not taken (none for a label image).
|
|
89
|
+
let release = () => undefined;
|
|
90
|
+
try {
|
|
91
|
+
if (set.labels && set.size) {
|
|
92
|
+
[width, height] = set.size;
|
|
93
|
+
checkSize(width, height);
|
|
94
|
+
urls = await labelSliceUrls(set.labels.stack, set.labels.classes);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Regions alone: a blank stack as large as they reach, measured on the sources (kept open
|
|
98
|
+
// for their slices, so each is parsed once).
|
|
99
|
+
const measured = await measure(set.openers);
|
|
100
|
+
openers = measured.openers;
|
|
101
|
+
release = measured.release;
|
|
102
|
+
[width, height] = measured.size;
|
|
103
|
+
checkSize(width, height);
|
|
104
|
+
const png = encodePng({ width, height, data: new Uint8Array(width * height), channels: 1, depth: 8 });
|
|
105
|
+
const blank = new Blob([png], { type: 'image/png' });
|
|
106
|
+
urls = Array.from({ length: set.slices }, () => URL.createObjectURL(blank));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
urls.forEach((u) => URL.revokeObjectURL(u));
|
|
111
|
+
release();
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
114
|
+
const [mx, my, mz] = set.spacing ?? [];
|
|
115
|
+
const isStack = set.slices > 1;
|
|
116
|
+
const info = {
|
|
117
|
+
isGrayscale: true,
|
|
118
|
+
trueImageSize: [width, height],
|
|
119
|
+
urls,
|
|
120
|
+
isStack,
|
|
121
|
+
showStack: false,
|
|
122
|
+
scaleRatio: true,
|
|
123
|
+
// Unique: the slice cache keys on the name, and two opened sets must not share slices.
|
|
124
|
+
fileName: `${set.name} · annotations [${++opened}]`,
|
|
125
|
+
imageMeta: [
|
|
126
|
+
{
|
|
127
|
+
channelCount: 1,
|
|
128
|
+
rgbChannels: 1,
|
|
129
|
+
x: width,
|
|
130
|
+
y: height,
|
|
131
|
+
z: set.slices,
|
|
132
|
+
mppX: mx ?? null,
|
|
133
|
+
mppY: my ?? null,
|
|
134
|
+
...(mz != null ? { mppZ: mz } : {}),
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
tiled: false,
|
|
138
|
+
// Open mid-stack: an atlas's first and last sections are mostly empty.
|
|
139
|
+
initialZIndex: isStack ? set.slices >> 1 : undefined,
|
|
140
|
+
regionSlices: openers,
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
info,
|
|
144
|
+
summary: `${set.summary}, ${width} × ${height}`,
|
|
145
|
+
dispose: () => {
|
|
146
|
+
urls.forEach((u) => URL.revokeObjectURL(u));
|
|
147
|
+
release();
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function labelSlices(kind, name, stack, classes, openGeoJson) {
|
|
152
|
+
const openers = new Map();
|
|
153
|
+
for (let z = 0; z < stack.slices; z++) {
|
|
154
|
+
openers.set(z, async () => openGeoJson(labelSliceGeoJson(oneSlice(stack, await stack.labels(z)), 0, classes)));
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
kind,
|
|
158
|
+
name,
|
|
159
|
+
slices: stack.slices,
|
|
160
|
+
openers,
|
|
161
|
+
labels: { stack, classes },
|
|
162
|
+
size: [stack.width, stack.height],
|
|
163
|
+
...(stack.spacing ? { spacing: stack.spacing } : {}),
|
|
164
|
+
summary: `${stack.slices} slice${stack.slices === 1 ? '' : 's'} of ${stack.width} × ${stack.height}`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/** `classes`, with the atlas look when asked for and they name no style of their own. */
|
|
168
|
+
function styled(classes, decoders) {
|
|
169
|
+
return decoders.outlineLabels && !classes.style ? { ...classes, style: ATLAS_STYLE } : classes;
|
|
170
|
+
}
|
|
171
|
+
/** A label volume as a stack read on demand. */
|
|
172
|
+
function stackOf(volume) {
|
|
173
|
+
return {
|
|
174
|
+
width: volume.width,
|
|
175
|
+
height: volume.height,
|
|
176
|
+
slices: volume.slices,
|
|
177
|
+
...(volume.spacing ? { spacing: volume.spacing } : {}),
|
|
178
|
+
labels: async (z) => volume.sliceLabels(z),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/** One slice's labels as the one-slice volume the tracer reads. */
|
|
182
|
+
function oneSlice(stack, labels) {
|
|
183
|
+
return { format: 'nrrd', width: stack.width, height: stack.height, slices: 1, sliceLabels: () => labels };
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Every slice as a grayscale PNG blob URL, each label at its class colour's luminance (never 0),
|
|
187
|
+
* background black. Grayscale, not colour: the Volume and Isosurface views take a grayscale stack,
|
|
188
|
+
* and the colour is the regions' own, filled over it in their classes' colours (the atlas look).
|
|
189
|
+
*/
|
|
190
|
+
async function labelSliceUrls(stack, classes) {
|
|
191
|
+
const levels = new Map();
|
|
192
|
+
const levelOf = (v) => {
|
|
193
|
+
let l = levels.get(v);
|
|
194
|
+
if (l === undefined) {
|
|
195
|
+
const hex = classes.classOf(v).color;
|
|
196
|
+
const [r, g, b] = [1, 3, 5].map((o) => parseInt(hex.slice(o, o + 2), 16));
|
|
197
|
+
l = Math.max(1, Math.round(0.299 * r + 0.587 * g + 0.114 * b));
|
|
198
|
+
levels.set(v, l);
|
|
199
|
+
}
|
|
200
|
+
return l;
|
|
201
|
+
};
|
|
202
|
+
const urls = [];
|
|
203
|
+
const gray = new Uint8Array(stack.width * stack.height);
|
|
204
|
+
for (let z = 0; z < stack.slices; z++) {
|
|
205
|
+
const labels = await stack.labels(z);
|
|
206
|
+
for (let i = 0; i < labels.length; i++)
|
|
207
|
+
gray[i] = labels[i] ? levelOf(labels[i]) : 0;
|
|
208
|
+
const png = encodePng({ width: stack.width, height: stack.height, data: gray, channels: 1, depth: 8 });
|
|
209
|
+
urls.push(URL.createObjectURL(new Blob([png], { type: 'image/png' })));
|
|
210
|
+
}
|
|
211
|
+
return urls;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Open every slice's source to learn how far the regions reach (the image is as large, from the
|
|
215
|
+
* origin, as region coordinates are image pixels). Each opener then hands its already-open source
|
|
216
|
+
* over the first time (the region store owns it from then on) and opens anew after. `release`
|
|
217
|
+
* disposes the sources not handed over yet; they are released here when measuring fails.
|
|
218
|
+
*/
|
|
219
|
+
async function measure(openers) {
|
|
220
|
+
// Sources opened here and not yet handed to the store: theirs to release until then.
|
|
221
|
+
const held = new Map();
|
|
222
|
+
const release = () => {
|
|
223
|
+
for (const source of held.values())
|
|
224
|
+
source.dispose();
|
|
225
|
+
held.clear();
|
|
226
|
+
};
|
|
227
|
+
let x1 = 0;
|
|
228
|
+
let y1 = 0;
|
|
229
|
+
try {
|
|
230
|
+
for (const [z, open] of openers) {
|
|
231
|
+
const source = await open();
|
|
232
|
+
held.set(z, source);
|
|
233
|
+
const bounds = source.info.bounds;
|
|
234
|
+
if (bounds) {
|
|
235
|
+
x1 = Math.max(x1, bounds[2]);
|
|
236
|
+
y1 = Math.max(y1, bounds[3]);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (!(x1 > 0 && y1 > 0))
|
|
240
|
+
throw new Error('The regions have no extent to show.');
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
release();
|
|
244
|
+
throw err;
|
|
245
|
+
}
|
|
246
|
+
const reused = new Map();
|
|
247
|
+
for (const [z, open] of openers) {
|
|
248
|
+
reused.set(z, () => {
|
|
249
|
+
const first = held.get(z);
|
|
250
|
+
if (!first)
|
|
251
|
+
return open();
|
|
252
|
+
held.delete(z);
|
|
253
|
+
return Promise.resolve(first);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return { openers: reused, size: [Math.ceil(x1), Math.ceil(y1)], release };
|
|
257
|
+
}
|
|
258
|
+
function checkSize(width, height) {
|
|
259
|
+
if (Math.max(width, height) > ANNOTATION_IMAGE_MAX_DIM) {
|
|
260
|
+
throw new Error(`The annotations span ${width} × ${height} pixels, more than ${ANNOTATION_IMAGE_MAX_DIM} on a side: ` +
|
|
261
|
+
'open the image they were drawn on, and import them onto it from the Region Editor.');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* One GeoJSON's slices: a collection whose features name planes (`geometry.plane.z`) split into
|
|
266
|
+
* one collection per plane, each keeping the set's class tree and style, its features moved to
|
|
267
|
+
* plane 0 (a slice's source shows plane 0); any other GeoJSON is one slice as it is.
|
|
268
|
+
*/
|
|
269
|
+
export function splitByPlane(text) {
|
|
270
|
+
const doc = JSON.parse(text);
|
|
271
|
+
const features = doc.type === 'FeatureCollection' ? (doc.features ?? []) : [];
|
|
272
|
+
const zOf = (f) => Math.max(0, Math.floor(f.geometry?.plane?.z ?? 0));
|
|
273
|
+
const last = features.reduce((m, f) => Math.max(m, zOf(f)), 0);
|
|
274
|
+
if (last === 0)
|
|
275
|
+
return [text];
|
|
276
|
+
const slices = Array.from({ length: last + 1 }, () => []);
|
|
277
|
+
for (const f of features) {
|
|
278
|
+
const z = zOf(f);
|
|
279
|
+
const geometry = f.geometry ? { ...f.geometry } : f.geometry;
|
|
280
|
+
if (geometry)
|
|
281
|
+
delete geometry.plane;
|
|
282
|
+
slices[z].push({ ...f, geometry });
|
|
283
|
+
}
|
|
284
|
+
return slices.map((list) => JSON.stringify({ ...doc, features: list }));
|
|
285
|
+
}
|
|
286
|
+
function stem(name) {
|
|
287
|
+
return (name.split('/').pop() ?? name).replace(/\.(nii\.gz|nii|nrrd|geojson|json|zip)$/i, '');
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3Blbi1hbm5vdGF0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWltcG9ydC9vcGVuLWFubm90YXRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE9BQU8sRUFBRSxNQUFNLElBQUksU0FBUyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBSS9DLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFnQixpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzdGLE9BQU8sRUFBdUIsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEUsT0FBTyxFQUFFLGVBQWUsRUFBYyxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ25GLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxnQkFBZ0IsRUFBb0IsTUFBTSxpQkFBaUIsQ0FBQztBQUV6RixPQUFPLEVBQUUsVUFBVSxFQUFjLE1BQU0sT0FBTyxDQUFDO0FBRS9DLGlHQUFpRztBQUNqRyxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxJQUFJLENBQUM7QUFzQzdDOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxNQUFtQyxFQUNuQyxXQUErQixFQUFFO0lBRWpDLE1BQU0sS0FBSyxHQUFHLE1BQU0sVUFBVSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDNUQsTUFBTSxXQUFXLEdBQUcsUUFBUSxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUMsSUFBWSxFQUFFLEVBQUUsQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzlGLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDM0IsTUFBTSxJQUFJLEdBQUcs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QUFFLENBQUMsQ0FBQztBQUNoRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBbm5vdGF0aW9ucyBvcGVuZWQgYnkgdGhlbXNlbHZlcywgd2l0aCBubyBpbWFnZSB1bmRlciB0aGVtOiBhIGxhYmVsIHZvbHVtZSAoYC5uaWlgLCBgLm5paS5nemAsXG4gKiBgLm5ycmRgLCB3aXRoIHRoZSBvbnRvbG9neSBKU09OIGNob3NlbiB3aXRoIGl0KSwgYW4gT01FLVphcnIgc3RvcmUncyBsYWJlbCBpbWFnZSwgYSBmb2xkZXIgb2ZcbiAqIHBlci1zbGljZSBHZW9KU09OICh3aXRoIGl0cyBgcmVnaW9uc2V0Lmpzb25gKSwgb25lIEdlb0pTT04gKHotaW5kZXhlZCBieSBgZ2VvbWV0cnkucGxhbmUuemAgb3JcbiAqIG5vdCksIG9yIGEgYC56aXBgIG9mIGFueSBvZiB0aGVzZS5cbiAqXG4gKiB7QGxpbmsgb3BlbkFubm90YXRpb25zfSBidWlsZHMgdGhlIGltYWdlIHRoZXkgYXJlIHNob3duIG9uLCB3aGljaCBldmVyeSB2aWV3IHRha2VzIGFzIGl0IHRha2VzXG4gKiBhbnkgb3RoZXIgKE9wZW5TZWFkcmFnb24sIG5hcGFyaSwgUGxvdGx5OyBhIHN0YWNrIHdoZW4gdGhlcmUgYXJlIHNldmVyYWwgc2xpY2VzOyB0aGUgVm9sdW1lIGFuZFxuICogSXNvc3VyZmFjZSB2aWV3cyBhbmQgdGhlaXIgM0QgcmVnaW9uIHN1cmZhY2VzKTogYSBsYWJlbCB2b2x1bWUncyBzbGljZXMgaW4gZ3JheSBsZXZlbHMsIGl0c1xuICogcmVnaW9ucyBmaWxsZWQgb3ZlciB0aGVtIGluIHRoZWlyIGNsYXNzZXMnIGNvbG91cnMsIGVsc2UgYSBibGFuayBzdGFjayB0aGUgc2l6ZSBvZiB0aGUgcmVnaW9ucy5cbiAqIFRoZSBpbWFnZSBjYXJyaWVzIHRoZSBhbm5vdGF0aW9ucyBhcyBpdHMgb3duIHJlZ2lvbiBzb3VyY2VzLCBvbmUgcGVyIHNsaWNlXG4gKiAoe0BsaW5rIElJbWFnZUluZm8ucmVnaW9uU2xpY2VzfSksIHRyYWNlZCBvciBwYXJzZWQgdGhlIGZpcnN0IHRpbWUgYSBzbGljZSBpcyBzaG93bi5cbiAqIFRoZSBob3N0IHB1Ymxpc2hlcyBpdCBhcyBpdCBwdWJsaXNoZXMgYW55IGltYWdlLCBhbmQgZGlzcG9zZXMgaXQgd2hlbiBhbm90aGVyIHJlcGxhY2VzIGl0LlxuICpcbiAqIHtAbGluayByZWFkQW5ub3RhdGlvblNsaWNlc30gaXMgdGhlIHBhcnQgdGhlIFJlZ2lvbiBFZGl0b3IncyBpbXBvcnQgc2hhcmVzOiB0aGUgc291cmNlcywgYnkgc2xpY2UuXG4gKi9cbmltcG9ydCB7IGVuY29kZSBhcyBlbmNvZGVQbmcgfSBmcm9tICdmYXN0LXBuZyc7XG5cbmltcG9ydCB0eXBlIHsgSUltYWdlSW5mbyB9IGZyb20gJy4uL2NvbnRyYWN0cy9pbWFnZS5jb250cmFjdCc7XG5pbXBvcnQgdHlwZSB7IFJlZ2lvblNvdXJjZSB9IGZyb20gJy4uL3JlZ2lvbi1zb3VyY2UvcmVnaW9uLXNvdXJjZSc7XG5pbXBvcnQgeyBvcGVuR2VvSnNvblJlZ2lvblNvdXJjZSB9IGZyb20gJy4uL3JlZ2lvbi1zb3VyY2Uvd29ya2VyLXJlZ2lvbi1zb3VyY2UnO1xuaW1wb3J0IHsgQVRMQVNfU1RZTEUsIGxhYmVsQ2xhc3NlcywgTGFiZWxDbGFzc2VzLCBsYWJlbFNsaWNlR2VvSnNvbiB9IGZyb20gJy4vbGFiZWwtY2xhc3Nlcyc7XG5pbXBvcnQgeyBHdW56aXAsIExhYmVsVm9sdW1lLCByZWFkTGFiZWxWb2x1bWUgfSBmcm9tICcuL2xhYmVsLXZvbHVtZSc7XG5pbXBvcnQgeyBoYXNaYXJyTWV0YWRhdGEsIExhYmVsU3RhY2ssIHJlYWRPbWVaYXJyTGFiZWxzIH0gZnJvbSAnLi9vbWUtemFyci1sYWJlbHMnO1xuaW1wb3J0IHsgZm9sZGVyU2xpY2VHZW9Kc29uLCBwbGFuUmVnaW9uSW1wb3J0LCBSZWdpb25JbXBvcnRGaWxlIH0gZnJvbSAnLi9yZWdpb24taW1wb3J0JztcbmltcG9ydCB7IEluZmxhdGUgfSBmcm9tICcuL3phcnItY29kZWNzJztcbmltcG9ydCB7IGV4cGFuZFppcHMsIEluZmxhdGVSYXcgfSBmcm9tICcuL3ppcCc7XG5cbi8qKiBUaGUgbG9uZ2VzdCBzaWRlIGFuIGltYWdlIGJ1aWx0IGZvciBhbm5vdGF0aW9ucyBtYXkgaGF2ZTogT3BlblNlYWRyYWdvbidzIG5vbi10aWxlZCBsaW1pdC4gKi9cbmV4cG9ydCBjb25zdCBBTk5PVEFUSU9OX0lNQUdFX01BWF9ESU0gPSA4MTkyO1xuXG4vKiogT3BlbnMgYSBzbGljZSdzIHJlZ2lvbiBzb3VyY2UgKGFnYWluLCBhZnRlciB0aGUgc3RvcmUgY2xvc2VkIGl0KS4gKi9cbnR5cGUgT3BlbmVyID0gKCkgPT4gUHJvbWlzZTxSZWdpb25Tb3VyY2U+O1xuXG4vKiogRGVjb2RlcnMsIGluamVjdGFibGUgZm9yIHRlc3RzIGFuZCB3b3JrZXJzIChkZWZhdWx0czogdGhlIHBsYXRmb3JtJ3Mgc3RyZWFtcykuICovXG5leHBvcnQgaW50ZXJmYWNlIEFubm90YXRpb25EZWNvZGVycyB7XG4gIGluZmxhdGVSYXc/OiBJbmZsYXRlUmF3O1xuICBpbmZsYXRlPzogSW5mbGF0ZTtcbiAgZ3VuemlwPzogR3VuemlwO1xuICAvKiogT3BlbiBhIEdlb0pTT04gdGV4dCBhcyBhIHJlZ2lvbiBzb3VyY2UgKGRlZmF1bHQ6IGluIHRoZSBzaGFyZWQgcmVnaW9uIHdvcmtlcikuICovXG4gIG9wZW5HZW9Kc29uPzogKHRleHQ6IHN0cmluZykgPT4gUHJvbWlzZTxSZWdpb25Tb3VyY2U+O1xuICAvKipcbiAgICogR2l2ZSBhIGxhYmVsIGltYWdlJ3MgcmVnaW9ucyB0aGUgYXRsYXMgbG9vayAoZGFyayBvdXRsaW5lcywgbGFiZWxzKSB3aGVuIGl0cyBvbnRvbG9neSBuYW1lc1xuICAgKiBubyBzdHlsZTogZHJhd24gb3ZlciB0aGUgbGFiZWwgaW1hZ2UgaXRzZWxmLCBvdXRsaW5lcyBpbiB0aGVpciBjbGFzc2VzJyBvd24gY29sb3VycyB3b3VsZCBub3RcbiAgICogc2hvdy4gKEltcG9ydGVkIG92ZXIgYSByZWFsIGltYWdlLCB0aGUgZGVmYXVsdCBsb29rIHJlYWRzLilcbiAgICovXG4gIG91dGxpbmVMYWJlbHM/OiBib29sZWFuO1xufVxuXG4vKiogVGhlIGFubm90YXRpb25zIGFtb25nIHNvbWUgZmlsZXMsIGFzIG9uZSByZWdpb24gc291cmNlIHBlciBzbGljZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQW5ub3RhdGlvblNsaWNlcyB7XG4gIGtpbmQ6ICdsYWJlbHMnIHwgJ2ZvbGRlcicgfCAnc2luZ2xlJztcbiAgLyoqIEEgbmFtZSBmb3Igd2hhdCB3YXMgb3BlbmVkICh0aGUgbGFiZWwgaW1hZ2UncywgdGhlIGZvbGRlcidzLCB0aGUgZmlsZSdzKS4gKi9cbiAgbmFtZTogc3RyaW5nO1xuICBzbGljZXM6IG51bWJlcjtcbiAgLyoqIE9uZSBvcGVuZXIgcGVyIHNsaWNlIGluZGV4LiAqL1xuICBvcGVuZXJzOiBNYXA8bnVtYmVyLCBPcGVuZXI+O1xuICAvKiogQSBsYWJlbCBpbWFnZSdzIHNsaWNlcyBhbmQgY2xhc3NlcyAodG8gZHJhdyB0aGVtLCBzZWUgb3BlbkFubm90YXRpb25zKS4gKi9cbiAgbGFiZWxzPzogeyBzdGFjazogTGFiZWxTdGFjazsgY2xhc3NlczogTGFiZWxDbGFzc2VzIH07XG4gIC8qKiBTbGljZSB3aWR0aCBhbmQgaGVpZ2h0LCB3aGVuIGtub3duIHdpdGhvdXQgb3BlbmluZyB0aGUgc291cmNlcyAoYSBsYWJlbCBpbWFnZSdzKS4gKi9cbiAgc2l6ZT86IFtudW1iZXIsIG51bWJlcl07XG4gIC8qKiBWb3hlbCBzaXplIHgsIHksIHogaW4gbWljcm9tZXRyZXMsIHdoZW4gdGhlIHNvdXJjZSBzYXlzLiAqL1xuICBzcGFjaW5nPzogW251bWJlciwgbnVtYmVyLCBudW1iZXJdO1xuICAvKiogV2hhdCB3YXMgcmVhZCwgZm9yIGEgbWVzc2FnZSAoXCIxMiBzbGljZXMgb2YgNDU2IMOXIDMyMFwiKS4gKi9cbiAgc3VtbWFyeTogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBhbm5vdGF0aW9ucyBhbW9uZyBgZmlsZXNgICh6aXBzIGV4cGFuZGVkKSwgYXMgb25lIHJlZ2lvbiBzb3VyY2UgcGVyIHNsaWNlOyBudWxsIHdoZW4gdGhlcmVcbiAqIGFyZSBub25lIHRvIHJlYWQuIEEgbGFiZWwgaW1hZ2UncyBzbGljZXMgYXJlIHRyYWNlZCwgYW5kIGEgR2VvSlNPTiBwYXJzZWQsIHdoZW4gdGhlIHNsaWNlIGlzXG4gKiBmaXJzdCBzaG93bi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRBbm5vdGF0aW9uU2xpY2VzKFxuICBjaG9zZW46IHJlYWRvbmx5IFJlZ2lvbkltcG9ydEZpbGVbXSxcbiAgZGVjb2RlcnM6IEFubm90YXRpb25EZWNvZGVycyA9IHt9LFxuKTogUHJvbWlzZTxBbm5vdGF0aW9uU2xpY2VzIHwgbnVsbD4ge1xuICBjb25zdCBmaWxlcyA9IGF3YWl0IGV4cGFuZFppcHMoY2hvc2VuLCBkZWNvZGVycy5pbmZsYXRlUmF3KTtcbiAgY29uc3Qgb3Blbkdlb0pzb24gPSBkZWNvZGVycy5vcGVuR2VvSnNvbiA/PyAoKHRleHQ6IHN0cmluZykgPT4gb3Blbkdlb0pzb25SZWdpb25Tb3VyY2UodGV4dCkpO1xuICBpZiAoaGFzWmFyck1ldGFkYXRhKGZpbGVzKSkge1xuICAgIGNvbnN0IHphcnIgPSBhd2FpdCByZWFkT21lWmFyckxhYmVscyhmaWxlcywgZGVjb2RlcnMuaW5mbGF0ZSk7XG4gICAgaWYgKCF6YXJyKSB0aHJvdyBuZXcgRXJyb3IoJ1RoZSB6YXJyIHN0b3JlIGhhcyBubyBsYWJlbCBpbWFnZSAoYW4gT01FLVphcnIgbGFiZWxzLyBncm91cCkuJyk7XG4gICAgcmV0dXJuIGxhYmVsU2xpY2VzKCdsYWJlbHMnLCB6YXJyLm5hbWUsIHphcnIuc3RhY2ssIHN0eWxlZCh6YXJyLmNsYXNzZXMsIGRlY29kZXJzKSwgb3Blbkdlb0pzb24pO1xuICB9XG4gIGNvbnN0IHBsYW4gPSBwbGFuUmVnaW9uSW1wb3J0KGZpbGVzKTtcbiAgaWYgKCFwbGFuKSByZXR1cm4gbnVsbDtcbiAgaWYgKHBsYW4ua2luZCA9PT0gJ3ZvbHVtZScpIHtcbiAgICBjb25zdCB2b2x1bWUgPSBhd2FpdCByZWFkTGFiZWxWb2x1bWUocGxhbi52b2x1bWUubmFtZSwgYXdhaXQgcGxhbi52b2x1bWUuYnl0ZXMoKSwgZGVjb2RlcnMuZ3VuemlwKTtcbiAgICBjb25zdCBjbGFzc2VzID0gbGFiZWxDbGFzc2VzKHBsYW4ub250b2xvZ3kgPyBKU09OLnBhcnNlKGF3YWl0IHBsYW4ub250b2xvZ3kudGV4dCgpKSA6IHVuZGVmaW5lZCk7XG4gICAgcmV0dXJuIGxhYmVsU2xpY2VzKCdsYWJlbHMnLCBzdGVtKHBsYW4udm9sdW1lLm5hbWUpLCBzdGFja09mKHZvbHVtZSksIHN0eWxlZChjbGFzc2VzLCBkZWNvZGVycyksIG9wZW5HZW9Kc29uKTtcbiAgfVxuICBpZiAocGxhbi5raW5kID09PSAnZm9sZGVyJykge1xuICAgIGNvbnN0IHJlZ2lvblNldCA9IHBsYW4ucmVnaW9uU2V0ID8gSlNPTi5wYXJzZShhd2FpdCBwbGFuLnJlZ2lvblNldC50ZXh0KCkpIDogbnVsbDtcbiAgICBjb25zdCBvcGVuZXJzID0gbmV3IE1hcDxudW1iZXIsIE9wZW5lcj4oKTtcbiAgICBwbGFuLnNsaWNlcy5mb3JFYWNoKChmaWxlLCB6KSA9PlxuICAgICAgb3BlbmVycy5zZXQoeiwgYXN5bmMgKCkgPT4gb3Blbkdlb0pzb24oYXdhaXQgZm9sZGVyU2xpY2VHZW9Kc29uKGZpbGUsIHJlZ2lvblNldCkpKSxcbiAgICApO1xuICAgIGNvbnN0IGZvbGRlciA9IHBsYW4uc2xpY2VzWzBdLm5hbWUuc3BsaXQoJy8nKS5zbGljZSgtMiwgLTEpWzBdIHx8ICdyZWdpb25zJztcbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2ZvbGRlcicsXG4gICAgICBuYW1lOiBmb2xkZXIsXG4gICAgICBzbGljZXM6IHBsYW4uc2xpY2VzLmxlbmd0aCxcbiAgICAgIG9wZW5lcnMsXG4gICAgICBzdW1tYXJ5OiBgJHtwbGFuLnNsaWNlcy5sZW5ndGh9IHNsaWNlIGZpbGVzYCxcbiAgICB9O1xuICB9XG4gIGNvbnN0IHNsaWNlcyA9IHNwbGl0QnlQbGFuZShhd2FpdCBwbGFuLmZpbGUudGV4dCgpKTtcbiAgY29uc3Qgb3BlbmVycyA9IG5ldyBNYXA8bnVtYmVyLCBPcGVuZXI+KCk7XG4gIHNsaWNlcy5mb3JFYWNoKCh0ZXh0LCB6KSA9PiBvcGVuZXJzLnNldCh6LCAoKSA9PiBvcGVuR2VvSnNvbih0ZXh0KSkpO1xuICByZXR1cm4ge1xuICAgIGtpbmQ6ICdzaW5nbGUnLFxuICAgIG5hbWU6IHN0ZW0ocGxhbi5maWxlLm5hbWUpLFxuICAgIHNsaWNlczogc2xpY2VzLmxlbmd0aCxcbiAgICBvcGVuZXJzLFxuICAgIHN1bW1hcnk6IHNsaWNlcy5sZW5ndGggPiAxID8gYCR7c2xpY2VzLmxlbmd0aH0gc2xpY2VzYCA6ICdvbmUgcGxhbmUnLFxuICB9O1xufVxuXG4vKiogV2hhdCB7QGxpbmsgb3BlbkFubm90YXRpb25zfSBidWlsdDogdGhlIGltYWdlIHRvIHB1Ymxpc2gsIGFuZCBob3cgdG8gcmVsZWFzZSBpdC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbmVkQW5ub3RhdGlvbnMge1xuICBpbmZvOiBJSW1hZ2VJbmZvO1xuICBzdW1tYXJ5OiBzdHJpbmc7XG4gIC8qKiBSZXZva2UgdGhlIGltYWdlJ3MgYmxvYiBVUkxzLCBhbmQgcmVsZWFzZSB0aGUgc2xpY2VzJyBzb3VyY2VzIHRoZSByZWdpb24gc3RvcmUgbmV2ZXIgdG9va1xuICAgKiAgKG9uY2UgYW5vdGhlciBpbWFnZSByZXBsYWNlZCBpdCkuICovXG4gIGRpc3Bvc2UoKTogdm9pZDtcbn1cblxubGV0IG9wZW5lZCA9IDA7XG5cbi8qKlxuICogVGhlIGltYWdlIGBmaWxlc2AnIGFubm90YXRpb25zIGFyZSBzaG93biBvbiBieSB0aGVtc2VsdmVzIChzZWUgdGhlIG1vZHVsZSBjb21tZW50KS4gVGhyb3dzIHdoZW5cbiAqIHRoZXJlIGFyZSBub25lLCBvciB3aGVuIHRoZWlyIHJlZ2lvbnMgc3BhbiBtb3JlIHRoYW4ge0BsaW5rIEFOTk9UQVRJT05fSU1BR0VfTUFYX0RJTX0gcGl4ZWxzXG4gKiAodGhleSBhcmUgdGhlbiBpbXBvcnRlZCBvbnRvIHRoZSBpbWFnZSB0aGV5IHdlcmUgZHJhd24gb24pLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gb3BlbkFubm90YXRpb25zKFxuICBmaWxlczogcmVhZG9ubHkgUmVnaW9uSW1wb3J0RmlsZVtdLFxuICBkZWNvZGVyczogQW5ub3RhdGlvbkRlY29kZXJzID0ge30sXG4pOiBQcm9taXNlPE9wZW5lZEFubm90YXRpb25zPiB7XG4gIGNvbnN0IHNldCA9IGF3YWl0IHJlYWRBbm5vdGF0aW9uU2xpY2VzKGZpbGVzLCB7IG91dGxpbmVMYWJlbHM6IHRydWUsIC4uLmRlY29kZXJzIH0pO1xuICBpZiAoIXNldCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICdDaG9vc2UgYSBsYWJlbCB2b2x1bWUgKC5uaWksIC5uaWkuZ3osIC5ucnJkLCB3aXRoIGl0cyBvbnRvbG9neSBKU09OKSwgYW4gT01FLVphcnIgc3RvcmUsICcgK1xuICAgICAgICAnR2VvSlNPTiBmaWxlcyBvciBhIGZvbGRlciBvZiB0aGVtLCBvciBhIC56aXAgb2YgYW55IG9mIHRoZXNlLicsXG4gICAgKTtcbiAgfVxuICBsZXQgdXJsczogc3RyaW5nW10gPSBbXTtcbiAgbGV0IHdpZHRoOiBudW1iZXI7XG4gIGxldCBoZWlnaHQ6IG51bWJlcjtcbiAgbGV0IG9wZW5lcnMgPSBzZXQub3BlbmVycztcbiAgLy8gUmVsZWFzZXMgdGhlIHNvdXJjZXMgbWVhc3VyaW5nIG9wZW5lZCB0aGF0IHRoZSBzdG9yZSBoYXMgbm90IHRha2VuIChub25lIGZvciBhIGxhYmVsIGltYWdlKS5cbiAgbGV0IHJlbGVhc2UgPSAoKSA9PiB1bmRlZmluZWQgYXMgdm9pZDtcbiAgdHJ5IHtcbiAgICBpZiAoc2V0LmxhYmVscyAmJiBzZXQuc2l6ZSkge1xuICAgICAgW3dpZHRoLCBoZWlnaHRdID0gc2V0LnNpemU7XG4gICAgICBjaGVja1NpemUod2lkdGgsIGhlaWdodCk7XG4gICAgICB1cmxzID0gYXdhaXQgbGFiZWxTbGljZVVybHMoc2V0LmxhYmVscy5zdGFjaywgc2V0LmxhYmVscy5jbGFzc2VzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUmVnaW9ucyBhbG9uZTogYSBibGFuayBzdGFjayBhcyBsYXJnZSBhcyB0aGV5IHJlYWNoLCBtZWFzdXJlZCBvbiB0aGUgc291cmNlcyAoa2VwdCBvcGVuXG4gICAgICAvLyBmb3IgdGhlaXIgc2xpY2VzLCBzbyBlYWNoIGlzIHBhcnNlZCBvbmNlKS5cbiAgICAgIGNvbnN0IG1lYXN1cmVkID0gYXdhaXQgbWVhc3VyZShzZXQub3BlbmVycyk7XG4gICAgICBvcGVuZXJzID0gbWVhc3VyZWQub3BlbmVycztcbiAgICAgIHJlbGVhc2UgPSBtZWFzdXJlZC5yZWxlYXNlO1xuICAgICAgW3dpZHRoLCBoZWlnaHRdID0gbWVhc3VyZWQuc2l6ZTtcbiAgICAgIGNoZWNrU2l6ZSh3aWR0aCwgaGVpZ2h0KTtcbiAgICAgIGNvbnN0IHBuZyA9IGVuY29kZVBuZyh7IHdpZHRoLCBoZWlnaHQsIGRhdGE6IG5ldyBVaW50OEFycmF5KHdpZHRoICogaGVpZ2h0KSwgY2hhbm5lbHM6IDEsIGRlcHRoOiA4IH0pO1xuICAgICAgY29uc3QgYmxhbmsgPSBuZXcgQmxvYihbcG5nIGFzIEJsb2JQYXJ0XSwgeyB0eXBlOiAnaW1hZ2UvcG5nJyB9KTtcbiAgICAgIHVybHMgPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiBzZXQuc2xpY2VzIH0sICgpID0+IFVSTC5jcmVhdGVPYmplY3RVUkwoYmxhbmspKTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIHVybHMuZm9yRWFjaCgodSkgPT4gVVJMLnJldm9rZU9iamVjdFVSTCh1KSk7XG4gICAgcmVsZWFzZSgpO1xuICAgIHRocm93IGVycjtcbiAgfVxuICBjb25zdCBbbXgsIG15LCBtel0gPSBzZXQuc3BhY2luZyA/PyBbXTtcbiAgY29uc3QgaXNTdGFjayA9IHNldC5zbGljZXMgPiAxO1xuICBjb25zdCBpbmZvOiBJSW1hZ2VJbmZvID0ge1xuICAgIGlzR3JheXNjYWxlOiB0cnVlLFxuICAgIHRydWVJbWFnZVNpemU6IFt3aWR0aCwgaGVpZ2h0XSxcbiAgICB1cmxzLFxuICAgIGlzU3RhY2ssXG4gICAgc2hvd1N0YWNrOiBmYWxzZSxcbiAgICBzY2FsZVJhdGlvOiB0cnVlLFxuICAgIC8vIFVuaXF1ZTogdGhlIHNsaWNlIGNhY2hlIGtleXMgb24gdGhlIG5hbWUsIGFuZCB0d28gb3BlbmVkIHNldHMgbXVzdCBub3Qgc2hhcmUgc2xpY2VzLlxuICAgIGZpbGVOYW1lOiBgJHtzZXQubmFtZX0gwrcgYW5ub3RhdGlvbnMgWyR7KytvcGVuZWR9XWAsXG4gICAgaW1hZ2VNZXRhOiBbXG4gICAgICB7XG4gICAgICAgIGNoYW5uZWxDb3VudDogMSxcbiAgICAgICAgcmdiQ2hhbm5lbHM6IDEsXG4gICAgICAgIHg6IHdpZHRoLFxuICAgICAgICB5OiBoZWlnaHQsXG4gICAgICAgIHo6IHNldC5zbGljZXMsXG4gICAgICAgIG1wcFg6IG14ID8/IG51bGwsXG4gICAgICAgIG1wcFk6IG15ID8/IG51bGwsXG4gICAgICAgIC4uLihteiAhPSBudWxsID8geyBtcHBaOiBteiB9IDoge30pLFxuICAgICAgfSxcbiAgICBdLFxuICAgIHRpbGVkOiBmYWxzZSxcbiAgICAvLyBPcGVuIG1pZC1zdGFjazogYW4gYXRsYXMncyBmaXJzdCBhbmQgbGFzdCBzZWN0aW9ucyBhcmUgbW9zdGx5IGVtcHR5LlxuICAgIGluaXRpYWxaSW5kZXg6IGlzU3RhY2sgPyBzZXQuc2xpY2VzID4+IDEgOiB1bmRlZmluZWQsXG4gICAgcmVnaW9uU2xpY2VzOiBvcGVuZXJzLFxuICB9IGFzIElJbWFnZUluZm87XG4gIHJldHVybiB7XG4gICAgaW5mbyxcbiAgICBzdW1tYXJ5OiBgJHtzZXQuc3VtbWFyeX0sICR7d2lkdGh9IMOXICR7aGVpZ2h0fWAsXG4gICAgZGlzcG9zZTogKCkgPT4ge1xuICAgICAgdXJscy5mb3JFYWNoKCh1KSA9PiBVUkwucmV2b2tlT2JqZWN0VVJMKHUpKTtcbiAgICAgIHJlbGVhc2UoKTtcbiAgICB9LFxuICB9O1xufVxuXG5mdW5jdGlvbiBsYWJlbFNsaWNlcyhcbiAga2luZDogJ2xhYmVscycsXG4gIG5hbWU6IHN0cmluZyxcbiAgc3RhY2s6IExhYmVsU3RhY2ssXG4gIGNsYXNzZXM6IExhYmVsQ2xhc3NlcyxcbiAgb3Blbkdlb0pzb246ICh0ZXh0OiBzdHJpbmcpID0+IFByb21pc2U8UmVnaW9uU291cmNlPixcbik6IEFubm90YXRpb25TbGljZXMge1xuICBjb25zdCBvcGVuZXJzID0gbmV3IE1hcDxudW1iZXIsIE9wZW5lcj4oKTtcbiAgZm9yIChsZXQgeiA9IDA7IHogPCBzdGFjay5zbGljZXM7IHorKykge1xuICAgIG9wZW5lcnMuc2V0KHosIGFzeW5jICgpID0+IG9wZW5HZW9Kc29uKGxhYmVsU2xpY2VHZW9Kc29uKG9uZVNsaWNlKHN0YWNrLCBhd2FpdCBzdGFjay5sYWJlbHMoeikpLCAwLCBjbGFzc2VzKSkpO1xuICB9XG4gIHJldHVybiB7XG4gICAga2luZCxcbiAgICBuYW1lLFxuICAgIHNsaWNlczogc3RhY2suc2xpY2VzLFxuICAgIG9wZW5lcnMsXG4gICAgbGFiZWxzOiB7IHN0YWNrLCBjbGFzc2VzIH0sXG4gICAgc2l6ZTogW3N0YWNrLndpZHRoLCBzdGFjay5oZWlnaHRdLFxuICAgIC4uLihzdGFjay5zcGFjaW5nID8geyBzcGFjaW5nOiBzdGFjay5zcGFjaW5nIH0gOiB7fSksXG4gICAgc3VtbWFyeTogYCR7c3RhY2suc2xpY2VzfSBzbGljZSR7c3RhY2suc2xpY2VzID09PSAxID8gJycgOiAncyd9IG9mICR7c3RhY2sud2lkdGh9IMOXICR7c3RhY2suaGVpZ2h0fWAsXG4gIH07XG59XG5cbi8qKiBgY2xhc3Nlc2AsIHdpdGggdGhlIGF0bGFzIGxvb2sgd2hlbiBhc2tlZCBmb3IgYW5kIHRoZXkgbmFtZSBubyBzdHlsZSBvZiB0aGVpciBvd24uICovXG5mdW5jdGlvbiBzdHlsZWQoY2xhc3NlczogTGFiZWxDbGFzc2VzLCBkZWNvZGVyczogQW5ub3RhdGlvbkRlY29kZXJzKTogTGFiZWxDbGFzc2VzIHtcbiAgcmV0dXJuIGRlY29kZXJzLm91dGxpbmVMYWJlbHMgJiYgIWNsYXNzZXMuc3R5bGUgPyB7IC4uLmNsYXNzZXMsIHN0eWxlOiBBVExBU19TVFlMRSB9IDogY2xhc3Nlcztcbn1cblxuLyoqIEEgbGFiZWwgdm9sdW1lIGFzIGEgc3RhY2sgcmVhZCBvbiBkZW1hbmQuICovXG5mdW5jdGlvbiBzdGFja09mKHZvbHVtZTogTGFiZWxWb2x1bWUpOiBMYWJlbFN0YWNrIHtcbiAgcmV0dXJuIHtcbiAgICB3aWR0aDogdm9sdW1lLndpZHRoLFxuICAgIGhlaWdodDogdm9sdW1lLmhlaWdodCxcbiAgICBzbGljZXM6IHZvbHVtZS5zbGljZXMsXG4gICAgLi4uKHZvbHVtZS5zcGFjaW5nID8geyBzcGFjaW5nOiB2b2x1bWUuc3BhY2luZyB9IDoge30pLFxuICAgIGxhYmVsczogYXN5bmMgKHopID0+IHZvbHVtZS5zbGljZUxhYmVscyh6KSxcbiAgfTtcbn1cblxuLyoqIE9uZSBzbGljZSdzIGxhYmVscyBhcyB0aGUgb25lLXNsaWNlIHZvbHVtZSB0aGUgdHJhY2VyIHJlYWRzLiAqL1xuZnVuY3Rpb24gb25lU2xpY2Uoc3RhY2s6IExhYmVsU3RhY2ssIGxhYmVsczogVWludDMyQXJyYXkpOiBMYWJlbFZvbHVtZSB7XG4gIHJldHVybiB7IGZvcm1hdDogJ25ycmQnLCB3aWR0aDogc3RhY2sud2lkdGgsIGhlaWdodDogc3RhY2suaGVpZ2h0LCBzbGljZXM6IDEsIHNsaWNlTGFiZWxzOiAoKSA9PiBsYWJlbHMgfTtcbn1cblxuLyoqXG4gKiBFdmVyeSBzbGljZSBhcyBhIGdyYXlzY2FsZSBQTkcgYmxvYiBVUkwsIGVhY2ggbGFiZWwgYXQgaXRzIGNsYXNzIGNvbG91cidzIGx1bWluYW5jZSAobmV2ZXIgMCksXG4gKiBiYWNrZ3JvdW5kIGJsYWNrLiBHcmF5c2NhbGUsIG5vdCBjb2xvdXI6IHRoZSBWb2x1bWUgYW5kIElzb3N1cmZhY2Ugdmlld3MgdGFrZSBhIGdyYXlzY2FsZSBzdGFjayxcbiAqIGFuZCB0aGUgY29sb3VyIGlzIHRoZSByZWdpb25zJyBvd24sIGZpbGxlZCBvdmVyIGl0IGluIHRoZWlyIGNsYXNzZXMnIGNvbG91cnMgKHRoZSBhdGxhcyBsb29rKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gbGFiZWxTbGljZVVybHMoc3RhY2s6IExhYmVsU3RhY2ssIGNsYXNzZXM6IExhYmVsQ2xhc3Nlcyk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgY29uc3QgbGV2ZWxzID0gbmV3IE1hcDxudW1iZXIsIG51bWJlcj4oKTtcbiAgY29uc3QgbGV2ZWxPZiA9ICh2OiBudW1iZXIpID0+IHtcbiAgICBsZXQgbCA9IGxldmVscy5nZXQodik7XG4gICAgaWYgKGwgPT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgaGV4ID0gY2xhc3Nlcy5jbGFzc09mKHYpLmNvbG9yO1xuICAgICAgY29uc3QgW3IsIGcsIGJdID0gWzEsIDMsIDVdLm1hcCgobykgPT4gcGFyc2VJbnQoaGV4LnNsaWNlKG8sIG8gKyAyKSwgMTYpKTtcbiAgICAgIGwgPSBNYXRoLm1heCgxLCBNYXRoLnJvdW5kKDAuMjk5ICogciArIDAuNTg3ICogZyArIDAuMTE0ICogYikpO1xuICAgICAgbGV2ZWxzLnNldCh2LCBsKTtcbiAgICB9XG4gICAgcmV0dXJuIGw7XG4gIH07XG4gIGNvbnN0IHVybHM6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IGdyYXkgPSBuZXcgVWludDhBcnJheShzdGFjay53aWR0aCAqIHN0YWNrLmhlaWdodCk7XG4gIGZvciAobGV0IHogPSAwOyB6IDwgc3RhY2suc2xpY2VzOyB6KyspIHtcbiAgICBjb25zdCBsYWJlbHMgPSBhd2FpdCBzdGFjay5sYWJlbHMoeik7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsYWJlbHMubGVuZ3RoOyBpKyspIGdyYXlbaV0gPSBsYWJlbHNbaV0gPyBsZXZlbE9mKGxhYmVsc1tpXSkgOiAwO1xuICAgIGNvbnN0IHBuZyA9IGVuY29kZVBuZyh7IHdpZHRoOiBzdGFjay53aWR0aCwgaGVpZ2h0OiBzdGFjay5oZWlnaHQsIGRhdGE6IGdyYXksIGNoYW5uZWxzOiAxLCBkZXB0aDogOCB9KTtcbiAgICB1cmxzLnB1c2goVVJMLmNyZWF0ZU9iamVjdFVSTChuZXcgQmxvYihbcG5nIGFzIEJsb2JQYXJ0XSwgeyB0eXBlOiAnaW1hZ2UvcG5nJyB9KSkpO1xuICB9XG4gIHJldHVybiB1cmxzO1xufVxuXG4vKipcbiAqIE9wZW4gZXZlcnkgc2xpY2UncyBzb3VyY2UgdG8gbGVhcm4gaG93IGZhciB0aGUgcmVnaW9ucyByZWFjaCAodGhlIGltYWdlIGlzIGFzIGxhcmdlLCBmcm9tIHRoZVxuICogb3JpZ2luLCBhcyByZWdpb24gY29vcmRpbmF0ZXMgYXJlIGltYWdlIHBpeGVscykuIEVhY2ggb3BlbmVyIHRoZW4gaGFuZHMgaXRzIGFscmVhZHktb3BlbiBzb3VyY2VcbiAqIG92ZXIgdGhlIGZpcnN0IHRpbWUgKHRoZSByZWdpb24gc3RvcmUgb3ducyBpdCBmcm9tIHRoZW4gb24pIGFuZCBvcGVucyBhbmV3IGFmdGVyLiBgcmVsZWFzZWBcbiAqIGRpc3Bvc2VzIHRoZSBzb3VyY2VzIG5vdCBoYW5kZWQgb3ZlciB5ZXQ7IHRoZXkgYXJlIHJlbGVhc2VkIGhlcmUgd2hlbiBtZWFzdXJpbmcgZmFpbHMuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIG1lYXN1cmUoXG4gIG9wZW5lcnM6IE1hcDxudW1iZXIsIE9wZW5lcj4sXG4pOiBQcm9taXNlPHsgb3BlbmVyczogTWFwPG51bWJlciwgT3BlbmVyPjsgc2l6ZTogW251bWJlciwgbnVtYmVyXTsgcmVsZWFzZTogKCkgPT4gdm9pZCB9PiB7XG4gIC8vIFNvdXJjZXMgb3BlbmVkIGhlcmUgYW5kIG5vdCB5ZXQgaGFuZGVkIHRvIHRoZSBzdG9yZTogdGhlaXJzIHRvIHJlbGVhc2UgdW50aWwgdGhlbi5cbiAgY29uc3QgaGVsZCA9IG5ldyBNYXA8bnVtYmVyLCBSZWdpb25Tb3VyY2U+KCk7XG4gIGNvbnN0IHJlbGVhc2UgPSAoKSA9PiB7XG4gICAgZm9yIChjb25zdCBzb3VyY2Ugb2YgaGVsZC52YWx1ZXMoKSkgc291cmNlLmRpc3Bvc2UoKTtcbiAgICBoZWxkLmNsZWFyKCk7XG4gIH07XG4gIGxldCB4MSA9IDA7XG4gIGxldCB5MSA9IDA7XG4gIHRyeSB7XG4gICAgZm9yIChjb25zdCBbeiwgb3Blbl0gb2Ygb3BlbmVycykge1xuICAgICAgY29uc3Qgc291cmNlID0gYXdhaXQgb3BlbigpO1xuICAgICAgaGVsZC5zZXQoeiwgc291cmNlKTtcbiAgICAgIGNvbnN0IGJvdW5kcyA9IHNvdXJjZS5pbmZvLmJvdW5kcztcbiAgICAgIGlmIChib3VuZHMpIHtcbiAgICAgICAgeDEgPSBNYXRoLm1heCh4MSwgYm91bmRzWzJdKTtcbiAgICAgICAgeTEgPSBNYXRoLm1heCh5MSwgYm91bmRzWzNdKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCEoeDEgPiAwICYmIHkxID4gMCkpIHRocm93IG5ldyBFcnJvcignVGhlIHJlZ2lvbnMgaGF2ZSBubyBleHRlbnQgdG8gc2hvdy4nKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgcmVsZWFzZSgpO1xuICAgIHRocm93IGVycjtcbiAgfVxuICBjb25zdCByZXVzZWQgPSBuZXcgTWFwPG51bWJlciwgT3BlbmVyPigpO1xuICBmb3IgKGNvbnN0IFt6LCBvcGVuXSBvZiBvcGVuZXJzKSB7XG4gICAgcmV1c2VkLnNldCh6LCAoKSA9PiB7XG4gICAgICBjb25zdCBmaXJzdCA9IGhlbGQuZ2V0KHopO1xuICAgICAgaWYgKCFmaXJzdCkgcmV0dXJuIG9wZW4oKTtcbiAgICAgIGhlbGQuZGVsZXRlKHopO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShmaXJzdCk7XG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIHsgb3BlbmVyczogcmV1c2VkLCBzaXplOiBbTWF0aC5jZWlsKHgxKSwgTWF0aC5jZWlsKHkxKV0sIHJlbGVhc2UgfTtcbn1cblxuZnVuY3Rpb24gY2hlY2tTaXplKHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyKTogdm9pZCB7XG4gIGlmIChNYXRoLm1heCh3aWR0aCwgaGVpZ2h0KSA+IEFOTk9UQVRJT05fSU1BR0VfTUFYX0RJTSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBUaGUgYW5ub3RhdGlvbnMgc3BhbiAke3dpZHRofSDDlyAke2hlaWdodH0gcGl4ZWxzLCBtb3JlIHRoYW4gJHtBTk5PVEFUSU9OX0lNQUdFX01BWF9ESU19IG9uIGEgc2lkZTogYCArXG4gICAgICAgICdvcGVuIHRoZSBpbWFnZSB0aGV5IHdlcmUgZHJhd24gb24sIGFuZCBpbXBvcnQgdGhlbSBvbnRvIGl0IGZyb20gdGhlIFJlZ2lvbiBFZGl0b3IuJyxcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogT25lIEdlb0pTT04ncyBzbGljZXM6IGEgY29sbGVjdGlvbiB3aG9zZSBmZWF0dXJlcyBuYW1lIHBsYW5lcyAoYGdlb21ldHJ5LnBsYW5lLnpgKSBzcGxpdCBpbnRvXG4gKiBvbmUgY29sbGVjdGlvbiBwZXIgcGxhbmUsIGVhY2gga2VlcGluZyB0aGUgc2V0J3MgY2xhc3MgdHJlZSBhbmQgc3R5bGUsIGl0cyBmZWF0dXJlcyBtb3ZlZCB0b1xuICogcGxhbmUgMCAoYSBzbGljZSdzIHNvdXJjZSBzaG93cyBwbGFuZSAwKTsgYW55IG90aGVyIEdlb0pTT04gaXMgb25lIHNsaWNlIGFzIGl0IGlzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc3BsaXRCeVBsYW5lKHRleHQ6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgY29uc3QgZG9jID0gSlNPTi5wYXJzZSh0ZXh0KSBhcyB7IHR5cGU/OiBzdHJpbmc7IGZlYXR1cmVzPzogQXJyYXk8eyBnZW9tZXRyeT86IHsgcGxhbmU/OiB7IHo/OiBudW1iZXIgfSB9IH0+IH07XG4gIGNvbnN0IGZlYXR1cmVzID0gZG9jLnR5cGUgPT09ICdGZWF0dXJlQ29sbGVjdGlvbicgPyAoZG9jLmZlYXR1cmVzID8/IFtdKSA6IFtdO1xuICBjb25zdCB6T2YgPSAoZjogKHR5cGVvZiBmZWF0dXJlcylbbnVtYmVyXSkgPT4gTWF0aC5tYXgoMCwgTWF0aC5mbG9vcihmLmdlb21ldHJ5Py5wbGFuZT8ueiA/PyAwKSk7XG4gIGNvbnN0IGxhc3QgPSBmZWF0dXJlcy5yZWR1Y2UoKG0sIGYpID0+IE1hdGgubWF4KG0sIHpPZihmKSksIDApO1xuICBpZiAobGFzdCA9PT0gMCkgcmV0dXJuIFt0ZXh0XTtcbiAgY29uc3Qgc2xpY2VzID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogbGFzdCArIDEgfSwgKCkgPT4gW10gYXMgdW5rbm93bltdKTtcbiAgZm9yIChjb25zdCBmIG9mIGZlYXR1cmVzKSB7XG4gICAgY29uc3QgeiA9IHpPZihmKTtcbiAgICBjb25zdCBnZW9tZXRyeSA9IGYuZ2VvbWV0cnkgPyB7IC4uLmYuZ2VvbWV0cnkgfSA6IGYuZ2VvbWV0cnk7XG4gICAgaWYgKGdlb21ldHJ5KSBkZWxldGUgZ2VvbWV0cnkucGxhbmU7XG4gICAgc2xpY2VzW3pdLnB1c2goeyAuLi5mLCBnZW9tZXRyeSB9KTtcbiAgfVxuICByZXR1cm4gc2xpY2VzLm1hcCgobGlzdCkgPT4gSlNPTi5zdHJpbmdpZnkoeyAuLi5kb2MsIGZlYXR1cmVzOiBsaXN0IH0pKTtcbn1cblxuZnVuY3Rpb24gc3RlbShuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gKG5hbWUuc3BsaXQoJy8nKS5wb3AoKSA/PyBuYW1lKS5yZXBsYWNlKC9cXC4obmlpXFwuZ3p8bmlpfG5ycmR8Z2VvanNvbnxqc29ufHppcCkkL2ksICcnKTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { isLabelVolumeName } from './label-volume';
|
|
2
|
+
/** `data`, named `name`, as an import file. A `File`'s own name is used when `name` is omitted. */
|
|
3
|
+
export function importFile(data, name = data.name ?? '') {
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
return {
|
|
6
|
+
name,
|
|
7
|
+
text: async () => typeof data === 'string'
|
|
8
|
+
? data
|
|
9
|
+
: data instanceof Blob
|
|
10
|
+
? data.text()
|
|
11
|
+
: new TextDecoder().decode(data instanceof Uint8Array ? data : new Uint8Array(data)),
|
|
12
|
+
bytes: async () => typeof data === 'string'
|
|
13
|
+
? encoder.encode(data)
|
|
14
|
+
: data instanceof Blob
|
|
15
|
+
? new Uint8Array(await data.arrayBuffer())
|
|
16
|
+
: data instanceof Uint8Array
|
|
17
|
+
? data
|
|
18
|
+
: new Uint8Array(data),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const leaf = (name) => name.split(/[\\/]/).pop() ?? name;
|
|
22
|
+
const isRegionSet = (f) => leaf(f.name).toLowerCase() === 'regionset.json';
|
|
23
|
+
const isGeoJson = (f) => /\.geojson$/i.test(f.name);
|
|
24
|
+
const isJson = (f) => /\.json$/i.test(f.name);
|
|
25
|
+
/**
|
|
26
|
+
* What `files` import as: a label volume (`.nii`, `.nii.gz`, `.nrrd`) with the ontology JSON chosen
|
|
27
|
+
* with it (a `regionset.json`, else an Allen `structure_graph*.json`, else any `.json`); several
|
|
28
|
+
* region files (a folder of per-slice `.geojson`, in natural name order, its `regionset.json`
|
|
29
|
+
* apart); or one region file (`.geojson` or `.json`). Null when none of them is one.
|
|
30
|
+
*/
|
|
31
|
+
export function planRegionImport(files) {
|
|
32
|
+
const volume = files.find((f) => isLabelVolumeName(f.name));
|
|
33
|
+
if (volume) {
|
|
34
|
+
const jsons = files.filter((f) => f !== volume && isJson(f));
|
|
35
|
+
const ontology = jsons.find(isRegionSet) ??
|
|
36
|
+
jsons.find((f) => /structure_graph.*\.json$/i.test(leaf(f.name))) ??
|
|
37
|
+
jsons[0] ??
|
|
38
|
+
null;
|
|
39
|
+
return { kind: 'volume', volume, ontology };
|
|
40
|
+
}
|
|
41
|
+
const regionSet = files.find(isRegionSet) ?? null;
|
|
42
|
+
const geojsons = files.filter((f) => isGeoJson(f));
|
|
43
|
+
const regionFiles = geojsons.length ? geojsons : files.filter((f) => isJson(f) && !isRegionSet(f));
|
|
44
|
+
if (regionFiles.length > 1 || (regionFiles.length === 1 && regionSet)) {
|
|
45
|
+
const slices = [...regionFiles].sort((a, b) => naturalCompare(leaf(a.name), leaf(b.name)));
|
|
46
|
+
return { kind: 'folder', slices, regionSet };
|
|
47
|
+
}
|
|
48
|
+
return regionFiles.length === 1 ? { kind: 'single', file: regionFiles[0] } : null;
|
|
49
|
+
}
|
|
50
|
+
/** "slice_2" before "slice_10": runs of digits compared as numbers. */
|
|
51
|
+
export function naturalCompare(a, b) {
|
|
52
|
+
return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A folder slice's GeoJSON with the set's class tree and style (its `regionset.json`) as the
|
|
56
|
+
* collection's own members, unless the file has its own: what a served folder's slice carries.
|
|
57
|
+
*/
|
|
58
|
+
export async function folderSliceGeoJson(file, regionSet) {
|
|
59
|
+
const text = await file.text();
|
|
60
|
+
if (!regionSet || (!regionSet.classHierarchy && !regionSet.style))
|
|
61
|
+
return text;
|
|
62
|
+
const doc = JSON.parse(text);
|
|
63
|
+
if (doc['type'] !== 'FeatureCollection')
|
|
64
|
+
return text;
|
|
65
|
+
if (regionSet.classHierarchy && !doc['classHierarchy'])
|
|
66
|
+
doc['classHierarchy'] = regionSet.classHierarchy;
|
|
67
|
+
if (regionSet.style && !doc['style'])
|
|
68
|
+
doc['style'] = regionSet.style;
|
|
69
|
+
return JSON.stringify(doc);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLWltcG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWltcG9ydC9yZWdpb24taW1wb3J0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBWW5ELG1HQUFtRztBQUNuRyxNQUFNLFVBQVUsVUFBVSxDQUFDLElBQXNCLEVBQUUsT0FBUSxJQUFhLENBQUMsSUFBSSxJQUFJLEVBQUU7SUFDakYsTUFBTSxPQUFPLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztJQUNsQyxPQUFPO1FBQ0wsSUFBSTtRQUNKLElBQUksRUFBRSxLQUFLLElBQUksRUFBRSxDQUNmLE9BQU8sSUFBSSxLQUFLLFFBQVE7WUFDdEIsQ0FBQyxDQUFDLElBQUk7WUFDTixDQUFDLENBQUMsSUFBSSxZQUFZLElBQUk7Z0JBQ3BCLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO2dCQUNiLENBQUMsQ0FBQyxJQUFJLFdBQVcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLFlBQVksVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFGLEtBQUssRUFBRSxLQUFLLElBQUksRUFBRSxDQUNoQixPQUFPLElBQUksS0FBSyxRQUFRO1lBQ3RCLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztZQUN0QixDQUFDLENBQUMsSUFBSSxZQUFZLElBQUk7Z0JBQ3BCLENBQUMsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxNQUFNLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDMUMsQ0FBQyxDQUFDLElBQUksWUFBWSxVQUFVO29CQUMxQixDQUFDLENBQUMsSUFBSTtvQkFDTixDQUFDLENBQUMsSUFBSSxVQUFVLENBQUMsSUFBSSxDQUFDO0tBQy9CLENBQUM7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QztBQUNwRixDQUFDO0FBRUQsdUVBQXVFO0FBQ3ZFLE1BQU0sVUFBVSxjQUFjLENBQUMsQ0FBUyxFQUFFLENBQVM7SUFDakQsT0FBTyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO0FBQy9FLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUN0QyxJQUFzQixFQUN0QixTQUErRDtJQUUvRCxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMvQixJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUMsY0FBYyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQy9FLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUE0QixDQUFDO0lBQ3hELElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLG1CQUFtQjtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3JELElBQUksU0FBUyxDQUFDLGNBQWMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQztRQUFFLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxjQUFjLENBQUM7SUFDekcsSUFBSSxTQUFTLENBQUMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQztRQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDO0lBQ3JFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUM3QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXNMYWJlbFZvbHVtZU5hbWUgfSBmcm9tICcuL2xhYmVsLXZvbHVtZSc7XG5cbi8qKiBBIGZpbGUgdG8gaW1wb3J0IHJlZ2lvbnMgZnJvbTogb25lIHRoZSB1c2VyIGNob3NlLCBvciBvbmUgdGhlIGhvc3QncyBzZXJ2ZXIgc2VudC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVnaW9uSW1wb3J0RmlsZSB7XG4gIG5hbWU6IHN0cmluZztcbiAgdGV4dCgpOiBQcm9taXNlPHN0cmluZz47XG4gIGJ5dGVzKCk6IFByb21pc2U8VWludDhBcnJheT47XG59XG5cbi8qKiBBIGZpbGUncyBjb250ZW50cyBhcyB0aGUgaG9zdCBtYXkgaGFuZCB0aGVtIG92ZXIgKHNlZSBgU2VydmVyUmVnaW9uUGlja2ApLiAqL1xuZXhwb3J0IHR5cGUgUmVnaW9uSW1wb3J0RGF0YSA9IEJsb2IgfCBBcnJheUJ1ZmZlciB8IFVpbnQ4QXJyYXkgfCBzdHJpbmc7XG5cbi8qKiBgZGF0YWAsIG5hbWVkIGBuYW1lYCwgYXMgYW4gaW1wb3J0IGZpbGUuIEEgYEZpbGVgJ3Mgb3duIG5hbWUgaXMgdXNlZCB3aGVuIGBuYW1lYCBpcyBvbWl0dGVkLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGltcG9ydEZpbGUoZGF0YTogUmVnaW9uSW1wb3J0RGF0YSwgbmFtZSA9IChkYXRhIGFzIEZpbGUpLm5hbWUgPz8gJycpOiBSZWdpb25JbXBvcnRGaWxlIHtcbiAgY29uc3QgZW5jb2RlciA9IG5ldyBUZXh0RW5jb2RlcigpO1xuICByZXR1cm4ge1xuICAgIG5hbWUsXG4gICAgdGV4dDogYXN5bmMgKCkgPT5cbiAgICAgIHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJ1xuICAgICAgICA/IGRhdGFcbiAgICAgICAgOiBkYXRhIGluc3RhbmNlb2YgQmxvYlxuICAgICAgICAgID8gZGF0YS50ZXh0KClcbiAgICAgICAgICA6IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhIGluc3RhbmNlb2YgVWludDhBcnJheSA/IGRhdGEgOiBuZXcgVWludDhBcnJheShkYXRhKSksXG4gICAgYnl0ZXM6IGFzeW5jICgpID0+XG4gICAgICB0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZydcbiAgICAgICAgPyBlbmNvZGVyLmVuY29kZShkYXRhKVxuICAgICAgICA6IGRhdGEgaW5zdGFuY2VvZiBCbG9iXG4gICAgICAgICAgPyBuZXcgVWludDhBcnJheShhd2FpdCBkYXRhLmFycmF5QnVmZmVyKCkpXG4gICAgICAgICAgOiBkYXRhIGluc3RhbmNlb2YgVWludDhBcnJheVxuICAgICAgICAgICAgPyBkYXRhXG4gICAgICAgICAgICA6IG5ldyBVaW50OEFycmF5KGRhdGEpLFxuICB9O1xufVxuXG4vKiogV2hhdCBhIHNldCBvZiBjaG9zZW4gZmlsZXMgaW1wb3J0cyBhcy4gKi9cbmV4cG9ydCB0eXBlIFJlZ2lvbkltcG9ydFBsYW4gPVxuICAvKiogQSBsYWJlbCB2b2x1bWUsIGl0cyBjbGFzc2VzIG5hbWVkIGJ5IGFuIG9udG9sb2d5IChvciBhIHJlZ2lvbiBzZXQgZGVzY3JpcHRpb24pIGJlc2lkZSBpdC4gKi9cbiAgfCB7IGtpbmQ6ICd2b2x1bWUnOyB2b2x1bWU6IFJlZ2lvbkltcG9ydEZpbGU7IG9udG9sb2d5OiBSZWdpb25JbXBvcnRGaWxlIHwgbnVsbCB9XG4gIC8qKiBBIGZvbGRlciBvZiBwZXItc2xpY2UgcmVnaW9uIGZpbGVzLCBpbiBzbGljZSBvcmRlciwgd2l0aCB0aGUgc2V0J3MgYHJlZ2lvbnNldC5qc29uYC4gKi9cbiAgfCB7IGtpbmQ6ICdmb2xkZXInOyBzbGljZXM6IFJlZ2lvbkltcG9ydEZpbGVbXTsgcmVnaW9uU2V0OiBSZWdpb25JbXBvcnRGaWxlIHwgbnVsbCB9XG4gIC8qKiBPbmUgcmVnaW9uIGZpbGUuICovXG4gIHwgeyBraW5kOiAnc2luZ2xlJzsgZmlsZTogUmVnaW9uSW1wb3J0RmlsZSB9O1xuXG5jb25zdCBsZWFmID0gKG5hbWU6IHN0cmluZykgPT4gbmFtZS5zcGxpdCgvW1xcXFwvXS8pLnBvcCgpID8/IG5hbWU7XG5jb25zdCBpc1JlZ2lvblNldCA9IChmOiBSZWdpb25JbXBvcnRGaWxlKSA9PiBsZWFmKGYubmFtZSkudG9Mb3dlckNhc2UoKSA9PT0gJ3JlZ2lvbnNldC5qc29uJztcbmNvbnN0IGlzR2VvSnNvbiA9IChmOiBSZWdpb25JbXBvcnRGaWxlKSA9PiAvXFwuZ2VvanNvbiQvaS50ZXN0KGYubmFtZSk7XG5jb25zdCBpc0pzb24gPSAoZjogUmVnaW9uSW1wb3J0RmlsZSkgPT4gL1xcLmpzb24kL2kudGVzdChmLm5hbWUpO1xuXG4vKipcbiAqIFdoYXQgYGZpbGVzYCBpbXBvcnQgYXM6IGEgbGFiZWwgdm9sdW1lIChgLm5paWAsIGAubmlpLmd6YCwgYC5ucnJkYCkgd2l0aCB0aGUgb250b2xvZ3kgSlNPTiBjaG9zZW5cbiAqIHdpdGggaXQgKGEgYHJlZ2lvbnNldC5qc29uYCwgZWxzZSBhbiBBbGxlbiBgc3RydWN0dXJlX2dyYXBoKi5qc29uYCwgZWxzZSBhbnkgYC5qc29uYCk7IHNldmVyYWxcbiAqIHJlZ2lvbiBmaWxlcyAoYSBmb2xkZXIgb2YgcGVyLXNsaWNlIGAuZ2VvanNvbmAsIGluIG5hdHVyYWwgbmFtZSBvcmRlciwgaXRzIGByZWdpb25zZXQuanNvbmBcbiAqIGFwYXJ0KTsgb3Igb25lIHJlZ2lvbiBmaWxlIChgLmdlb2pzb25gIG9yIGAuanNvbmApLiBOdWxsIHdoZW4gbm9uZSBvZiB0aGVtIGlzIG9uZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBsYW5SZWdpb25JbXBvcnQoZmlsZXM6IHJlYWRvbmx5IFJlZ2lvbkltcG9ydEZpbGVbXSk6IFJlZ2lvbkltcG9ydFBsYW4gfCBudWxsIHtcbiAgY29uc3Qgdm9sdW1lID0gZmlsZXMuZmluZCgoZikgPT4gaXNMYWJlbFZvbHVtZU5hbWUoZi5uYW1lKSk7XG4gIGlmICh2b2x1bWUpIHtcbiAgICBjb25zdCBqc29ucyA9IGZpbGVzLmZpbHRlcigoZikgPT4gZiAhPT0gdm9sdW1lICYmIGlzSnNvbihmKSk7XG4gICAgY29uc3Qgb250b2xvZ3kgPVxuICAgICAganNvbnMuZmluZChpc1JlZ2lvblNldCkgPz9cbiAgICAgIGpzb25zLmZpbmQoKGYpID0+IC9zdHJ1Y3R1cmVfZ3JhcGguKlxcLmpzb24kL2kudGVzdChsZWFmKGYubmFtZSkpKSA/P1xuICAgICAganNvbnNbMF0gPz9cbiAgICAgIG51bGw7XG4gICAgcmV0dXJuIHsga2luZDogJ3ZvbHVtZScsIHZvbHVtZSwgb250b2xvZ3kgfTtcbiAgfVxuICBjb25zdCByZWdpb25TZXQgPSBmaWxlcy5maW5kKGlzUmVnaW9uU2V0KSA/PyBudWxsO1xuICBjb25zdCBnZW9qc29ucyA9IGZpbGVzLmZpbHRlcigoZikgPT4gaXNHZW9Kc29uKGYpKTtcbiAgY29uc3QgcmVnaW9uRmlsZXMgPSBnZW9qc29ucy5sZW5ndGggPyBnZW9qc29ucyA6IGZpbGVzLmZpbHRlcigoZikgPT4gaXNKc29uKGYpICYmICFpc1JlZ2lvblNldChmKSk7XG4gIGlmIChyZWdpb25GaWxlcy5sZW5ndGggPiAxIHx8IChyZWdpb25GaWxlcy5sZW5ndGggPT09IDEgJiYgcmVnaW9uU2V0KSkge1xuICAgIGNvbnN0IHNsaWNlcyA9IFsuLi5yZWdpb25GaWxlc10uc29ydCgoYSwgYikgPT4gbmF0dXJhbENvbXBhcmUobGVhZihhLm5hbWUpLCBsZWFmKGIubmFtZSkpKTtcbiAgICByZXR1cm4geyBraW5kOiAnZm9sZGVyJywgc2xpY2VzLCByZWdpb25TZXQgfTtcbiAgfVxuICByZXR1cm4gcmVnaW9uRmlsZXMubGVuZ3RoID09PSAxID8geyBraW5kOiAnc2luZ2xlJywgZmlsZTogcmVnaW9uRmlsZXNbMF0gfSA6IG51bGw7XG59XG5cbi8qKiBcInNsaWNlXzJcIiBiZWZvcmUgXCJzbGljZV8xMFwiOiBydW5zIG9mIGRpZ2l0cyBjb21wYXJlZCBhcyBudW1iZXJzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5hdHVyYWxDb21wYXJlKGE6IHN0cmluZywgYjogc3RyaW5nKTogbnVtYmVyIHtcbiAgcmV0dXJuIGEubG9jYWxlQ29tcGFyZShiLCB1bmRlZmluZWQsIHsgbnVtZXJpYzogdHJ1ZSwgc2Vuc2l0aXZpdHk6ICdiYXNlJyB9KTtcbn1cblxuLyoqXG4gKiBBIGZvbGRlciBzbGljZSdzIEdlb0pTT04gd2l0aCB0aGUgc2V0J3MgY2xhc3MgdHJlZSBhbmQgc3R5bGUgKGl0cyBgcmVnaW9uc2V0Lmpzb25gKSBhcyB0aGVcbiAqIGNvbGxlY3Rpb24ncyBvd24gbWVtYmVycywgdW5sZXNzIHRoZSBmaWxlIGhhcyBpdHMgb3duOiB3aGF0IGEgc2VydmVkIGZvbGRlcidzIHNsaWNlIGNhcnJpZXMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmb2xkZXJTbGljZUdlb0pzb24oXG4gIGZpbGU6IFJlZ2lvbkltcG9ydEZpbGUsXG4gIHJlZ2lvblNldDogeyBjbGFzc0hpZXJhcmNoeT86IHVua25vd247IHN0eWxlPzogdW5rbm93biB9IHwgbnVsbCxcbik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHRleHQgPSBhd2FpdCBmaWxlLnRleHQoKTtcbiAgaWYgKCFyZWdpb25TZXQgfHwgKCFyZWdpb25TZXQuY2xhc3NIaWVyYXJjaHkgJiYgIXJlZ2lvblNldC5zdHlsZSkpIHJldHVybiB0ZXh0O1xuICBjb25zdCBkb2MgPSBKU09OLnBhcnNlKHRleHQpIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBpZiAoZG9jWyd0eXBlJ10gIT09ICdGZWF0dXJlQ29sbGVjdGlvbicpIHJldHVybiB0ZXh0O1xuICBpZiAocmVnaW9uU2V0LmNsYXNzSGllcmFyY2h5ICYmICFkb2NbJ2NsYXNzSGllcmFyY2h5J10pIGRvY1snY2xhc3NIaWVyYXJjaHknXSA9IHJlZ2lvblNldC5jbGFzc0hpZXJhcmNoeTtcbiAgaWYgKHJlZ2lvblNldC5zdHlsZSAmJiAhZG9jWydzdHlsZSddKSBkb2NbJ3N0eWxlJ10gPSByZWdpb25TZXQuc3R5bGU7XG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShkb2MpO1xufVxuIl19
|