@jax-data-science/sci-image-visualizer 0.11.0 → 0.12.1
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 +4 -1
- package/esm2022/lib/contracts/image.contract.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +18 -6
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +70 -2
- package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +29 -14
- 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/napari-js/region-overlay/region-svg-renderer.mjs +9 -4
- package/esm2022/lib/region-editor/region-editor.component.mjs +46 -41
- package/esm2022/lib/region-import/label-volume.mjs +35 -4
- 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/zarr-codecs.mjs +167 -0
- package/esm2022/lib/region-import/zip.mjs +157 -0
- package/esm2022/lib/routing-visualizer.service.mjs +20 -7
- package/esm2022/lib/visualizer/region-load.mjs +16 -1
- package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DnPlIP2F.mjs} +1103 -71
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DnPlIP2F.mjs.map +1 -0
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-DEDSm_NL.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-Bs987_-E.mjs} +4 -2
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-DEDSm_NL.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-Bs987_-E.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 +6 -0
- package/lib/contracts/image.contract.d.ts +7 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +13 -1
- package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +40 -1
- package/lib/implementations/napari-js/napari-tool-bridge.d.ts +11 -0
- package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +5 -0
- package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +6 -1
- package/lib/region-editor/region-editor.component.d.ts +5 -4
- package/lib/region-import/label-volume.d.ts +4 -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/zarr-codecs.d.ts +14 -0
- package/lib/region-import/zip.d.ts +31 -0
- package/lib/routing-visualizer.service.d.ts +9 -1
- package/package.json +2 -1
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.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,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The chunk codecs of the zarr stores label images come in (OME-Zarr `labels/`): Blosc framing
|
|
3
|
+
* with its lz4, zstd or zlib inner codecs (zarr v2's default, as ome-zarr-py writes), zstd (zarr
|
|
4
|
+
* v3's default), gzip and zlib. Anything else throws rather than be decoded wrongly. Pure: usable
|
|
5
|
+
* from workers.
|
|
6
|
+
*
|
|
7
|
+
* The Blosc framing follows jit-bioformats' `Blosc` (the decoder JIT validated on SpatialData
|
|
8
|
+
* stores): `u8 version, u8 versionlz, u8 flags, u8 typesize, u32 nbytes, u32 blocksize,
|
|
9
|
+
* u32 cbytes`, then `u32 bstarts[nblocks]`, then blocks of `nstreams` sub-streams, each
|
|
10
|
+
* `i32 csize` + bytes (a stream whose csize equals its decoded size stored raw, a negative one a
|
|
11
|
+
* run of one byte). Flags: 0x1 byte-shuffle, 0x2 memcpyed, 0x4 bit-shuffle, 0x10 no-split, bits
|
|
12
|
+
* 5-7 the inner codec.
|
|
13
|
+
*/
|
|
14
|
+
import { decompress as zstdDecompress } from 'fzstd';
|
|
15
|
+
const BLOSC_CODECS = ['blosclz', 'lz4', 'snappy', 'zlib', 'zstd'];
|
|
16
|
+
/** Decode a Blosc frame. */
|
|
17
|
+
export async function bloscDecompress(frame, inflate = platformInflate) {
|
|
18
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
19
|
+
if (frame.length < 16)
|
|
20
|
+
throw new Error('blosc: frame too short');
|
|
21
|
+
const flags = frame[2];
|
|
22
|
+
const typesize = frame[3];
|
|
23
|
+
const nbytes = view.getUint32(4, true);
|
|
24
|
+
const blocksize = view.getUint32(8, true);
|
|
25
|
+
const out = new Uint8Array(nbytes);
|
|
26
|
+
if (nbytes === 0)
|
|
27
|
+
return out;
|
|
28
|
+
if (flags & 0x2) {
|
|
29
|
+
out.set(frame.subarray(16, 16 + nbytes));
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
if (flags & 0x4)
|
|
33
|
+
throw new Error('blosc: bit-shuffle is not supported');
|
|
34
|
+
const code = flags >>> 5;
|
|
35
|
+
const codec = BLOSC_CODECS[code] ?? `code ${code}`;
|
|
36
|
+
if (codec !== 'lz4' && codec !== 'zstd' && codec !== 'zlib') {
|
|
37
|
+
throw new Error(`blosc: inner codec ${codec} is not supported (lz4, zstd or zlib)`);
|
|
38
|
+
}
|
|
39
|
+
const shuffle = (flags & 0x1) !== 0 && typesize > 1;
|
|
40
|
+
const noSplit = (flags & 0x10) !== 0;
|
|
41
|
+
const nblocks = Math.ceil(nbytes / blocksize);
|
|
42
|
+
const scratch = shuffle ? new Uint8Array(blocksize) : null;
|
|
43
|
+
for (let blk = 0; blk < nblocks; blk++) {
|
|
44
|
+
const bsize = Math.min(blocksize, nbytes - blk * blocksize);
|
|
45
|
+
const leftover = bsize !== blocksize;
|
|
46
|
+
const nstreams = !noSplit && !leftover ? typesize : 1;
|
|
47
|
+
const ssize = Math.floor(bsize / nstreams);
|
|
48
|
+
let p = view.getUint32(16 + blk * 4, true);
|
|
49
|
+
const block = scratch ?? out;
|
|
50
|
+
const base = scratch ? 0 : blk * blocksize;
|
|
51
|
+
for (let s = 0; s < nstreams; s++) {
|
|
52
|
+
const csize = view.getInt32(p, true);
|
|
53
|
+
p += 4;
|
|
54
|
+
const dst = base + s * ssize;
|
|
55
|
+
if (csize < 0) {
|
|
56
|
+
block.fill(-csize & 0xff, dst, dst + ssize);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const src = frame.subarray(p, p + csize);
|
|
60
|
+
if (csize === ssize) {
|
|
61
|
+
block.set(src, dst);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const dec = codec === 'lz4'
|
|
65
|
+
? lz4BlockDecompress(src, ssize)
|
|
66
|
+
: codec === 'zstd'
|
|
67
|
+
? zstdDecompress(src)
|
|
68
|
+
: await inflate(src, 'deflate');
|
|
69
|
+
if (dec.length !== ssize)
|
|
70
|
+
throw new Error(`blosc: ${codec} produced ${dec.length} of ${ssize} bytes`);
|
|
71
|
+
block.set(dec, dst);
|
|
72
|
+
}
|
|
73
|
+
p += csize;
|
|
74
|
+
}
|
|
75
|
+
if (scratch)
|
|
76
|
+
unshuffle(scratch, bsize, typesize, out, blk * blocksize);
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/** Decode one LZ4 block (no frame) of `size` bytes. */
|
|
81
|
+
export function lz4BlockDecompress(src, size) {
|
|
82
|
+
const out = new Uint8Array(size);
|
|
83
|
+
let i = 0;
|
|
84
|
+
let o = 0;
|
|
85
|
+
while (i < src.length) {
|
|
86
|
+
const token = src[i++];
|
|
87
|
+
let literals = token >>> 4;
|
|
88
|
+
if (literals === 15) {
|
|
89
|
+
let b;
|
|
90
|
+
do {
|
|
91
|
+
b = src[i++];
|
|
92
|
+
literals += b;
|
|
93
|
+
} while (b === 255);
|
|
94
|
+
}
|
|
95
|
+
if (o + literals > size || i + literals > src.length)
|
|
96
|
+
throw new Error('lz4: literals overrun');
|
|
97
|
+
out.set(src.subarray(i, i + literals), o);
|
|
98
|
+
i += literals;
|
|
99
|
+
o += literals;
|
|
100
|
+
if (i >= src.length)
|
|
101
|
+
break; // the last sequence has no match
|
|
102
|
+
const offset = src[i] | (src[i + 1] << 8);
|
|
103
|
+
i += 2;
|
|
104
|
+
if (offset === 0 || offset > o)
|
|
105
|
+
throw new Error('lz4: bad match offset');
|
|
106
|
+
let length = (token & 15) + 4;
|
|
107
|
+
if ((token & 15) === 15) {
|
|
108
|
+
let b;
|
|
109
|
+
do {
|
|
110
|
+
b = src[i++];
|
|
111
|
+
length += b;
|
|
112
|
+
} while (b === 255);
|
|
113
|
+
}
|
|
114
|
+
if (o + length > size)
|
|
115
|
+
throw new Error('lz4: match overrun');
|
|
116
|
+
// Byte by byte: a match may overlap what it copies (a run).
|
|
117
|
+
for (let k = 0; k < length; k++, o++)
|
|
118
|
+
out[o] = out[o - offset];
|
|
119
|
+
}
|
|
120
|
+
if (o !== size)
|
|
121
|
+
throw new Error(`lz4: produced ${o} of ${size} bytes`);
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Decode a zarr chunk through `codecs`, outermost last as zarr lists them (v2: the one
|
|
126
|
+
* `compressor`; v3: the bytes-to-bytes codecs after `bytes`).
|
|
127
|
+
*/
|
|
128
|
+
export async function decodeChunk(bytes, codecs, inflate = platformInflate) {
|
|
129
|
+
let data = bytes;
|
|
130
|
+
for (const codec of [...codecs].reverse()) {
|
|
131
|
+
switch (codec.id) {
|
|
132
|
+
case 'blosc':
|
|
133
|
+
data = await bloscDecompress(data, inflate);
|
|
134
|
+
break;
|
|
135
|
+
case 'zstd':
|
|
136
|
+
data = zstdDecompress(data);
|
|
137
|
+
break;
|
|
138
|
+
case 'gzip':
|
|
139
|
+
data = await inflate(data, 'gzip');
|
|
140
|
+
break;
|
|
141
|
+
case 'zlib':
|
|
142
|
+
data = await inflate(data, 'deflate');
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
throw new Error(`zarr: codec ${codec.id} is not supported (blosc, zstd, gzip, zlib)`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return data;
|
|
149
|
+
}
|
|
150
|
+
function unshuffle(src, len, typesize, dst, off) {
|
|
151
|
+
const n = Math.floor(len / typesize);
|
|
152
|
+
for (let j = 0; j < typesize; j++) {
|
|
153
|
+
const base = j * n;
|
|
154
|
+
for (let i = 0; i < n; i++)
|
|
155
|
+
dst[off + i * typesize + j] = src[base + i];
|
|
156
|
+
}
|
|
157
|
+
// Bytes past the last whole element are not shuffled.
|
|
158
|
+
for (let k = n * typesize; k < len; k++)
|
|
159
|
+
dst[off + k] = src[k];
|
|
160
|
+
}
|
|
161
|
+
async function platformInflate(bytes, format) {
|
|
162
|
+
if (typeof DecompressionStream === 'undefined')
|
|
163
|
+
throw new Error(`zarr: ${format} chunks need DecompressionStream`);
|
|
164
|
+
const stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream(format));
|
|
165
|
+
return new Uint8Array(await new Response(stream).arrayBuffer());
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiemFyci1jb2RlY3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3JlZ2lvbi1pbXBvcnQvemFyci1jb2RlY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsT0FBTyxFQUFFLFVBQVUsSUFBSSxjQUFjLEVBQUUsTUFBTSxPQUFPLENBQUM7QUFLckQsTUFBTSxZQUFZLEdBQUcsQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFFbEUsNEJBQTRCO0FBQzVCLE1BQU0sQ0FBQyxLQUFLLFVBQVUsZUFBZSxDQUFDLEtBQWlCLEVBQUUsVUFBbUIsZUFBZTtJQUN6RixNQUFNLElBQUksR0FBRyxJQUFJLFFBQVEsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzVFLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxFQUFFO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0lBQ2pFLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2QixNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdkMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDMUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDbkMsSUFBSSxNQUFNLEtBQUssQ0FBQztRQUFFLE9BQU8sR0FBRyxDQUFDO0lBQzdCLElBQUksS0FBSyxHQUFHLEdBQUcsRUFBRSxDQUFDO1FB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LElBQUksS0FBSyxDQUFDLFNBQVMsTUFBTSxrQ0FBa0MsQ0FBQyxDQUFDO0lBQ3JFLE1BQU0sTUFBTSxHQUFHLElBQUksSUFBSSxDQUFDLENBQUMsS0FBaUIsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsV0FBVyxDQUFDLElBQUksbUJBQW1CLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUNuRyxPQUFPLElBQUksVUFBVSxDQUFDLE1BQU0sSUFBSSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztBQUNsRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGUgY2h1bmsgY29kZWNzIG9mIHRoZSB6YXJyIHN0b3JlcyBsYWJlbCBpbWFnZXMgY29tZSBpbiAoT01FLVphcnIgYGxhYmVscy9gKTogQmxvc2MgZnJhbWluZ1xuICogd2l0aCBpdHMgbHo0LCB6c3RkIG9yIHpsaWIgaW5uZXIgY29kZWNzICh6YXJyIHYyJ3MgZGVmYXVsdCwgYXMgb21lLXphcnItcHkgd3JpdGVzKSwgenN0ZCAoemFyclxuICogdjMncyBkZWZhdWx0KSwgZ3ppcCBhbmQgemxpYi4gQW55dGhpbmcgZWxzZSB0aHJvd3MgcmF0aGVyIHRoYW4gYmUgZGVjb2RlZCB3cm9uZ2x5LiBQdXJlOiB1c2FibGVcbiAqIGZyb20gd29ya2Vycy5cbiAqXG4gKiBUaGUgQmxvc2MgZnJhbWluZyBmb2xsb3dzIGppdC1iaW9mb3JtYXRzJyBgQmxvc2NgICh0aGUgZGVjb2RlciBKSVQgdmFsaWRhdGVkIG9uIFNwYXRpYWxEYXRhXG4gKiBzdG9yZXMpOiBgdTggdmVyc2lvbiwgdTggdmVyc2lvbmx6LCB1OCBmbGFncywgdTggdHlwZXNpemUsIHUzMiBuYnl0ZXMsIHUzMiBibG9ja3NpemUsXG4gKiB1MzIgY2J5dGVzYCwgdGhlbiBgdTMyIGJzdGFydHNbbmJsb2Nrc11gLCB0aGVuIGJsb2NrcyBvZiBgbnN0cmVhbXNgIHN1Yi1zdHJlYW1zLCBlYWNoXG4gKiBgaTMyIGNzaXplYCArIGJ5dGVzIChhIHN0cmVhbSB3aG9zZSBjc2l6ZSBlcXVhbHMgaXRzIGRlY29kZWQgc2l6ZSBzdG9yZWQgcmF3LCBhIG5lZ2F0aXZlIG9uZSBhXG4gKiBydW4gb2Ygb25lIGJ5dGUpLiBGbGFnczogMHgxIGJ5dGUtc2h1ZmZsZSwgMHgyIG1lbWNweWVkLCAweDQgYml0LXNodWZmbGUsIDB4MTAgbm8tc3BsaXQsIGJpdHNcbiAqIDUtNyB0aGUgaW5uZXIgY29kZWMuXG4gKi9cbmltcG9ydCB7IGRlY29tcHJlc3MgYXMgenN0ZERlY29tcHJlc3MgfSBmcm9tICdmenN0ZCc7XG5cbi8qKiBJbmZsYXRlIGd6aXAgb3IgemxpYiBkYXRhIChkZWZhdWx0OiB0aGUgcGxhdGZvcm0ncyBgRGVjb21wcmVzc2lvblN0cmVhbWApLiAqL1xuZXhwb3J0IHR5cGUgSW5mbGF0ZSA9IChieXRlczogVWludDhBcnJheSwgZm9ybWF0OiAnZ3ppcCcgfCAnZGVmbGF0ZScpID0+IFByb21pc2U8VWludDhBcnJheT47XG5cbmNvbnN0IEJMT1NDX0NPREVDUyA9IFsnYmxvc2NseicsICdsejQnLCAnc25hcHB5JywgJ3psaWInLCAnenN0ZCddO1xuXG4vKiogRGVjb2RlIGEgQmxvc2MgZnJhbWUuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYmxvc2NEZWNvbXByZXNzKGZyYW1lOiBVaW50OEFycmF5LCBpbmZsYXRlOiBJbmZsYXRlID0gcGxhdGZvcm1JbmZsYXRlKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gIGNvbnN0IHZpZXcgPSBuZXcgRGF0YVZpZXcoZnJhbWUuYnVmZmVyLCBmcmFtZS5ieXRlT2Zmc2V0LCBmcmFtZS5ieXRlTGVuZ3RoKTtcbiAgaWYgKGZyYW1lLmxlbmd0aCA8IDE2KSB0aHJvdyBuZXcgRXJyb3IoJ2Jsb3NjOiBmcmFtZSB0b28gc2hvcnQnKTtcbiAgY29uc3QgZmxhZ3MgPSBmcmFtZVsyXTtcbiAgY29uc3QgdHlwZXNpemUgPSBmcmFtZVszXTtcbiAgY29uc3QgbmJ5dGVzID0gdmlldy5nZXRVaW50MzIoNCwgdHJ1ZSk7XG4gIGNvbnN0IGJsb2Nrc2l6ZSA9IHZpZXcuZ2V0VWludDMyKDgsIHRydWUpO1xuICBjb25zdCBvdXQgPSBuZXcgVWludDhBcnJheShuYnl0ZXMpO1xuICBpZiAobmJ5dGVzID09PSAwKSByZXR1cm4gb3V0O1xuICBpZiAoZmxhZ3MgJiAweDIpIHtcbiAgICBvdXQuc2V0KGZyYW1lLnN1YmFycmF5KDE2LCAxNiArIG5ieXRlcykpO1xuICAgIHJldHVybiBvdXQ7XG4gIH1cbiAgaWYgKGZsYWdzICYgMHg0KSB0aHJvdyBuZXcgRXJyb3IoJ2Jsb3NjOiBiaXQtc2h1ZmZsZSBpcyBub3Qgc3VwcG9ydGVkJyk7XG4gIGNvbnN0IGNvZGUgPSBmbGFncyA+Pj4gNTtcbiAgY29uc3QgY29kZWMgPSBCTE9TQ19DT0RFQ1NbY29kZV0gPz8gYGNvZGUgJHtjb2RlfWA7XG4gIGlmIChjb2RlYyAhPT0gJ2x6NCcgJiYgY29kZWMgIT09ICd6c3RkJyAmJiBjb2RlYyAhPT0gJ3psaWInKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBibG9zYzogaW5uZXIgY29kZWMgJHtjb2RlY30gaXMgbm90IHN1cHBvcnRlZCAobHo0LCB6c3RkIG9yIHpsaWIpYCk7XG4gIH1cbiAgY29uc3Qgc2h1ZmZsZSA9IChmbGFncyAmIDB4MSkgIT09IDAgJiYgdHlwZXNpemUgPiAxO1xuICBjb25zdCBub1NwbGl0ID0gKGZsYWdzICYgMHgxMCkgIT09IDA7XG4gIGNvbnN0IG5ibG9ja3MgPSBNYXRoLmNlaWwobmJ5dGVzIC8gYmxvY2tzaXplKTtcbiAgY29uc3Qgc2NyYXRjaCA9IHNodWZmbGUgPyBuZXcgVWludDhBcnJheShibG9ja3NpemUpIDogbnVsbDtcbiAgZm9yIChsZXQgYmxrID0gMDsgYmxrIDwgbmJsb2NrczsgYmxrKyspIHtcbiAgICBjb25zdCBic2l6ZSA9IE1hdGgubWluKGJsb2Nrc2l6ZSwgbmJ5dGVzIC0gYmxrICogYmxvY2tzaXplKTtcbiAgICBjb25zdCBsZWZ0b3ZlciA9IGJzaXplICE9PSBibG9ja3NpemU7XG4gICAgY29uc3QgbnN0cmVhbXMgPSAhbm9TcGxpdCAmJiAhbGVmdG92ZXIgPyB0eXBlc2l6ZSA6IDE7XG4gICAgY29uc3Qgc3NpemUgPSBNYXRoLmZsb29yKGJzaXplIC8gbnN0cmVhbXMpO1xuICAgIGxldCBwID0gdmlldy5nZXRVaW50MzIoMTYgKyBibGsgKiA0LCB0cnVlKTtcbiAgICBjb25zdCBibG9jayA9IHNjcmF0Y2ggPz8gb3V0O1xuICAgIGNvbnN0IGJhc2UgPSBzY3JhdGNoID8gMCA6IGJsayAqIGJsb2Nrc2l6ZTtcbiAgICBmb3IgKGxldCBzID0gMDsgcyA8IG5zdHJlYW1zOyBzKyspIHtcbiAgICAgIGNvbnN0IGNzaXplID0gdmlldy5nZXRJbnQzMihwLCB0cnVlKTtcbiAgICAgIHAgKz0gNDtcbiAgICAgIGNvbnN0IGRzdCA9IGJhc2UgKyBzICogc3NpemU7XG4gICAgICBpZiAoY3NpemUgPCAwKSB7XG4gICAgICAgIGJsb2NrLmZpbGwoLWNzaXplICYgMHhmZiwgZHN0LCBkc3QgKyBzc2l6ZSk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3Qgc3JjID0gZnJhbWUuc3ViYXJyYXkocCwgcCArIGNzaXplKTtcbiAgICAgIGlmIChjc2l6ZSA9PT0gc3NpemUpIHtcbiAgICAgICAgYmxvY2suc2V0KHNyYywgZHN0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGRlYyA9XG4gICAgICAgICAgY29kZWMgPT09ICdsejQnXG4gICAgICAgICAgICA/IGx6NEJsb2NrRGVjb21wcmVzcyhzcmMsIHNzaXplKVxuICAgICAgICAgICAgOiBjb2RlYyA9PT0gJ3pzdGQnXG4gICAgICAgICAgICAgID8genN0ZERlY29tcHJlc3Moc3JjKVxuICAgICAgICAgICAgICA6IGF3YWl0IGluZmxhdGUoc3JjLCAnZGVmbGF0ZScpO1xuICAgICAgICBpZiAoZGVjLmxlbmd0aCAhPT0gc3NpemUpIHRocm93IG5ldyBFcnJvcihgYmxvc2M6ICR7Y29kZWN9IHByb2R1Y2VkICR7ZGVjLmxlbmd0aH0gb2YgJHtzc2l6ZX0gYnl0ZXNgKTtcbiAgICAgICAgYmxvY2suc2V0KGRlYywgZHN0KTtcbiAgICAgIH1cbiAgICAgIHAgKz0gY3NpemU7XG4gICAgfVxuICAgIGlmIChzY3JhdGNoKSB1bnNodWZmbGUoc2NyYXRjaCwgYnNpemUsIHR5cGVzaXplLCBvdXQsIGJsayAqIGJsb2Nrc2l6ZSk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIERlY29kZSBvbmUgTFo0IGJsb2NrIChubyBmcmFtZSkgb2YgYHNpemVgIGJ5dGVzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGx6NEJsb2NrRGVjb21wcmVzcyhzcmM6IFVpbnQ4QXJyYXksIHNpemU6IG51bWJlcik6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBvdXQgPSBuZXcgVWludDhBcnJheShzaXplKTtcbiAgbGV0IGkgPSAwO1xuICBsZXQgbyA9IDA7XG4gIHdoaWxlIChpIDwgc3JjLmxlbmd0aCkge1xuICAgIGNvbnN0IHRva2VuID0gc3JjW2krK107XG4gICAgbGV0IGxpdGVyYWxzID0gdG9rZW4gPj4+IDQ7XG4gICAgaWYgKGxpdGVyYWxzID09PSAxNSkge1xuICAgICAgbGV0IGI6IG51bWJlcjtcbiAgICAgIGRvIHtcbiAgICAgICAgYiA9IHNyY1tpKytdO1xuICAgICAgICBsaXRlcmFscyArPSBiO1xuICAgICAgfSB3aGlsZSAoYiA9PT0gMjU1KTtcbiAgICB9XG4gICAgaWYgKG8gKyBsaXRlcmFscyA+IHNpemUgfHwgaSArIGxpdGVyYWxzID4gc3JjLmxlbmd0aCkgdGhyb3cgbmV3IEVycm9yKCdsejQ6IGxpdGVyYWxzIG92ZXJydW4nKTtcbiAgICBvdXQuc2V0KHNyYy5zdWJhcnJheShpLCBpICsgbGl0ZXJhbHMpLCBvKTtcbiAgICBpICs9IGxpdGVyYWxzO1xuICAgIG8gKz0gbGl0ZXJhbHM7XG4gICAgaWYgKGkgPj0gc3JjLmxlbmd0aCkgYnJlYWs7IC8vIHRoZSBsYXN0IHNlcXVlbmNlIGhhcyBubyBtYXRjaFxuICAgIGNvbnN0IG9mZnNldCA9IHNyY1tpXSB8IChzcmNbaSArIDFdIDw8IDgpO1xuICAgIGkgKz0gMjtcbiAgICBpZiAob2Zmc2V0ID09PSAwIHx8IG9mZnNldCA+IG8pIHRocm93IG5ldyBFcnJvcignbHo0OiBiYWQgbWF0Y2ggb2Zmc2V0Jyk7XG4gICAgbGV0IGxlbmd0aCA9ICh0b2tlbiAmIDE1KSArIDQ7XG4gICAgaWYgKCh0b2tlbiAmIDE1KSA9PT0gMTUpIHtcbiAgICAgIGxldCBiOiBudW1iZXI7XG4gICAgICBkbyB7XG4gICAgICAgIGIgPSBzcmNbaSsrXTtcbiAgICAgICAgbGVuZ3RoICs9IGI7XG4gICAgICB9IHdoaWxlIChiID09PSAyNTUpO1xuICAgIH1cbiAgICBpZiAobyArIGxlbmd0aCA+IHNpemUpIHRocm93IG5ldyBFcnJvcignbHo0OiBtYXRjaCBvdmVycnVuJyk7XG4gICAgLy8gQnl0ZSBieSBieXRlOiBhIG1hdGNoIG1heSBvdmVybGFwIHdoYXQgaXQgY29waWVzIChhIHJ1bikuXG4gICAgZm9yIChsZXQgayA9IDA7IGsgPCBsZW5ndGg7IGsrKywgbysrKSBvdXRbb10gPSBvdXRbbyAtIG9mZnNldF07XG4gIH1cbiAgaWYgKG8gIT09IHNpemUpIHRocm93IG5ldyBFcnJvcihgbHo0OiBwcm9kdWNlZCAke299IG9mICR7c2l6ZX0gYnl0ZXNgKTtcbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqXG4gKiBEZWNvZGUgYSB6YXJyIGNodW5rIHRocm91Z2ggYGNvZGVjc2AsIG91dGVybW9zdCBsYXN0IGFzIHphcnIgbGlzdHMgdGhlbSAodjI6IHRoZSBvbmVcbiAqIGBjb21wcmVzc29yYDsgdjM6IHRoZSBieXRlcy10by1ieXRlcyBjb2RlY3MgYWZ0ZXIgYGJ5dGVzYCkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWNvZGVDaHVuayhcbiAgYnl0ZXM6IFVpbnQ4QXJyYXksXG4gIGNvZGVjczogcmVhZG9ubHkgeyBpZDogc3RyaW5nOyBbazogc3RyaW5nXTogdW5rbm93biB9W10sXG4gIGluZmxhdGU6IEluZmxhdGUgPSBwbGF0Zm9ybUluZmxhdGUsXG4pOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgbGV0IGRhdGEgPSBieXRlcztcbiAgZm9yIChjb25zdCBjb2RlYyBvZiBbLi4uY29kZWNzXS5yZXZlcnNlKCkpIHtcbiAgICBzd2l0Y2ggKGNvZGVjLmlkKSB7XG4gICAgICBjYXNlICdibG9zYyc6XG4gICAgICAgIGRhdGEgPSBhd2FpdCBibG9zY0RlY29tcHJlc3MoZGF0YSwgaW5mbGF0ZSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnenN0ZCc6XG4gICAgICAgIGRhdGEgPSB6c3RkRGVjb21wcmVzcyhkYXRhKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdnemlwJzpcbiAgICAgICAgZGF0YSA9IGF3YWl0IGluZmxhdGUoZGF0YSwgJ2d6aXAnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd6bGliJzpcbiAgICAgICAgZGF0YSA9IGF3YWl0IGluZmxhdGUoZGF0YSwgJ2RlZmxhdGUnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHphcnI6IGNvZGVjICR7Y29kZWMuaWR9IGlzIG5vdCBzdXBwb3J0ZWQgKGJsb3NjLCB6c3RkLCBnemlwLCB6bGliKWApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZGF0YTtcbn1cblxuZnVuY3Rpb24gdW5zaHVmZmxlKHNyYzogVWludDhBcnJheSwgbGVuOiBudW1iZXIsIHR5cGVzaXplOiBudW1iZXIsIGRzdDogVWludDhBcnJheSwgb2ZmOiBudW1iZXIpOiB2b2lkIHtcbiAgY29uc3QgbiA9IE1hdGguZmxvb3IobGVuIC8gdHlwZXNpemUpO1xuICBmb3IgKGxldCBqID0gMDsgaiA8IHR5cGVzaXplOyBqKyspIHtcbiAgICBjb25zdCBiYXNlID0gaiAqIG47XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpKyspIGRzdFtvZmYgKyBpICogdHlwZXNpemUgKyBqXSA9IHNyY1tiYXNlICsgaV07XG4gIH1cbiAgLy8gQnl0ZXMgcGFzdCB0aGUgbGFzdCB3aG9sZSBlbGVtZW50IGFyZSBub3Qgc2h1ZmZsZWQuXG4gIGZvciAobGV0IGsgPSBuICogdHlwZXNpemU7IGsgPCBsZW47IGsrKykgZHN0W29mZiArIGtdID0gc3JjW2tdO1xufVxuXG5hc3luYyBmdW5jdGlvbiBwbGF0Zm9ybUluZmxhdGUoYnl0ZXM6IFVpbnQ4QXJyYXksIGZvcm1hdDogJ2d6aXAnIHwgJ2RlZmxhdGUnKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gIGlmICh0eXBlb2YgRGVjb21wcmVzc2lvblN0cmVhbSA9PT0gJ3VuZGVmaW5lZCcpXG4gICAgdGhyb3cgbmV3IEVycm9yKGB6YXJyOiAke2Zvcm1hdH0gY2h1bmtzIG5lZWQgRGVjb21wcmVzc2lvblN0cmVhbWApO1xuICBjb25zdCBzdHJlYW0gPSBuZXcgQmxvYihbYnl0ZXMgYXMgQmxvYlBhcnRdKS5zdHJlYW0oKS5waXBlVGhyb3VnaChuZXcgRGVjb21wcmVzc2lvblN0cmVhbShmb3JtYXQpKTtcbiAgcmV0dXJuIG5ldyBVaW50OEFycmF5KGF3YWl0IG5ldyBSZXNwb25zZShzdHJlYW0pLmFycmF5QnVmZmVyKCkpO1xufVxuIl19
|