@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.
Files changed (58) hide show
  1. package/esm2022/index.mjs +7 -1
  2. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  3. package/esm2022/lib/contracts/ports/region-io.port.mjs +1 -1
  4. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  5. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +70 -2
  6. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2 -2
  7. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +11 -1
  8. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +18 -2
  9. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +9 -1
  10. package/esm2022/lib/implementations/osd/osd-tile-loading.mjs +71 -0
  11. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +1 -1
  12. package/esm2022/lib/implementations/osd/slice-cache.mjs +35 -6
  13. package/esm2022/lib/region-editor/region-editor.component.mjs +152 -4
  14. package/esm2022/lib/region-editor/region-persistence.service.mjs +9 -1
  15. package/esm2022/lib/region-import/label-classes.mjs +149 -0
  16. package/esm2022/lib/region-import/label-volume.mjs +225 -0
  17. package/esm2022/lib/region-import/ome-zarr-labels.mjs +253 -0
  18. package/esm2022/lib/region-import/open-annotations.mjs +289 -0
  19. package/esm2022/lib/region-import/region-import.mjs +71 -0
  20. package/esm2022/lib/region-import/zarr-codecs.mjs +167 -0
  21. package/esm2022/lib/region-import/zip.mjs +157 -0
  22. package/esm2022/lib/routing-visualizer.service.mjs +112 -7
  23. package/esm2022/lib/store/region-source-scope.mjs +19 -4
  24. package/esm2022/lib/store/region-store.service.mjs +64 -14
  25. package/esm2022/lib/visualizer/region-load.mjs +16 -1
  26. package/esm2022/lib/visualizer.component.mjs +28 -2
  27. 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
  28. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-a68Hw5rw.mjs.map +1 -0
  29. 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
  30. 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
  31. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3 -1
  32. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  33. package/index.d.ts +12 -0
  34. package/lib/contracts/image.contract.d.ts +7 -0
  35. package/lib/contracts/ports/region-io.port.d.ts +24 -0
  36. package/lib/contracts/region-editor-api.contract.d.ts +19 -1
  37. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +40 -1
  38. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +5 -0
  39. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +2 -0
  40. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +2 -0
  41. package/lib/implementations/osd/osd-tile-loading.d.ts +43 -0
  42. package/lib/implementations/osd/osd-viewer-like.d.ts +14 -0
  43. package/lib/implementations/osd/slice-cache.d.ts +13 -3
  44. package/lib/region-editor/region-editor.component.d.ts +27 -0
  45. package/lib/region-editor/region-persistence.service.d.ts +5 -1
  46. package/lib/region-import/label-classes.d.ts +39 -0
  47. package/lib/region-import/label-volume.d.ts +35 -0
  48. package/lib/region-import/ome-zarr-labels.d.ts +36 -0
  49. package/lib/region-import/open-annotations.d.ts +73 -0
  50. package/lib/region-import/region-import.d.ts +46 -0
  51. package/lib/region-import/zarr-codecs.d.ts +14 -0
  52. package/lib/region-import/zip.d.ts +31 -0
  53. package/lib/routing-visualizer.service.d.ts +39 -1
  54. package/lib/store/region-source-scope.d.ts +8 -2
  55. package/lib/store/region-store.service.d.ts +15 -5
  56. package/lib/visualizer.component.d.ts +9 -0
  57. package/package.json +2 -1
  58. 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3Blbi1hbm5vdGF0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWltcG9ydC9vcGVuLWFubm90YXRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE9BQU8sRUFBRSxNQUFNLElBQUksU0FBUyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBSS9DLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFnQixpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzdGLE9BQU8sRUFBdUIsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEUsT0FBTyxFQUFFLGVBQWUsRUFBYyxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ25GLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxnQkFBZ0IsRUFBb0IsTUFBTSxpQkFBaUIsQ0FBQztBQUV6RixPQUFPLEVBQUUsVUFBVSxFQUFjLE1BQU0sT0FBTyxDQUFDO0FBRS9DLGlHQUFpRztBQUNqRyxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxJQUFJLENBQUM7QUFzQzdDOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxNQUFtQyxFQUNuQyxXQUErQixFQUFFO0lBRWpDLE1BQU0sS0FBSyxHQUFHLE1BQU0sVUFBVSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDNUQsTUFBTSxXQUFXLEdBQUcsUUFBUSxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUMsSUFBWSxFQUFFLEVBQUUsQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzlGLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDM0IsTUFBTSxJQUFJLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzlELElBQUksQ0FBQyxJQUFJO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1FBQzdGLE9BQU8sV0FBVyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDbkcsQ0FBQztJQUNELE1BQU0sSUFBSSxHQUFHLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3JDLElBQUksQ0FBQyxJQUFJO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDdkIsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzNCLE1BQU0sTUFBTSxHQUFHLE1BQU0sZUFBZSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbkcsTUFBTSxPQUFPLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2pHLE9BQU8sV0FBVyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUNoSCxDQUFDO0lBQ0QsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzNCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNsRixNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUMxQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUM5QixPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLElBQUksRUFBRSxDQUFDLFdBQVcsQ0FBQyxNQUFNLGtCQUFrQixDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQ25GLENBQUM7UUFDRixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksU0FBUyxDQUFDO1FBQzVFLE9BQU87WUFDTCxJQUFJLEVBQUUsUUFBUTtZQUNkLElBQUksRUFBRSxNQUFNO1lBQ1osTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTTtZQUMxQixPQUFPO1lBQ1AsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLGNBQWM7U0FDN0MsQ0FBQztJQUNKLENBQUM7SUFDRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDcEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7SUFDMUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckUsT0FBTztRQUNMLElBQUksRUFBRSxRQUFRO1FBQ2QsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztRQUMxQixNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU07UUFDckIsT0FBTztRQUNQLE9BQU8sRUFBRSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxTQUFTLENBQUMsQ0FBQyxDQUFDLFdBQVc7S0FDckUsQ0FBQztBQUNKLENBQUM7QUFXRCxJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUM7QUFFZjs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxlQUFlLENBQ25DLEtBQWtDLEVBQ2xDLFdBQStCLEVBQUU7SUFFakMsTUFBTSxHQUFHLEdBQUcsTUFBTSxvQkFBb0IsQ0FBQyxLQUFLLEVBQUUsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLEdBQUcsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUNwRixJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDVCxNQUFNLElBQUksS0FBSyxDQUNiLDJGQUEyRjtZQUN6RiwrREFBK0QsQ0FDbEUsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUFJLElBQUksR0FBYSxFQUFFLENBQUM7SUFDeEIsSUFBSSxLQUFhLENBQUM7SUFDbEIsSUFBSSxNQUFjLENBQUM7SUFDbkIsSUFBSSxPQUFPLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQztJQUMxQiwrRkFBK0Y7SUFDL0YsSUFBSSxPQUFPLEdBQUcsR0FBRyxFQUFFLENBQUMsU0FBaUIsQ0FBQztJQUN0QyxJQUFJLENBQUM7UUFDSCxJQUFJLEdBQUcsQ0FBQyxNQUFNLElBQUksR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQzNCLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUM7WUFDM0IsU0FBUyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztZQUN6QixJQUFJLEdBQUcsTUFBTSxjQUFjLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNwRSxDQUFDO2FBQU0sQ0FBQztZQUNOLDBGQUEwRjtZQUMxRiw2Q0FBNkM7WUFDN0MsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzVDLE9BQU8sR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDO1lBQzNCLE9BQU8sR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDO1lBQzNCLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUM7WUFDaEMsU0FBUyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztZQUN6QixNQUFNLEdBQUcsR0FBRyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLFVBQVUsQ0FBQyxLQUFLLEdBQUcsTUFBTSxDQUFDLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN0RyxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLEdBQWUsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7WUFDakUsSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU0sRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUM5RSxDQUFDO0lBQ0gsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDNUMsT0FBTyxFQUFFLENBQUM7UUFDVixNQUFNLEdBQUcsQ0FBQztJQUNaLENBQUM7SUFDRCxNQUFNLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztJQUN2QyxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztJQUMvQixNQUFNLElBQUksR0FBZTtRQUN2QixXQUFXLEVBQUUsSUFBSTtRQUNqQixhQUFhLEVBQUUsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDO1FBQzlCLElBQUk7UUFDSixPQUFPO1FBQ1AsU0FBUyxFQUFFLEtBQUs7UUFDaEIsVUFBVSxFQUFFLElBQUk7UUFDaEIsdUZBQXVGO1FBQ3ZGLFFBQVEsRUFBRSxHQUFHLEdBQUcsQ0FBQyxJQUFJLG1CQUFtQixFQUFFLE1BQU0sR0FBRztRQUNuRCxTQUFTLEVBQUU7WUFDVDtnQkFDRSxZQUFZLEVBQUUsQ0FBQztnQkFDZixXQUFXLEVBQUUsQ0FBQztnQkFDZCxDQUFDLEVBQUUsS0FBSztnQkFDUixDQUFDLEVBQUUsTUFBTTtnQkFDVCxDQUFDLEVBQUUsR0FBRyxDQUFDLE1BQU07Z0JBQ2IsSUFBSSxFQUFFLEVBQUUsSUFBSSxJQUFJO2dCQUNoQixJQUFJLEVBQUUsRUFBRSxJQUFJLElBQUk7Z0JBQ2hCLEdBQUcsQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2FBQ3BDO1NBQ0Y7UUFDRCxLQUFLLEVBQUUsS0FBSztRQUNaLHVFQUF1RTtRQUN2RSxhQUFhLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUztRQUNwRCxZQUFZLEVBQUUsT0FBTztLQUNSLENBQUM7SUFDaEIsT0FBTztRQUNMLElBQUk7UUFDSixPQUFPLEVBQUUsR0FBRyxHQUFHLENBQUMsT0FBTyxLQUFLLEtBQUssTUFBTSxNQUFNLEVBQUU7UUFDL0MsT0FBTyxFQUFFLEdBQUcsRUFBRTtZQUNaLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM1QyxPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsV0FBVyxDQUNsQixJQUFjLEVBQ2QsSUFBWSxFQUNaLEtBQWlCLEVBQ2pCLE9BQXFCLEVBQ3JCLFdBQW9EO0lBRXBELE1BQU0sT0FBTyxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBQzFDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxXQUFXLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2pILENBQUM7SUFDRCxPQUFPO1FBQ0wsSUFBSTtRQUNKLElBQUk7UUFDSixNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsT0FBTztRQUNQLE1BQU0sRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUU7UUFDMUIsSUFBSSxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQ2pDLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNwRCxPQUFPLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxTQUFTLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsT0FBTyxLQUFLLENBQUMsS0FBSyxNQUFNLEtBQUssQ0FBQyxNQUFNLEVBQUU7S0FDckcsQ0FBQztBQUNKLENBQUM7QUFFRCx5RkFBeUY7QUFDekYsU0FBUyxNQUFNLENBQUMsT0FBcUIsRUFBRSxRQUE0QjtJQUNqRSxPQUFPLFFBQVEsQ0FBQyxhQUFhLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO0FBQ2pHLENBQUM7QUFFRCxnREFBZ0Q7QUFDaEQsU0FBUyxPQUFPLENBQUMsTUFBbUI7SUFDbEMsT0FBTztRQUNMLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSztRQUNuQixNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU07UUFDckIsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNO1FBQ3JCLEdBQUcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN0RCxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7S0FDM0MsQ0FBQztBQUNKLENBQUM7QUFFRCxtRUFBbUU7QUFDbkUsU0FBUyxRQUFRLENBQUMsS0FBaUIsRUFBRSxNQUFtQjtJQUN0RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLFdBQVcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQUM1RyxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILEtBQUssVUFBVSxjQUFjLENBQUMsS0FBaUIsRUFBRSxPQUFxQjtJQUNwRSxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztJQUN6QyxNQUFNLE9BQU8sR0FBRyxDQUFDLENBQVMsRUFBRSxFQUFFO1FBQzVCLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdEIsSUFBSSxDQUFDLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDcEIsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7WUFDckMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzFFLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxDQUFDLEdBQUcsS0FBSyxHQUFHLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMvRCxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNuQixDQUFDO1FBQ0QsT0FBTyxDQUFDLENBQUM7SUFDWCxDQUFDLENBQUM7SUFDRixNQUFNLElBQUksR0FBYSxFQUFFLENBQUM7SUFDMUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxVQUFVLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDeEQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUN0QyxNQUFNLE1BQU0sR0FBRyxNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDckMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFO1lBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDckYsTUFBTSxHQUFHLEdBQUcsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZHLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLEdBQWUsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JGLENBQUM7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILEtBQUssVUFBVSxPQUFPLENBQ3BCLE9BQTRCO0lBRTVCLHFGQUFxRjtJQUNyRixNQUFNLElBQUksR0FBRyxJQUFJLEdBQUcsRUFBd0IsQ0FBQztJQUM3QyxNQUFNLE9BQU8sR0FBRyxHQUFHLEVBQUU7UUFDbkIsS0FBSyxNQUFNLE1BQU0sSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQUUsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3JELElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNmLENBQUMsQ0FBQztJQUNGLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNYLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNYLElBQUksQ0FBQztRQUNILEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsSUFBSSxPQUFPLEVBQUUsQ0FBQztZQUNoQyxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksRUFBRSxDQUFDO1lBQzVCLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3BCLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1lBQ2xDLElBQUksTUFBTSxFQUFFLENBQUM7Z0JBQ1gsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUM3QixFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0IsQ0FBQztRQUNILENBQUM7UUFDRCxJQUFJLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7SUFDbEYsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixPQUFPLEVBQUUsQ0FBQztRQUNWLE1BQU0sR0FBRyxDQUFDO0lBQ1osQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBQ3pDLEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUNoQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUU7WUFDakIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMxQixJQUFJLENBQUMsS0FBSztnQkFBRSxPQUFPLElBQUksRUFBRSxDQUFDO1lBQzFCLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDZixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDaEMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUM7QUFDNUUsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLEtBQWEsRUFBRSxNQUFjO0lBQzlDLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLEdBQUcsd0JBQXdCLEVBQUUsQ0FBQztRQUN2RCxNQUFNLElBQUksS0FBSyxDQUNiLHdCQUF3QixLQUFLLE1BQU0sTUFBTSxzQkFBc0Isd0JBQXdCLGNBQWM7WUFDbkcsb0ZBQW9GLENBQ3ZGLENBQUM7SUFDSixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUFDLElBQVk7SUFDdkMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQW1GLENBQUM7SUFDL0csTUFBTSxRQUFRLEdBQUcsR0FBRyxDQUFDLElBQUksS0FBSyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDOUUsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUE0QixFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2pHLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUMvRCxJQUFJLElBQUksS0FBSyxDQUFDO1FBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzlCLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsSUFBSSxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQWUsQ0FBQyxDQUFDO0lBQ3ZFLEtBQUssTUFBTSxDQUFDLElBQUksUUFBUSxFQUFFLENBQUM7UUFDekIsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pCLE1BQU0sUUFBUSxHQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUM7UUFDN0QsSUFBSSxRQUFRO1lBQUUsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFDO1FBQ3BDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxHQUFHLEdBQUcsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQzFFLENBQUM7QUFFRCxTQUFTLElBQUksQ0FBQyxJQUFZO0lBQ3hCLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyx5Q0FBeUMsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUNoRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBbm5vdGF0aW9ucyBvcGVuZWQgYnkgdGhlbXNlbHZlcywgd2l0aCBubyBpbWFnZSB1bmRlciB0aGVtOiBhIGxhYmVsIHZvbHVtZSAoYC5uaWlgLCBgLm5paS5nemAsXG4gKiBgLm5ycmRgLCB3aXRoIHRoZSBvbnRvbG9neSBKU09OIGNob3NlbiB3aXRoIGl0KSwgYW4gT01FLVphcnIgc3RvcmUncyBsYWJlbCBpbWFnZSwgYSBmb2xkZXIgb2ZcbiAqIHBlci1zbGljZSBHZW9KU09OICh3aXRoIGl0cyBgcmVnaW9uc2V0Lmpzb25gKSwgb25lIEdlb0pTT04gKHotaW5kZXhlZCBieSBgZ2VvbWV0cnkucGxhbmUuemAgb3JcbiAqIG5vdCksIG9yIGEgYC56aXBgIG9mIGFueSBvZiB0aGVzZS5cbiAqXG4gKiB7QGxpbmsgb3BlbkFubm90YXRpb25zfSBidWlsZHMgdGhlIGltYWdlIHRoZXkgYXJlIHNob3duIG9uLCB3aGljaCBldmVyeSB2aWV3IHRha2VzIGFzIGl0IHRha2VzXG4gKiBhbnkgb3RoZXIgKE9wZW5TZWFkcmFnb24sIG5hcGFyaSwgUGxvdGx5OyBhIHN0YWNrIHdoZW4gdGhlcmUgYXJlIHNldmVyYWwgc2xpY2VzOyB0aGUgVm9sdW1lIGFuZFxuICogSXNvc3VyZmFjZSB2aWV3cyBhbmQgdGhlaXIgM0QgcmVnaW9uIHN1cmZhY2VzKTogYSBsYWJlbCB2b2x1bWUncyBzbGljZXMgaW4gZ3JheSBsZXZlbHMsIGl0c1xuICogcmVnaW9ucyBmaWxsZWQgb3ZlciB0aGVtIGluIHRoZWlyIGNsYXNzZXMnIGNvbG91cnMsIGVsc2UgYSBibGFuayBzdGFjayB0aGUgc2l6ZSBvZiB0aGUgcmVnaW9ucy5cbiAqIFRoZSBpbWFnZSBjYXJyaWVzIHRoZSBhbm5vdGF0aW9ucyBhcyBpdHMgb3duIHJlZ2lvbiBzb3VyY2VzLCBvbmUgcGVyIHNsaWNlXG4gKiAoe0BsaW5rIElJbWFnZUluZm8ucmVnaW9uU2xpY2VzfSksIHRyYWNlZCBvciBwYXJzZWQgdGhlIGZpcnN0IHRpbWUgYSBzbGljZSBpcyBzaG93bi5cbiAqIFRoZSBob3N0IHB1Ymxpc2hlcyBpdCBhcyBpdCBwdWJsaXNoZXMgYW55IGltYWdlLCBhbmQgZGlzcG9zZXMgaXQgd2hlbiBhbm90aGVyIHJlcGxhY2VzIGl0LlxuICpcbiAqIHtAbGluayByZWFkQW5ub3RhdGlvblNsaWNlc30gaXMgdGhlIHBhcnQgdGhlIFJlZ2lvbiBFZGl0b3IncyBpbXBvcnQgc2hhcmVzOiB0aGUgc291cmNlcywgYnkgc2xpY2UuXG4gKi9cbmltcG9ydCB7IGVuY29kZSBhcyBlbmNvZGVQbmcgfSBmcm9tICdmYXN0LXBuZyc7XG5cbmltcG9ydCB0eXBlIHsgSUltYWdlSW5mbyB9IGZyb20gJy4uL2NvbnRyYWN0cy9pbWFnZS5jb250cmFjdCc7XG5pbXBvcnQgdHlwZSB7IFJlZ2lvblNvdXJjZSB9IGZyb20gJy4uL3JlZ2lvbi1zb3VyY2UvcmVnaW9uLXNvdXJjZSc7XG5pbXBvcnQgeyBvcGVuR2VvSnNvblJlZ2lvblNvdXJjZSB9IGZyb20gJy4uL3JlZ2lvbi1zb3VyY2Uvd29ya2VyLXJlZ2lvbi1zb3VyY2UnO1xuaW1wb3J0IHsgQVRMQVNfU1RZTEUsIGxhYmVsQ2xhc3NlcywgTGFiZWxDbGFzc2VzLCBsYWJlbFNsaWNlR2VvSnNvbiB9IGZyb20gJy4vbGFiZWwtY2xhc3Nlcyc7XG5pbXBvcnQgeyBHdW56aXAsIExhYmVsVm9sdW1lLCByZWFkTGFiZWxWb2x1bWUgfSBmcm9tICcuL2xhYmVsLXZvbHVtZSc7XG5pbXBvcnQgeyBoYXNaYXJyTWV0YWRhdGEsIExhYmVsU3RhY2ssIHJlYWRPbWVaYXJyTGFiZWxzIH0gZnJvbSAnLi9vbWUtemFyci1sYWJlbHMnO1xuaW1wb3J0IHsgZm9sZGVyU2xpY2VHZW9Kc29uLCBwbGFuUmVnaW9uSW1wb3J0LCBSZWdpb25JbXBvcnRGaWxlIH0gZnJvbSAnLi9yZWdpb24taW1wb3J0JztcbmltcG9ydCB7IEluZmxhdGUgfSBmcm9tICcuL3phcnItY29kZWNzJztcbmltcG9ydCB7IGV4cGFuZFppcHMsIEluZmxhdGVSYXcgfSBmcm9tICcuL3ppcCc7XG5cbi8qKiBUaGUgbG9uZ2VzdCBzaWRlIGFuIGltYWdlIGJ1aWx0IGZvciBhbm5vdGF0aW9ucyBtYXkgaGF2ZTogT3BlblNlYWRyYWdvbidzIG5vbi10aWxlZCBsaW1pdC4gKi9cbmV4cG9ydCBjb25zdCBBTk5PVEFUSU9OX0lNQUdFX01BWF9ESU0gPSA4MTkyO1xuXG4vKiogT3BlbnMgYSBzbGljZSdzIHJlZ2lvbiBzb3VyY2UgKGFnYWluLCBhZnRlciB0aGUgc3RvcmUgY2xvc2VkIGl0KS4gKi9cbnR5cGUgT3BlbmVyID0gKCkgPT4gUHJvbWlzZTxSZWdpb25Tb3VyY2U+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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLWltcG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWltcG9ydC9yZWdpb24taW1wb3J0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBWW5ELG1HQUFtRztBQUNuRyxNQUFNLFVBQVUsVUFBVSxDQUFDLElBQXNCLEVBQUUsT0FBUSxJQUFhLENBQUMsSUFBSSxJQUFJLEVBQUU7SUFDakYsTUFBTSxPQUFPLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztJQUNsQyxPQUFPO1FBQ0wsSUFBSTtRQUNKLElBQUksRUFBRSxLQUFLLElBQUksRUFBRSxDQUNmLE9BQU8sSUFBSSxLQUFLLFFBQVE7WUFDdEIsQ0FBQyxDQUFDLElBQUk7WUFDTixDQUFDLENBQUMsSUFBSSxZQUFZLElBQUk7Z0JBQ3BCLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO2dCQUNiLENBQUMsQ0FBQyxJQUFJLFdBQVcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLFlBQVksVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFGLEtBQUssRUFBRSxLQUFLLElBQUksRUFBRSxDQUNoQixPQUFPLElBQUksS0FBSyxRQUFRO1lBQ3RCLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztZQUN0QixDQUFDLENBQUMsSUFBSSxZQUFZLElBQUk7Z0JBQ3BCLENBQUMsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxNQUFNLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDMUMsQ0FBQyxDQUFDLElBQUksWUFBWSxVQUFVO29CQUMxQixDQUFDLENBQUMsSUFBSTtvQkFDTixDQUFDLENBQUMsSUFBSSxVQUFVLENBQUMsSUFBSSxDQUFDO0tBQy9CLENBQUM7QUFDSixDQUFDO0FBV0QsTUFBTSxJQUFJLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksSUFBSSxDQUFDO0FBQ2pFLE1BQU0sV0FBVyxHQUFHLENBQUMsQ0FBbUIsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxXQUFXLEVBQUUsS0FBSyxnQkFBZ0IsQ0FBQztBQUM3RixNQUFNLFNBQVMsR0FBRyxDQUFDLENBQW1CLEVBQUUsRUFBRSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ3RFLE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBbUIsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7QUFFaEU7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsS0FBa0M7SUFDakUsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDNUQsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNYLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxNQUFNLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0QsTUFBTSxRQUFRLEdBQ1osS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUM7WUFDdkIsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsMkJBQTJCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztZQUNqRSxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ1IsSUFBSSxDQUFDO1FBQ1AsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxDQUFDO0lBQzlDLENBQUM7SUFDRCxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLElBQUksQ0FBQztJQUNsRCxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNuRCxNQUFNLFdBQVcsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25HLElBQUksV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ3RFLE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMzRixPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLENBQUM7SUFDL0MsQ0FBQztJQUNELE9BQU8sV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztBQUNwRixDQUFDO0FBRUQsdUVBQXVFO0FBQ3ZFLE1BQU0sVUFBVSxjQUFjLENBQUMsQ0FBUyxFQUFFLENBQVM7SUFDakQsT0FBTyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO0FBQy9FLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUN0QyxJQUFzQixFQUN0QixTQUErRDtJQUUvRCxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMvQixJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUMsY0FBYyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQy9FLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUE0QixDQUFDO0lBQ3hELElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLG1CQUFtQjtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3JELElBQUksU0FBUyxDQUFDLGNBQWMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQztRQUFFLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxjQUFjLENBQUM7SUFDekcsSUFBSSxTQUFTLENBQUMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQztRQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDO0lBQ3JFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUM3QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXNMYWJlbFZvbHVtZU5hbWUgfSBmcm9tICcuL2xhYmVsLXZvbHVtZSc7XG5cbi8qKiBBIGZpbGUgdG8gaW1wb3J0IHJlZ2lvbnMgZnJvbTogb25lIHRoZSB1c2VyIGNob3NlLCBvciBvbmUgdGhlIGhvc3QncyBzZXJ2ZXIgc2VudC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVnaW9uSW1wb3J0RmlsZSB7XG4gIG5hbWU6IHN0cmluZztcbiAgdGV4dCgpOiBQcm9taXNlPHN0cmluZz47XG4gIGJ5dGVzKCk6IFByb21pc2U8VWludDhBcnJheT47XG59XG5cbi8qKiBBIGZpbGUncyBjb250ZW50cyBhcyB0aGUgaG9zdCBtYXkgaGFuZCB0aGVtIG92ZXIgKHNlZSBgU2VydmVyUmVnaW9uUGlja2ApLiAqL1xuZXhwb3J0IHR5cGUgUmVnaW9uSW1wb3J0RGF0YSA9IEJsb2IgfCBBcnJheUJ1ZmZlciB8IFVpbnQ4QXJyYXkgfCBzdHJpbmc7XG5cbi8qKiBgZGF0YWAsIG5hbWVkIGBuYW1lYCwgYXMgYW4gaW1wb3J0IGZpbGUuIEEgYEZpbGVgJ3Mgb3duIG5hbWUgaXMgdXNlZCB3aGVuIGBuYW1lYCBpcyBvbWl0dGVkLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGltcG9ydEZpbGUoZGF0YTogUmVnaW9uSW1wb3J0RGF0YSwgbmFtZSA9IChkYXRhIGFzIEZpbGUpLm5hbWUgPz8gJycpOiBSZWdpb25JbXBvcnRGaWxlIHtcbiAgY29uc3QgZW5jb2RlciA9IG5ldyBUZXh0RW5jb2RlcigpO1xuICByZXR1cm4ge1xuICAgIG5hbWUsXG4gICAgdGV4dDogYXN5bmMgKCkgPT5cbiAgICAgIHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJ1xuICAgICAgICA/IGRhdGFcbiAgICAgICAgOiBkYXRhIGluc3RhbmNlb2YgQmxvYlxuICAgICAgICAgID8gZGF0YS50ZXh0KClcbiAgICAgICAgICA6IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShkYXRhIGluc3RhbmNlb2YgVWludDhBcnJheSA/IGRhdGEgOiBuZXcgVWludDhBcnJheShkYXRhKSksXG4gICAgYnl0ZXM6IGFzeW5jICgpID0+XG4gICAgICB0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZydcbiAgICAgICAgPyBlbmNvZGVyLmVuY29kZShkYXRhKVxuICAgICAgICA6IGRhdGEgaW5zdGFuY2VvZiBCbG9iXG4gICAgICAgICAgPyBuZXcgVWludDhBcnJheShhd2FpdCBkYXRhLmFycmF5QnVmZmVyKCkpXG4gICAgICAgICAgOiBkYXRhIGluc3RhbmNlb2YgVWludDhBcnJheVxuICAgICAgICAgICAgPyBkYXRhXG4gICAgICAgICAgICA6IG5ldyBVaW50OEFycmF5KGRhdGEpLFxuICB9O1xufVxuXG4vKiogV2hhdCBhIHNldCBvZiBjaG9zZW4gZmlsZXMgaW1wb3J0cyBhcy4gKi9cbmV4cG9ydCB0eXBlIFJlZ2lvbkltcG9ydFBsYW4gPVxuICAvKiogQSBsYWJlbCB2b2x1bWUsIGl0cyBjbGFzc2VzIG5hbWVkIGJ5IGFuIG9udG9sb2d5IChvciBhIHJlZ2lvbiBzZXQgZGVzY3JpcHRpb24pIGJlc2lkZSBpdC4gKi9cbiAgfCB7IGtpbmQ6ICd2b2x1bWUnOyB2b2x1bWU6IFJlZ2lvbkltcG9ydEZpbGU7IG9udG9sb2d5OiBSZWdpb25JbXBvcnRGaWxlIHwgbnVsbCB9XG4gIC8qKiBBIGZvbGRlciBvZiBwZXItc2xpY2UgcmVnaW9uIGZpbGVzLCBpbiBzbGljZSBvcmRlciwgd2l0aCB0aGUgc2V0J3MgYHJlZ2lvbnNldC5qc29uYC4gKi9cbiAgfCB7IGtpbmQ6ICdmb2xkZXInOyBzbGljZXM6IFJlZ2lvbkltcG9ydEZpbGVbXTsgcmVnaW9uU2V0OiBSZWdpb25JbXBvcnRGaWxlIHwgbnVsbCB9XG4gIC8qKiBPbmUgcmVnaW9uIGZpbGUuICovXG4gIHwgeyBraW5kOiAnc2luZ2xlJzsgZmlsZTogUmVnaW9uSW1wb3J0RmlsZSB9O1xuXG5jb25zdCBsZWFmID0gKG5hbWU6IHN0cmluZykgPT4gbmFtZS5zcGxpdCgvW1xcXFwvXS8pLnBvcCgpID8/IG5hbWU7XG5jb25zdCBpc1JlZ2lvblNldCA9IChmOiBSZWdpb25JbXBvcnRGaWxlKSA9PiBsZWFmKGYubmFtZSkudG9Mb3dlckNhc2UoKSA9PT0gJ3JlZ2lvbnNldC5qc29uJztcbmNvbnN0IGlzR2VvSnNvbiA9IChmOiBSZWdpb25JbXBvcnRGaWxlKSA9PiAvXFwuZ2VvanNvbiQvaS50ZXN0KGYubmFtZSk7XG5jb25zdCBpc0pzb24gPSAoZjogUmVnaW9uSW1wb3J0RmlsZSkgPT4gL1xcLmpzb24kL2kudGVzdChmLm5hbWUpO1xuXG4vKipcbiAqIFdoYXQgYGZpbGVzYCBpbXBvcnQgYXM6IGEgbGFiZWwgdm9sdW1lIChgLm5paWAsIGAubmlpLmd6YCwgYC5ucnJkYCkgd2l0aCB0aGUgb250b2xvZ3kgSlNPTiBjaG9zZW5cbiAqIHdpdGggaXQgKGEgYHJlZ2lvbnNldC5qc29uYCwgZWxzZSBhbiBBbGxlbiBgc3RydWN0dXJlX2dyYXBoKi5qc29uYCwgZWxzZSBhbnkgYC5qc29uYCk7IHNldmVyYWxcbiAqIHJlZ2lvbiBmaWxlcyAoYSBmb2xkZXIgb2YgcGVyLXNsaWNlIGAuZ2VvanNvbmAsIGluIG5hdHVyYWwgbmFtZSBvcmRlciwgaXRzIGByZWdpb25zZXQuanNvbmBcbiAqIGFwYXJ0KTsgb3Igb25lIHJlZ2lvbiBmaWxlIChgLmdlb2pzb25gIG9yIGAuanNvbmApLiBOdWxsIHdoZW4gbm9uZSBvZiB0aGVtIGlzIG9uZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBsYW5SZWdpb25JbXBvcnQoZmlsZXM6IHJlYWRvbmx5IFJlZ2lvbkltcG9ydEZpbGVbXSk6IFJlZ2lvbkltcG9ydFBsYW4gfCBudWxsIHtcbiAgY29uc3Qgdm9sdW1lID0gZmlsZXMuZmluZCgoZikgPT4gaXNMYWJlbFZvbHVtZU5hbWUoZi5uYW1lKSk7XG4gIGlmICh2b2x1bWUpIHtcbiAgICBjb25zdCBqc29ucyA9IGZpbGVzLmZpbHRlcigoZikgPT4gZiAhPT0gdm9sdW1lICYmIGlzSnNvbihmKSk7XG4gICAgY29uc3Qgb250b2xvZ3kgPVxuICAgICAganNvbnMuZmluZChpc1JlZ2lvblNldCkgPz9cbiAgICAgIGpzb25zLmZpbmQoKGYpID0+IC9zdHJ1Y3R1cmVfZ3JhcGguKlxcLmpzb24kL2kudGVzdChsZWFmKGYubmFtZSkpKSA/P1xuICAgICAganNvbnNbMF0gPz9cbiAgICAgIG51bGw7XG4gICAgcmV0dXJuIHsga2luZDogJ3ZvbHVtZScsIHZvbHVtZSwgb250b2xvZ3kgfTtcbiAgfVxuICBjb25zdCByZWdpb25TZXQgPSBmaWxlcy5maW5kKGlzUmVnaW9uU2V0KSA/PyBudWxsO1xuICBjb25zdCBnZW9qc29ucyA9IGZpbGVzLmZpbHRlcigoZikgPT4gaXNHZW9Kc29uKGYpKTtcbiAgY29uc3QgcmVnaW9uRmlsZXMgPSBnZW9qc29ucy5sZW5ndGggPyBnZW9qc29ucyA6IGZpbGVzLmZpbHRlcigoZikgPT4gaXNKc29uKGYpICYmICFpc1JlZ2lvblNldChmKSk7XG4gIGlmIChyZWdpb25GaWxlcy5sZW5ndGggPiAxIHx8IChyZWdpb25GaWxlcy5sZW5ndGggPT09IDEgJiYgcmVnaW9uU2V0KSkge1xuICAgIGNvbnN0IHNsaWNlcyA9IFsuLi5yZWdpb25GaWxlc10uc29ydCgoYSwgYikgPT4gbmF0dXJhbENvbXBhcmUobGVhZihhLm5hbWUpLCBsZWFmKGIubmFtZSkpKTtcbiAgICByZXR1cm4geyBraW5kOiAnZm9sZGVyJywgc2xpY2VzLCByZWdpb25TZXQgfTtcbiAgfVxuICByZXR1cm4gcmVnaW9uRmlsZXMubGVuZ3RoID09PSAxID8geyBraW5kOiAnc2luZ2xlJywgZmlsZTogcmVnaW9uRmlsZXNbMF0gfSA6IG51bGw7XG59XG5cbi8qKiBcInNsaWNlXzJcIiBiZWZvcmUgXCJzbGljZV8xMFwiOiBydW5zIG9mIGRpZ2l0cyBjb21wYXJlZCBhcyBudW1iZXJzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5hdHVyYWxDb21wYXJlKGE6IHN0cmluZywgYjogc3RyaW5nKTogbnVtYmVyIHtcbiAgcmV0dXJuIGEubG9jYWxlQ29tcGFyZShiLCB1bmRlZmluZWQsIHsgbnVtZXJpYzogdHJ1ZSwgc2Vuc2l0aXZpdHk6ICdiYXNlJyB9KTtcbn1cblxuLyoqXG4gKiBBIGZvbGRlciBzbGljZSdzIEdlb0pTT04gd2l0aCB0aGUgc2V0J3MgY2xhc3MgdHJlZSBhbmQgc3R5bGUgKGl0cyBgcmVnaW9uc2V0Lmpzb25gKSBhcyB0aGVcbiAqIGNvbGxlY3Rpb24ncyBvd24gbWVtYmVycywgdW5sZXNzIHRoZSBmaWxlIGhhcyBpdHMgb3duOiB3aGF0IGEgc2VydmVkIGZvbGRlcidzIHNsaWNlIGNhcnJpZXMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmb2xkZXJTbGljZUdlb0pzb24oXG4gIGZpbGU6IFJlZ2lvbkltcG9ydEZpbGUsXG4gIHJlZ2lvblNldDogeyBjbGFzc0hpZXJhcmNoeT86IHVua25vd247IHN0eWxlPzogdW5rbm93biB9IHwgbnVsbCxcbik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHRleHQgPSBhd2FpdCBmaWxlLnRleHQoKTtcbiAgaWYgKCFyZWdpb25TZXQgfHwgKCFyZWdpb25TZXQuY2xhc3NIaWVyYXJjaHkgJiYgIXJlZ2lvblNldC5zdHlsZSkpIHJldHVybiB0ZXh0O1xuICBjb25zdCBkb2MgPSBKU09OLnBhcnNlKHRleHQpIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBpZiAoZG9jWyd0eXBlJ10gIT09ICdGZWF0dXJlQ29sbGVjdGlvbicpIHJldHVybiB0ZXh0O1xuICBpZiAocmVnaW9uU2V0LmNsYXNzSGllcmFyY2h5ICYmICFkb2NbJ2NsYXNzSGllcmFyY2h5J10pIGRvY1snY2xhc3NIaWVyYXJjaHknXSA9IHJlZ2lvblNldC5jbGFzc0hpZXJhcmNoeTtcbiAgaWYgKHJlZ2lvblNldC5zdHlsZSAmJiAhZG9jWydzdHlsZSddKSBkb2NbJ3N0eWxlJ10gPSByZWdpb25TZXQuc3R5bGU7XG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShkb2MpO1xufVxuIl19