@jax-data-science/sci-image-visualizer 0.3.3 → 0.4.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 (91) hide show
  1. package/README.md +208 -4
  2. package/esm2022/index.mjs +20 -1
  3. package/esm2022/lib/contracts/display-types.mjs +20 -2
  4. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  5. package/esm2022/lib/contracts/plot-type.mjs +36 -1
  6. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +3 -0
  7. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +45 -0
  8. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  9. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +10 -19
  10. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +71 -7
  11. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +1 -1
  12. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +96 -0
  13. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +1934 -55
  14. package/esm2022/lib/implementations/napari-js/napari-zoom.mjs +18 -0
  15. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +5 -3
  16. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +3 -4
  17. package/esm2022/lib/implementations/osd/osd-zoom.mjs +20 -0
  18. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +555 -0
  19. package/esm2022/lib/implementations/plotly/plotly.service.mjs +13 -7
  20. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +304 -0
  21. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +179 -0
  22. package/esm2022/lib/routing-visualizer.service.mjs +223 -12
  23. package/esm2022/lib/spatial/embedding-compute.mjs +142 -0
  24. package/esm2022/lib/spatial/gene-search.mjs +77 -0
  25. package/esm2022/lib/spatial/spatial-density.mjs +224 -0
  26. package/esm2022/lib/spatial/spatial-encoding.mjs +232 -0
  27. package/esm2022/lib/spatial/spatial-expression.mjs +257 -0
  28. package/esm2022/lib/spatial/spatial-framing.mjs +60 -0
  29. package/esm2022/lib/spatial/spatial-heatmap.mjs +185 -0
  30. package/esm2022/lib/spatial/spatial-hover.mjs +79 -0
  31. package/esm2022/lib/spatial/spatial-sections.mjs +96 -0
  32. package/esm2022/lib/spatial/spatial-selection.mjs +264 -0
  33. package/esm2022/lib/spatial/spatial-volume-image.mjs +163 -0
  34. package/esm2022/lib/spatial/tsne-worker.mjs +10 -0
  35. package/esm2022/lib/spatial/world-grid.mjs +77 -0
  36. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +1278 -0
  37. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +621 -0
  38. package/esm2022/lib/store/spatial-selection.service.mjs +47 -0
  39. package/esm2022/lib/store/visualizer-store.service.mjs +23 -1
  40. package/esm2022/lib/toolbar/toolbar.component.mjs +30 -7
  41. package/esm2022/lib/visualization.module.mjs +23 -5
  42. package/esm2022/lib/visualizer.component.mjs +283 -22
  43. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs} +6 -4
  44. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map} +1 -1
  45. package/fesm2022/jax-data-science-sci-image-visualizer-tsne-worker-B_nXDGf0.mjs +12 -0
  46. package/fesm2022/jax-data-science-sci-image-visualizer-tsne-worker-B_nXDGf0.mjs.map +1 -0
  47. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +15769 -8316
  48. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  49. package/fesm2022/tsne.worker.js +19091 -0
  50. package/index.d.ts +15 -0
  51. package/lib/contracts/display-types.d.ts +131 -0
  52. package/lib/contracts/image.contract.d.ts +7 -0
  53. package/lib/contracts/plot-type.d.ts +42 -2
  54. package/lib/contracts/ports/spatial-data.port.d.ts +90 -0
  55. package/lib/contracts/spatial-dataset.contract.d.ts +281 -0
  56. package/lib/contracts/visualizer.contract.d.ts +99 -1
  57. package/lib/implementations/napari-js/napari-axes-labels.d.ts +9 -7
  58. package/lib/implementations/napari-js/napari-region-overlay.d.ts +38 -4
  59. package/lib/implementations/napari-js/napari-scale-bar.d.ts +7 -3
  60. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +32 -0
  61. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +497 -16
  62. package/lib/implementations/napari-js/napari-zoom.d.ts +15 -0
  63. package/lib/implementations/osd/osd-zoom.d.ts +19 -0
  64. package/lib/implementations/plotly/omics-trace-builders.d.ts +193 -0
  65. package/lib/implementations/plotly/plotly.service.d.ts +9 -0
  66. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +123 -0
  67. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +115 -0
  68. package/lib/routing-visualizer.service.d.ts +45 -6
  69. package/lib/spatial/embedding-compute.d.ts +73 -0
  70. package/lib/spatial/gene-search.d.ts +48 -0
  71. package/lib/spatial/spatial-density.d.ts +73 -0
  72. package/lib/spatial/spatial-encoding.d.ts +155 -0
  73. package/lib/spatial/spatial-expression.d.ts +144 -0
  74. package/lib/spatial/spatial-framing.d.ts +37 -0
  75. package/lib/spatial/spatial-heatmap.d.ts +111 -0
  76. package/lib/spatial/spatial-hover.d.ts +49 -0
  77. package/lib/spatial/spatial-sections.d.ts +59 -0
  78. package/lib/spatial/spatial-selection.d.ts +113 -0
  79. package/lib/spatial/spatial-volume-image.d.ts +67 -0
  80. package/lib/spatial/tsne-worker.d.ts +7 -0
  81. package/lib/spatial/world-grid.d.ts +58 -0
  82. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +439 -0
  83. package/lib/spatial-controls/spatial-controls.component.d.ts +257 -0
  84. package/lib/store/spatial-selection.service.d.ts +27 -0
  85. package/lib/store/visualizer-store.service.d.ts +13 -0
  86. package/lib/toolbar/toolbar.component.d.ts +19 -3
  87. package/lib/visualization.module.d.ts +28 -24
  88. package/lib/visualizer.component.d.ts +73 -2
  89. package/package.json +6 -2
  90. package/src/lib/assets/spatial-omics-3d.svg +31 -0
  91. package/src/lib/assets/spatial-omics.svg +27 -0
@@ -0,0 +1,304 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { Injectable } from '@angular/core';
3
+ import { BehaviorSubject, firstValueFrom } from 'rxjs';
4
+ import { timeout } from 'rxjs/operators';
5
+ import { findColumnMeta, } from '../../contracts/spatial-dataset.contract';
6
+ import { assertManifestVersion, datasetFromManifest, decodeColumn, decodeCoords, decodeEmbedding, decodeFeatureVector, decodePolygons, decodeRadius, } from './spatial-wire';
7
+ import * as i0 from "@angular/core";
8
+ import * as i1 from "@angular/common/http";
9
+ /**
10
+ * Reference {@link SpatialDataPort} adapter for the wire format the bundled
11
+ * example server speaks (see `spatial-wire.ts` and
12
+ * `examples/tile-server/lib/spatial.mjs`).
13
+ *
14
+ * OPTIONAL AND UNBOUND BY DEFAULT — this service is `@Injectable()` without
15
+ * `providedIn`, so nothing gets it unless a host explicitly provides it:
16
+ *
17
+ * ```ts
18
+ * providers: [
19
+ * SpatialDataHttpService,
20
+ * { provide: SPATIAL_DATA_PORT, useExisting: SpatialDataHttpService },
21
+ * ]
22
+ * ```
23
+ *
24
+ * That mirrors `CellposeSegmenterService`: a concrete implementation the
25
+ * library ships for convenience, not a default the port inversion is quietly
26
+ * giving up on. A host with its own backend implements `SpatialDataPort`
27
+ * directly and never touches this class.
28
+ *
29
+ * Requests go through Angular's `HttpClient` (not `fetch`) so the host's
30
+ * interceptors — auth headers above all — apply, matching `tile-client.ts`.
31
+ */
32
+ /**
33
+ * A dataset selection that a newer selection (or a `clear`) overtook.
34
+ *
35
+ * Thrown rather than resolved so a caller cannot mistake it for "this dataset is
36
+ * now loaded": nothing was published, on purpose.
37
+ */
38
+ export class SupersededError extends Error {
39
+ constructor(id) {
40
+ super(`[spatial] selection of "${id}" was superseded by a newer one`);
41
+ this.name = 'SupersededError';
42
+ }
43
+ }
44
+ export class SpatialDataHttpService {
45
+ static { this.CACHE_LIMIT = 32; }
46
+ constructor(http) {
47
+ this.http = http;
48
+ /** Server root, normalised to end with exactly one `/`. */
49
+ this.baseUrl = '';
50
+ /** Per-request ceiling. Vectors are small; a hung request should not wedge
51
+ * the picker. */
52
+ this.timeoutMs = 30_000;
53
+ this.dataset$ = new BehaviorSubject(null);
54
+ this.manifest = null;
55
+ /** Bumped by every `selectDataset` and every `clear`, so a selection that
56
+ * finishes after a newer intent can tell and drop what it fetched. */
57
+ this.selectToken = 0;
58
+ /**
59
+ * Loaded vectors, keyed `column:<name>` / `feature:<name>`. Bounded LRU:
60
+ * colouring by cluster → by a gene → back by cluster must not refetch, but an
61
+ * afternoon of browsing genes must not grow without limit either (one vector
62
+ * is `4·N` bytes — 2 MB at 500k cells).
63
+ */
64
+ this.cache = new Map();
65
+ /** In-flight requests, so double-clicking a gene issues one fetch. */
66
+ this.inFlight = new Map();
67
+ this.volumePromise = null;
68
+ this.polygonsPromise = null;
69
+ }
70
+ // ── configuration ───────────────────────────────────────────────────────
71
+ /** Point the adapter at a server. Clears any loaded dataset. */
72
+ configure(options) {
73
+ const raw = options.baseUrl ?? '';
74
+ this.baseUrl = raw.endsWith('/') ? raw : `${raw}/`;
75
+ if (options.timeoutMs !== undefined)
76
+ this.timeoutMs = options.timeoutMs;
77
+ this.clear();
78
+ }
79
+ /** Datasets this server offers, for a host-side picker. */
80
+ listDatasets() {
81
+ return this.getJson('spatial/datasets')
82
+ .then((r) => r.datasets ?? []);
83
+ }
84
+ /**
85
+ * One dataset's manifest, WITHOUT selecting it. Lets a host inspect what a
86
+ * server offers — column and feature metadata, and which image a dataset
87
+ * registers onto — while building a picker, rather than having to load each
88
+ * dataset to find out.
89
+ */
90
+ readManifest(id) {
91
+ return this.getJson(`spatial/${encodeURIComponent(id)}/manifest`)
92
+ .then((manifest) => {
93
+ assertManifestVersion(manifest);
94
+ return manifest;
95
+ });
96
+ }
97
+ /**
98
+ * Load a dataset and publish it on {@link getDataset$}. Fetches the manifest,
99
+ * then the vectors that are always needed (coordinates, and ids/radius when
100
+ * the manifest says they exist) — nothing else.
101
+ */
102
+ async selectDataset(id) {
103
+ this.clear();
104
+ // Selections are SEQUENCED: this is four awaits deep, so a slower earlier
105
+ // call would otherwise assign `this.manifest` or publish its dataset after a
106
+ // later one — leaving the manifest and the observations from two different
107
+ // datasets, which is worse than either being late.
108
+ const mine = ++this.selectToken;
109
+ const superseded = () => mine !== this.selectToken;
110
+ const path = `spatial/${encodeURIComponent(id)}`;
111
+ const manifest = await this.getJson(`${path}/manifest`);
112
+ assertManifestVersion(manifest);
113
+ if (superseded())
114
+ throw new SupersededError(id);
115
+ this.manifest = manifest;
116
+ const coordsBuf = await this.getBinary(`${path}/coords`);
117
+ if (superseded())
118
+ throw new SupersededError(id);
119
+ const coords = decodeCoords(coordsBuf, manifest.count, !!manifest.hasZ);
120
+ const ids = manifest.hasIds
121
+ ? (await this.getJson(`${path}/ids`)).ids
122
+ : undefined;
123
+ const radius = manifest.radius?.mode === 'per-observation'
124
+ ? decodeRadius(await this.getBinary(`${path}/radius`), manifest.count)
125
+ : undefined;
126
+ if (superseded())
127
+ throw new SupersededError(id);
128
+ const dataset = datasetFromManifest(manifest, coords, { ids, radius });
129
+ this.dataset$.next(dataset);
130
+ return dataset;
131
+ }
132
+ /** Drop the loaded dataset and every cached vector. */
133
+ clear() {
134
+ // A clear is itself the newest intent, so it supersedes any selection still
135
+ // in flight rather than letting one land afterwards.
136
+ this.selectToken++;
137
+ this.manifest = null;
138
+ this.cache.clear();
139
+ this.inFlight.clear();
140
+ this.polygonsPromise = null;
141
+ this.volumePromise = null;
142
+ if (this.dataset$.value !== null)
143
+ this.dataset$.next(null);
144
+ }
145
+ // ── SpatialDataPort ─────────────────────────────────────────────────────
146
+ getDataset$() {
147
+ return this.dataset$.asObservable();
148
+ }
149
+ getColumn(name) {
150
+ const manifest = this.requireManifest();
151
+ const dataset = this.dataset$.value;
152
+ const meta = findColumnMeta(dataset, name);
153
+ if (!meta) {
154
+ // Reject rather than resolve empty: a typo must surface as an error, not
155
+ // as a plot that silently renders every point as "no data".
156
+ return Promise.reject(new Error(`[spatial] unknown column "${name}". Available: ${dataset.columns.map((c) => c.name).join(', ')}`));
157
+ }
158
+ return this.fetchCached(`column:${name}`, () => this.getBinary(`spatial/${encodeURIComponent(manifest.id)}/column/${encodeURIComponent(name)}`)
159
+ .then((buf) => decodeColumn(buf, meta, manifest.count)));
160
+ }
161
+ getEmbedding(name) {
162
+ const manifest = this.requireManifest();
163
+ const meta = manifest.embeddings?.find((e) => e.name === name);
164
+ if (!meta) {
165
+ return Promise.reject(new Error(`[spatial] unknown embedding "${name}"`));
166
+ }
167
+ return this.fetchCached(`embedding:${name}`, () => this.getBinary(`spatial/${encodeURIComponent(manifest.id)}/embedding/${encodeURIComponent(name)}`).then((buf) => decodeEmbedding(buf, meta, manifest.count)));
168
+ }
169
+ getFeatureVector(name) {
170
+ const manifest = this.requireManifest();
171
+ const names = manifest.features?.names;
172
+ if (names && !names.includes(name)) {
173
+ return Promise.reject(new Error(`[spatial] unknown feature "${name}"`));
174
+ }
175
+ return this.fetchCached(`feature:${name}`, () => this.getBinary(`spatial/${encodeURIComponent(manifest.id)}/feature/${encodeURIComponent(name)}`)
176
+ .then((buf) => decodeFeatureVector(buf, manifest.count)));
177
+ }
178
+ async searchFeatures(query, limit = 50) {
179
+ const manifest = this.requireManifest();
180
+ // A dataset that inlined its names (targeted panel) is filtered locally —
181
+ // no round-trip for a keystroke.
182
+ const names = manifest.features?.names;
183
+ if (names) {
184
+ const q = query.toLowerCase();
185
+ return names.filter((n) => n.toLowerCase().includes(q)).slice(0, limit);
186
+ }
187
+ const url = `spatial/${encodeURIComponent(manifest.id)}/features`
188
+ + `?q=${encodeURIComponent(query)}&limit=${limit}`;
189
+ return (await this.getJson(url)).names ?? [];
190
+ }
191
+ getPolygons() {
192
+ const manifest = this.requireManifest();
193
+ if (!manifest.polygons) {
194
+ return Promise.reject(new Error('[spatial] this dataset has no polygon geometry'));
195
+ }
196
+ // Geometry is one large blob rather than a per-name vector, so it gets its
197
+ // own single-flight slot instead of a cache entry.
198
+ this.polygonsPromise ??= this
199
+ .getBinary(`spatial/${encodeURIComponent(manifest.id)}/polygons`)
200
+ .then(decodePolygons)
201
+ .catch((err) => { this.polygonsPromise = null; throw err; });
202
+ return this.polygonsPromise;
203
+ }
204
+ /**
205
+ * The reference volume's voxels, single-flighted like the polygons.
206
+ *
207
+ * Validated against the manifest's declared dimensions before it is handed
208
+ * back: a short or long buffer read as a 3D texture does not fail, it shears
209
+ * the anatomy into diagonal streaks, and that is far harder to recognise as a
210
+ * transport problem than an error is.
211
+ */
212
+ getVolume() {
213
+ const manifest = this.requireManifest();
214
+ const meta = manifest.volume;
215
+ if (!meta) {
216
+ return Promise.reject(new Error('[spatial] this dataset has no reference volume'));
217
+ }
218
+ this.volumePromise ??= this
219
+ .getBinary(`spatial/${encodeURIComponent(manifest.id)}/volume`)
220
+ .then((buf) => {
221
+ const want = meta.width * meta.height * meta.depth;
222
+ if (buf.byteLength !== want) {
223
+ throw new Error(`[spatial] volume is ${buf.byteLength} bytes, expected ${want} `
224
+ + `(${meta.width}x${meta.height}x${meta.depth})`);
225
+ }
226
+ return new Uint8Array(buf);
227
+ })
228
+ .catch((err) => { this.volumePromise = null; throw err; });
229
+ return this.volumePromise;
230
+ }
231
+ // ── internals ───────────────────────────────────────────────────────────
232
+ requireManifest() {
233
+ if (!this.manifest || !this.dataset$.value) {
234
+ throw new Error('[spatial] no dataset selected — call selectDataset() first');
235
+ }
236
+ return this.manifest;
237
+ }
238
+ /**
239
+ * Cache + single-flight around a vector fetch.
240
+ *
241
+ * Keys are LOGICAL — `feature:GAPDH`, not `<dataset>/feature:GAPDH` — because `clear()`
242
+ * empties the maps on every switch, so two datasets never hold entries at once. What
243
+ * that does not cover is a request still in the air when the switch happens: `clear()`
244
+ * cannot cancel an HTTP call, so a vector fetched for dataset A can resolve after B has
245
+ * been selected and write itself into B's cache under a key B would read. Both datasets
246
+ * having a gene of that name is the common case, not the unlucky one, and the result is
247
+ * a plot of A's expression over B's cells — which looks like data, not like a fault.
248
+ *
249
+ * So the generation is checked after the await, and the in-flight slot is cleared only
250
+ * when the promise still sitting in it is this one: a late arrival must not evict the
251
+ * entry a newer request for the same key is already sharing.
252
+ */
253
+ fetchCached(key, load) {
254
+ const hit = this.cache.get(key);
255
+ if (hit) {
256
+ // Re-insert to mark most-recently-used (Map preserves insertion order).
257
+ this.cache.delete(key);
258
+ this.cache.set(key, hit);
259
+ return Promise.resolve(hit);
260
+ }
261
+ const pending = this.inFlight.get(key);
262
+ if (pending)
263
+ return pending;
264
+ const mine = this.selectToken;
265
+ const promise = load()
266
+ .then((value) => {
267
+ // Still returned to the caller that asked: it may well be a component that is
268
+ // itself being torn down, and rejecting here would surface a switch as an error.
269
+ // What must not happen is the value being kept for whoever comes next.
270
+ if (mine === this.selectToken) {
271
+ this.cache.set(key, value);
272
+ this.evict();
273
+ }
274
+ return value;
275
+ })
276
+ .finally(() => {
277
+ if (this.inFlight.get(key) === promise)
278
+ this.inFlight.delete(key);
279
+ });
280
+ this.inFlight.set(key, promise);
281
+ return promise;
282
+ }
283
+ evict() {
284
+ while (this.cache.size > SpatialDataHttpService.CACHE_LIMIT) {
285
+ const oldest = this.cache.keys().next().value;
286
+ if (oldest === undefined)
287
+ break;
288
+ this.cache.delete(oldest);
289
+ }
290
+ }
291
+ getJson(path) {
292
+ return firstValueFrom(this.http.get(`${this.baseUrl}${path}`).pipe(timeout(this.timeoutMs)));
293
+ }
294
+ getBinary(path) {
295
+ return firstValueFrom(this.http.get(`${this.baseUrl}${path}`, { responseType: 'arraybuffer' })
296
+ .pipe(timeout(this.timeoutMs)));
297
+ }
298
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialDataHttpService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
299
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialDataHttpService }); }
300
+ }
301
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialDataHttpService, decorators: [{
302
+ type: Injectable
303
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
304
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1kYXRhLWh0dHAuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvaW1wbGVtZW50YXRpb25zL3NwYXRpYWwtZGF0YS1odHRwL3NwYXRpYWwtZGF0YS1odHRwLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLGVBQWUsRUFBYyxjQUFjLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDbkUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBR3pDLE9BQU8sRUFLTCxjQUFjLEdBQ2YsTUFBTSwwQ0FBMEMsQ0FBQztBQUNsRCxPQUFPLEVBR0wscUJBQXFCLEVBQ3JCLG1CQUFtQixFQUNuQixZQUFZLEVBQ1osWUFBWSxFQUNaLGVBQWUsRUFDZixtQkFBbUIsRUFDbkIsY0FBYyxFQUNkLFlBQVksR0FDYixNQUFNLGdCQUFnQixDQUFDOzs7QUFFeEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzQkc7QUFDSDs7Ozs7R0FLRztBQUNILE1BQU0sT0FBTyxlQUFnQixTQUFRLEtBQUs7SUFDeEMsWUFBWSxFQUFVO1FBQ3BCLEtBQUssQ0FBQywyQkFBMkIsRUFBRSxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3RFLElBQUksQ0FBQyxJQUFJLEdBQUcsaUJBQWlCLENBQUM7SUFDaEMsQ0FBQztDQUNGO0FBU0QsTUFBTSxPQUFPLHNCQUFzQjthQW9CVCxnQkFBVyxHQUFHLEVBQUUsQUFBTCxDQUFNO0lBUXpDLFlBQW9CLElBQWdCO1FBQWhCLFNBQUksR0FBSixJQUFJLENBQVk7UUEzQnBDLDJEQUEyRDtRQUNuRCxZQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ3JCOzBCQUNrQjtRQUNWLGNBQVMsR0FBRyxNQUFNLENB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LENBQUMsQ0FBQyxDQUN6RSxDQUFDO0lBQ0osQ0FBQztJQUVPLFNBQVMsQ0FBQyxJQUFZO1FBQzVCLE9BQU8sY0FBYyxDQUNuQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxFQUFFLEVBQUUsRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLENBQUM7YUFDckUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FDakMsQ0FBQztJQUNKLENBQUM7OEdBcFNVLHNCQUFzQjtrSEFBdEIsc0JBQXNCOzsyRkFBdEIsc0JBQXNCO2tCQURsQyxVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgZmlyc3RWYWx1ZUZyb20gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRpbWVvdXQgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IFNwYXRpYWxEYXRhUG9ydCB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9wb3J0cy9zcGF0aWFsLWRhdGEucG9ydCc7XG5pbXBvcnQge1xuICBTcGF0aWFsQ29sdW1uLFxuICBTcGF0aWFsRGF0YXNldCxcbiAgU3BhdGlhbEVtYmVkZGluZyxcbiAgU3BhdGlhbFBvbHlnb25zLFxuICBmaW5kQ29sdW1uTWV0YSxcbn0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQge1xuICBTcGF0aWFsRGF0YXNldFN1bW1hcnksXG4gIFNwYXRpYWxNYW5pZmVzdCxcbiAgYXNzZXJ0TWFuaWZlc3RWZXJzaW9uLFxuICBkYXRhc2V0RnJvbU1hbmlmZXN0LFxuICBkZWNvZGVDb2x1bW4sXG4gIGRlY29kZUNvb3JkcyxcbiAgZGVjb2RlRW1iZWRkaW5nLFxuICBkZWNvZGVGZWF0dXJlVmVjdG9yLFxuICBkZWNvZGVQb2x5Z29ucyxcbiAgZGVjb2RlUmFkaXVzLFxufSBmcm9tICcuL3NwYXRpYWwtd2lyZSc7XG5cbi8qKlxuICogUmVmZXJlbmNlIHtAbGluayBTcGF0aWFsRGF0YVBvcnR9IGFkYXB0ZXIgZm9yIHRoZSB3aXJlIGZvcm1hdCB0aGUgYnVuZGxlZFxuICogZXhhbXBsZSBzZXJ2ZXIgc3BlYWtzIChzZWUgYHNwYXRpYWwtd2lyZS50c2AgYW5kXG4gKiBgZXhhbXBsZXMvdGlsZS1zZXJ2ZXIvbGliL3NwYXRpYWwubWpzYCkuXG4gKlxuICogT1BUSU9OQUwgQU5EIFVOQk9VTkQgQlkgREVGQVVMVCDigJQgdGhpcyBzZXJ2aWNlIGlzIGBASW5qZWN0YWJsZSgpYCB3aXRob3V0XG4gKiBgcHJvdmlkZWRJbmAsIHNvIG5vdGhpbmcgZ2V0cyBpdCB1bmxlc3MgYSBob3N0IGV4cGxpY2l0bHkgcHJvdmlkZXMgaXQ6XG4gKlxuICogYGBgdHNcbiAqIHByb3ZpZGVyczogW1xuICogICBTcGF0aWFsRGF0YUh0dHBTZXJ2aWNlLFxuICogICB7IHByb3ZpZGU6IFNQQVRJQUxfREFUQV9QT1JULCB1c2VFeGlzdGluZzogU3BhdGlhbERhdGFIdHRwU2VydmljZSB9LFxuICogXVxuICogYGBgXG4gKlxuICogVGhhdCBtaXJyb3JzIGBDZWxscG9zZVNlZ21lbnRlclNlcnZpY2VgOiBhIGNvbmNyZXRlIGltcGxlbWVudGF0aW9uIHRoZVxuICogbGlicmFyeSBzaGlwcyBmb3IgY29udmVuaWVuY2UsIG5vdCBhIGRlZmF1bHQgdGhlIHBvcnQgaW52ZXJzaW9uIGlzIHF1aWV0bHlcbiAqIGdpdmluZyB1cCBvbi4gQSBob3N0IHdpdGggaXRzIG93biBiYWNrZW5kIGltcGxlbWVudHMgYFNwYXRpYWxEYXRhUG9ydGBcbiAqIGRpcmVjdGx5IGFuZCBuZXZlciB0b3VjaGVzIHRoaXMgY2xhc3MuXG4gKlxuICogUmVxdWVzdHMgZ28gdGhyb3VnaCBBbmd1bGFyJ3MgYEh0dHBDbGllbnRgIChub3QgYGZldGNoYCkgc28gdGhlIGhvc3Qnc1xuICogaW50ZXJjZXB0b3JzIOKAlCBhdXRoIGhlYWRlcnMgYWJvdmUgYWxsIOKAlCBhcHBseSwgbWF0Y2hpbmcgYHRpbGUtY2xpZW50LnRzYC5cbiAqL1xuLyoqXG4gKiBBIGRhdGFzZXQgc2VsZWN0aW9uIHRoYXQgYSBuZXdlciBzZWxlY3Rpb24gKG9yIGEgYGNsZWFyYCkgb3ZlcnRvb2suXG4gKlxuICogVGhyb3duIHJhdGhlciB0aGFuIHJlc29sdmVkIHNvIGEgY2FsbGVyIGNhbm5vdCBtaXN0YWtlIGl0IGZvciBcInRoaXMgZGF0YXNldCBpc1xuICogbm93IGxvYWRlZFwiOiBub3RoaW5nIHdhcyBwdWJsaXNoZWQsIG9uIHB1cnBvc2UuXG4gKi9cbmV4cG9ydCBjbGFzcyBTdXBlcnNlZGVkRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKGlkOiBzdHJpbmcpIHtcbiAgICBzdXBlcihgW3NwYXRpYWxdIHNlbGVjdGlvbiBvZiBcIiR7aWR9XCIgd2FzIHN1cGVyc2VkZWQgYnkgYSBuZXdlciBvbmVgKTtcbiAgICB0aGlzLm5hbWUgPSAnU3VwZXJzZWRlZEVycm9yJztcbiAgfVxufVxuXG4vKipcbiAqIFdoYXQgdGhlIExSVSBjYW4gaG9sZC4gT25lIGFsaWFzIHJhdGhlciB0aGFuIGEgdW5pb24gcmVwZWF0ZWQgYXQgZWFjaCB1c2UsIHNvIGFkZGluZyBhIHBheWxvYWRcbiAqIGtpbmQgaXMgYSBzaW5nbGUgZWRpdCBpbnN0ZWFkIG9mIGZvdXIgdGhhdCBjYW4gZHJpZnQgYXBhcnQuXG4gKi9cbnR5cGUgQ2FjaGVkUGF5bG9hZCA9IFNwYXRpYWxDb2x1bW4gfCBGbG9hdDMyQXJyYXkgfCBTcGF0aWFsRW1iZWRkaW5nO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgU3BhdGlhbERhdGFIdHRwU2VydmljZSBpbXBsZW1lbnRzIFNwYXRpYWxEYXRhUG9ydCB7XG4gIC8qKiBTZXJ2ZXIgcm9vdCwgbm9ybWFsaXNlZCB0byBlbmQgd2l0aCBleGFjdGx5IG9uZSBgL2AuICovXG4gIHByaXZhdGUgYmFzZVVybCA9ICcnO1xuICAvKiogUGVyLXJlcXVlc3QgY2VpbGluZy4gVmVjdG9ycyBhcmUgc21hbGw7IGEgaHVuZyByZXF1ZXN0IHNob3VsZCBub3Qgd2VkZ2VcbiAgICogIHRoZSBwaWNrZXIuICovXG4gIHByaXZhdGUgdGltZW91dE1zID0gMzBfMDAwO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZGF0YXNldCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFNwYXRpYWxEYXRhc2V0IHwgbnVsbD4obnVsbCk7XG4gIHByaXZhdGUgbWFuaWZlc3Q6IFNwYXRpYWxNYW5pZmVzdCB8IG51bGwgPSBudWxsO1xuICAvKiogQnVtcGVkIGJ5IGV2ZXJ5IGBzZWxlY3REYXRhc2V0YCBhbmQgZXZlcnkgYGNsZWFyYCwgc28gYSBzZWxlY3Rpb24gdGhhdFxuICAgKiAgZmluaXNoZXMgYWZ0ZXIgYSBuZXdlciBpbnRlbnQgY2FuIHRlbGwgYW5kIGRyb3Agd2hhdCBpdCBmZXRjaGVkLiAqL1xuICBwcml2YXRlIHNlbGVjdFRva2VuID0gMDtcblxuICAvKipcbiAgICogTG9hZGVkIHZlY3RvcnMsIGtleWVkIGBjb2x1bW46PG5hbWU+YCAvIGBmZWF0dXJlOjxuYW1lPmAuIEJvdW5kZWQgTFJVOlxuICAgKiBjb2xvdXJpbmcgYnkgY2x1c3RlciDihpIgYnkgYSBnZW5lIOKGkiBiYWNrIGJ5IGNsdXN0ZXIgbXVzdCBub3QgcmVmZXRjaCwgYnV0IGFuXG4gICAqIGFmdGVybm9vbiBvZiBicm93c2luZyBnZW5lcyBtdXN0IG5vdCBncm93IHdpdGhvdXQgbGltaXQgZWl0aGVyIChvbmUgdmVjdG9yXG4gICAqIGlzIGA0wrdOYCBieXRlcyDigJQgMiBNQiBhdCA1MDBrIGNlbGxzKS5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgY2FjaGUgPSBuZXcgTWFwPHN0cmluZywgQ2FjaGVkUGF5bG9hZD4oKTtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgQ0FDSEVfTElNSVQgPSAzMjtcblxuICAvKiogSW4tZmxpZ2h0IHJlcXVlc3RzLCBzbyBkb3VibGUtY2xpY2tpbmcgYSBnZW5lIGlzc3VlcyBvbmUgZmV0Y2guICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaW5GbGlnaHQgPSBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTxDYWNoZWRQYXlsb2FkPj4oKTtcblxuICBwcml2YXRlIHZvbHVtZVByb21pc2U6IFByb21pc2U8VWludDhBcnJheT4gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBwb2x5Z29uc1Byb21pc2U6IFByb21pc2U8U3BhdGlhbFBvbHlnb25zPiB8IG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgaHR0cDogSHR0cENsaWVudCkge31cblxuICAvLyDilIDilIAgY29uZmlndXJhdGlvbiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogUG9pbnQgdGhlIGFkYXB0ZXIgYXQgYSBzZXJ2ZXIuIENsZWFycyBhbnkgbG9hZGVkIGRhdGFzZXQuICovXG4gIGNvbmZpZ3VyZShvcHRpb25zOiB7IGJhc2VVcmw6IHN0cmluZzsgdGltZW91dE1zPzogbnVtYmVyIH0pOiB2b2lkIHtcbiAgICBjb25zdCByYXcgPSBvcHRpb25zLmJhc2VVcmwgPz8gJyc7XG4gICAgdGhpcy5iYXNlVXJsID0gcmF3LmVuZHNXaXRoKCcvJykgPyByYXcgOiBgJHtyYXd9L2A7XG4gICAgaWYgKG9wdGlvbnMudGltZW91dE1zICE9PSB1bmRlZmluZWQpIHRoaXMudGltZW91dE1zID0gb3B0aW9ucy50aW1lb3V0TXM7XG4gICAgdGhpcy5jbGVhcigpO1xuICB9XG5cbiAgLyoqIERhdGFzZXRzIHRoaXMgc2VydmVyIG9mZmVycywgZm9yIGEgaG9zdC1zaWRlIHBpY2tlci4gKi9cbiAgbGlzdERhdGFzZXRzKCk6IFByb21pc2U8U3BhdGlhbERhdGFzZXRTdW1tYXJ5W10+IHtcbiAgICByZXR1cm4gdGhpcy5nZXRKc29uPHsgZGF0YXNldHM6IFNwYXRpYWxEYXRhc2V0U3VtbWFyeVtdIH0+KCdzcGF0aWFsL2RhdGFzZXRzJylcbiAgICAgIC50aGVuKChyKSA9PiByLmRhdGFzZXRzID8/IFtdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPbmUgZGF0YXNldCdzIG1hbmlmZXN0LCBXSVRIT1VUIHNlbGVjdGluZyBpdC4gTGV0cyBhIGhvc3QgaW5zcGVjdCB3aGF0IGFcbiAgICogc2VydmVyIG9mZmVycyDigJQgY29sdW1uIGFuZCBmZWF0dXJlIG1ldGFkYXRhLCBhbmQgd2hpY2ggaW1hZ2UgYSBkYXRhc2V0XG4gICAqIHJlZ2lzdGVycyBvbnRvIOKAlCB3aGlsZSBidWlsZGluZyBhIHBpY2tlciwgcmF0aGVyIHRoYW4gaGF2aW5nIHRvIGxvYWQgZWFjaFxuICAgKiBkYXRhc2V0IHRvIGZpbmQgb3V0LlxuICAgKi9cbiAgcmVhZE1hbmlmZXN0KGlkOiBzdHJpbmcpOiBQcm9taXNlPFNwYXRpYWxNYW5pZmVzdD4ge1xuICAgIHJldHVybiB0aGlzLmdldEpzb248U3BhdGlhbE1hbmlmZXN0Pihgc3BhdGlhbC8ke2VuY29kZVVSSUNvbXBvbmVudChpZCl9L21hbmlmZXN0YClcbiAgICAgIC50aGVuKChtYW5pZmVzdCkgPT4ge1xuICAgICAgICBhc3NlcnRNYW5pZmVzdFZlcnNpb24obWFuaWZlc3QpO1xuICAgICAgICByZXR1cm4gbWFuaWZlc3Q7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkIGEgZGF0YXNldCBhbmQgcHVibGlzaCBpdCBvbiB7QGxpbmsgZ2V0RGF0YXNldCR9LiBGZXRjaGVzIHRoZSBtYW5pZmVzdCxcbiAgICogdGhlbiB0aGUgdmVjdG9ycyB0aGF0IGFyZSBhbHdheXMgbmVlZGVkIChjb29yZGluYXRlcywgYW5kIGlkcy9yYWRpdXMgd2hlblxuICAgKiB0aGUgbWFuaWZlc3Qgc2F5cyB0aGV5IGV4aXN0KSDigJQgbm90aGluZyBlbHNlLlxuICAgKi9cbiAgYXN5bmMgc2VsZWN0RGF0YXNldChpZDogc3RyaW5nKTogUHJvbWlzZTxTcGF0aWFsRGF0YXNldD4ge1xuICAgIHRoaXMuY2xlYXIoKTtcbiAgICAvLyBTZWxlY3Rpb25zIGFyZSBTRVFVRU5DRUQ6IHRoaXMgaXMgZm91ciBhd2FpdHMgZGVlcCwgc28gYSBzbG93ZXIgZWFybGllclxuICAgIC8vIGNhbGwgd291bGQgb3RoZXJ3aXNlIGFzc2lnbiBgdGhpcy5tYW5pZmVzdGAgb3IgcHVibGlzaCBpdHMgZGF0YXNldCBhZnRlciBhXG4gICAgLy8gbGF0ZXIgb25lIOKAlCBsZWF2aW5nIHRoZSBtYW5pZmVzdCBhbmQgdGhlIG9ic2VydmF0aW9ucyBmcm9tIHR3byBkaWZmZXJlbnRcbiAgICAvLyBkYXRhc2V0cywgd2hpY2ggaXMgd29yc2UgdGhhbiBlaXRoZXIgYmVpbmcgbGF0ZS5cbiAgICBjb25zdCBtaW5lID0gKyt0aGlzLnNlbGVjdFRva2VuO1xuICAgIGNvbnN0IHN1cGVyc2VkZWQgPSAoKSA9PiBtaW5lICE9PSB0aGlzLnNlbGVjdFRva2VuO1xuICAgIGNvbnN0IHBhdGggPSBgc3BhdGlhbC8ke2VuY29kZVVSSUNvbXBvbmVudChpZCl9YDtcblxuICAgIGNvbnN0IG1hbmlmZXN0ID0gYXdhaXQgdGhpcy5nZXRKc29uPFNwYXRpYWxNYW5pZmVzdD4oYCR7cGF0aH0vbWFuaWZlc3RgKTtcbiAgICBhc3NlcnRNYW5pZmVzdFZlcnNpb24obWFuaWZlc3QpO1xuICAgIGlmIChzdXBlcnNlZGVkKCkpIHRocm93IG5ldyBTdXBlcnNlZGVkRXJyb3IoaWQpO1xuICAgIHRoaXMubWFuaWZlc3QgPSBtYW5pZmVzdDtcblxuICAgIGNvbnN0IGNvb3Jkc0J1ZiA9IGF3YWl0IHRoaXMuZ2V0QmluYXJ5KGAke3BhdGh9L2Nvb3Jkc2ApO1xuICAgIGlmIChzdXBlcnNlZGVkKCkpIHRocm93IG5ldyBTdXBlcnNlZGVkRXJyb3IoaWQpO1xuICAgIGNvbnN0IGNvb3JkcyA9IGRlY29kZUNvb3Jkcyhjb29yZHNCdWYsIG1hbmlmZXN0LmNvdW50LCAhIW1hbmlmZXN0Lmhhc1opO1xuXG4gICAgY29uc3QgaWRzID0gbWFuaWZlc3QuaGFzSWRzXG4gICAgICA/IChhd2FpdCB0aGlzLmdldEpzb248eyBpZHM6IHN0cmluZ1tdIH0+KGAke3BhdGh9L2lkc2ApKS5pZHNcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IHJhZGl1cyA9IG1hbmlmZXN0LnJhZGl1cz8ubW9kZSA9PT0gJ3Blci1vYnNlcnZhdGlvbidcbiAgICAgID8gZGVjb2RlUmFkaXVzKGF3YWl0IHRoaXMuZ2V0QmluYXJ5KGAke3BhdGh9L3JhZGl1c2ApLCBtYW5pZmVzdC5jb3VudClcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIGlmIChzdXBlcnNlZGVkKCkpIHRocm93IG5ldyBTdXBlcnNlZGVkRXJyb3IoaWQpO1xuXG4gICAgY29uc3QgZGF0YXNldCA9IGRhdGFzZXRGcm9tTWFuaWZlc3QobWFuaWZlc3QsIGNvb3JkcywgeyBpZHMsIHJhZGl1cyB9KTtcbiAgICB0aGlzLmRhdGFzZXQkLm5leHQoZGF0YXNldCk7XG4gICAgcmV0dXJuIGRhdGFzZXQ7XG4gIH1cblxuICAvKiogRHJvcCB0aGUgbG9hZGVkIGRhdGFzZXQgYW5kIGV2ZXJ5IGNhY2hlZCB2ZWN0b3IuICovXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIC8vIEEgY2xlYXIgaXMgaXRzZWxmIHRoZSBuZXdlc3QgaW50ZW50LCBzbyBpdCBzdXBlcnNlZGVzIGFueSBzZWxlY3Rpb24gc3RpbGxcbiAgICAvLyBpbiBmbGlnaHQgcmF0aGVyIHRoYW4gbGV0dGluZyBvbmUgbGFuZCBhZnRlcndhcmRzLlxuICAgIHRoaXMuc2VsZWN0VG9rZW4rKztcbiAgICB0aGlzLm1hbmlmZXN0ID0gbnVsbDtcbiAgICB0aGlzLmNhY2hlLmNsZWFyKCk7XG4gICAgdGhpcy5pbkZsaWdodC5jbGVhcigpO1xuICAgIHRoaXMucG9seWdvbnNQcm9taXNlID0gbnVsbDtcbiAgICB0aGlzLnZvbHVtZVByb21pc2UgPSBudWxsO1xuICAgIGlmICh0aGlzLmRhdGFzZXQkLnZhbHVlICE9PSBudWxsKSB0aGlzLmRhdGFzZXQkLm5leHQobnVsbCk7XG4gIH1cblxuICAvLyDilIDilIAgU3BhdGlhbERhdGFQb3J0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIGdldERhdGFzZXQkKCk6IE9ic2VydmFibGU8U3BhdGlhbERhdGFzZXQgfCBudWxsPiB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YXNldCQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICBnZXRDb2x1bW4obmFtZTogc3RyaW5nKTogUHJvbWlzZTxTcGF0aWFsQ29sdW1uPiB7XG4gICAgY29uc3QgbWFuaWZlc3QgPSB0aGlzLnJlcXVpcmVNYW5pZmVzdCgpO1xuICAgIGNvbnN0IGRhdGFzZXQgPSB0aGlzLmRhdGFzZXQkLnZhbHVlITtcbiAgICBjb25zdCBtZXRhID0gZmluZENvbHVtbk1ldGEoZGF0YXNldCwgbmFtZSk7XG4gICAgaWYgKCFtZXRhKSB7XG4gICAgICAvLyBSZWplY3QgcmF0aGVyIHRoYW4gcmVzb2x2ZSBlbXB0eTogYSB0eXBvIG11c3Qgc3VyZmFjZSBhcyBhbiBlcnJvciwgbm90XG4gICAgICAvLyBhcyBhIHBsb3QgdGhhdCBzaWxlbnRseSByZW5kZXJzIGV2ZXJ5IHBvaW50IGFzIFwibm8gZGF0YVwiLlxuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcbiAgICAgICAgYFtzcGF0aWFsXSB1bmtub3duIGNvbHVtbiBcIiR7bmFtZX1cIi4gQXZhaWxhYmxlOiAke2RhdGFzZXQuY29sdW1ucy5tYXAoKGMpID0+IGMubmFtZSkuam9pbignLCAnKX1gLFxuICAgICAgKSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmZldGNoQ2FjaGVkKFxuICAgICAgYGNvbHVtbjoke25hbWV9YCxcbiAgICAgICgpID0+IHRoaXMuZ2V0QmluYXJ5KGBzcGF0aWFsLyR7ZW5jb2RlVVJJQ29tcG9uZW50KG1hbmlmZXN0LmlkKX0vY29sdW1uLyR7ZW5jb2RlVVJJQ29tcG9uZW50KG5hbWUpfWApXG4gICAgICAgIC50aGVuKChidWYpID0+IGRlY29kZUNvbHVtbihidWYsIG1ldGEsIG1hbmlmZXN0LmNvdW50KSksXG4gICAgKSBhcyBQcm9taXNlPFNwYXRpYWxDb2x1bW4+O1xuICB9XG5cbiAgZ2V0RW1iZWRkaW5nKG5hbWU6IHN0cmluZyk6IFByb21pc2U8U3BhdGlhbEVtYmVkZGluZz4ge1xuICAgIGNvbnN0IG1hbmlmZXN0ID0gdGhpcy5yZXF1aXJlTWFuaWZlc3QoKTtcbiAgICBjb25zdCBtZXRhID0gbWFuaWZlc3QuZW1iZWRkaW5ncz8uZmluZCgoZSkgPT4gZS5uYW1lID09PSBuYW1lKTtcbiAgICBpZiAoIW1ldGEpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoYFtzcGF0aWFsXSB1bmtub3duIGVtYmVkZGluZyBcIiR7bmFtZX1cImApKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuZmV0Y2hDYWNoZWQoXG4gICAgICBgZW1iZWRkaW5nOiR7bmFtZX1gLFxuICAgICAgKCkgPT4gdGhpcy5nZXRCaW5hcnkoXG4gICAgICAgIGBzcGF0aWFsLyR7ZW5jb2RlVVJJQ29tcG9uZW50KG1hbmlmZXN0LmlkKX0vZW1iZWRkaW5nLyR7ZW5jb2RlVVJJQ29tcG9uZW50KG5hbWUpfWAsXG4gICAgICApLnRoZW4oKGJ1ZikgPT4gZGVjb2RlRW1iZWRkaW5nKGJ1ZiwgbWV0YSwgbWFuaWZlc3QuY291bnQpKSxcbiAgICApIGFzIFByb21pc2U8U3BhdGlhbEVtYmVkZGluZz47XG4gIH1cblxuICBnZXRGZWF0dXJlVmVjdG9yKG5hbWU6IHN0cmluZyk6IFByb21pc2U8RmxvYXQzMkFycmF5PiB7XG4gICAgY29uc3QgbWFuaWZlc3QgPSB0aGlzLnJlcXVpcmVNYW5pZmVzdCgpO1xuICAgIGNvbnN0IG5hbWVzID0gbWFuaWZlc3QuZmVhdHVyZXM/Lm5hbWVzO1xuICAgIGlmIChuYW1lcyAmJiAhbmFtZXMuaW5jbHVkZXMobmFtZSkpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoYFtzcGF0aWFsXSB1bmtub3duIGZlYXR1cmUgXCIke25hbWV9XCJgKSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmZldGNoQ2FjaGVkKFxuICAgICAgYGZlYXR1cmU6JHtuYW1lfWAsXG4gICAgICAoKSA9PiB0aGlzLmdldEJpbmFyeShgc3BhdGlhbC8ke2VuY29kZVVSSUNvbXBvbmVudChtYW5pZmVzdC5pZCl9L2ZlYXR1cmUvJHtlbmNvZGVVUklDb21wb25lbnQobmFtZSl9YClcbiAgICAgICAgLnRoZW4oKGJ1ZikgPT4gZGVjb2RlRmVhdHVyZVZlY3RvcihidWYsIG1hbmlmZXN0LmNvdW50KSksXG4gICAgKSBhcyBQcm9taXNlPEZsb2F0MzJBcnJheT47XG4gIH1cblxuICBhc3luYyBzZWFyY2hGZWF0dXJlcyhxdWVyeTogc3RyaW5nLCBsaW1pdCA9IDUwKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGNvbnN0IG1hbmlmZXN0ID0gdGhpcy5yZXF1aXJlTWFuaWZlc3QoKTtcbiAgICAvLyBBIGRhdGFzZXQgdGhhdCBpbmxpbmVkIGl0cyBuYW1lcyAodGFyZ2V0ZWQgcGFuZWwpIGlzIGZpbHRlcmVkIGxvY2FsbHkg4oCUXG4gICAgLy8gbm8gcm91bmQtdHJpcCBmb3IgYSBrZXlzdHJva2UuXG4gICAgY29uc3QgbmFtZXMgPSBtYW5pZmVzdC5mZWF0dXJlcz8ubmFtZXM7XG4gICAgaWYgKG5hbWVzKSB7XG4gICAgICBjb25zdCBxID0gcXVlcnkudG9Mb3dlckNhc2UoKTtcbiAgICAgIHJldHVybiBuYW1lcy5maWx0ZXIoKG4pID0+IG4udG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhxKSkuc2xpY2UoMCwgbGltaXQpO1xuICAgIH1cbiAgICBjb25zdCB1cmwgPSBgc3BhdGlhbC8ke2VuY29kZVVSSUNvbXBvbmVudChtYW5pZmVzdC5pZCl9L2ZlYXR1cmVzYFxuICAgICAgKyBgP3E9JHtlbmNvZGVVUklDb21wb25lbnQocXVlcnkpfSZsaW1pdD0ke2xpbWl0fWA7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmdldEpzb248eyBuYW1lczogc3RyaW5nW10gfT4odXJsKSkubmFtZXMgPz8gW107XG4gIH1cblxuICBnZXRQb2x5Z29ucygpOiBQcm9taXNlPFNwYXRpYWxQb2x5Z29ucz4ge1xuICAgIGNvbnN0IG1hbmlmZXN0ID0gdGhpcy5yZXF1aXJlTWFuaWZlc3QoKTtcbiAgICBpZiAoIW1hbmlmZXN0LnBvbHlnb25zKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IEVycm9yKCdbc3BhdGlhbF0gdGhpcyBkYXRhc2V0IGhhcyBubyBwb2x5Z29uIGdlb21ldHJ5JykpO1xuICAgIH1cbiAgICAvLyBHZW9tZXRyeSBpcyBvbmUgbGFyZ2UgYmxvYiByYXRoZXIgdGhhbiBhIHBlci1uYW1lIHZlY3Rvciwgc28gaXQgZ2V0cyBpdHNcbiAgICAvLyBvd24gc2luZ2xlLWZsaWdodCBzbG90IGluc3RlYWQgb2YgYSBjYWNoZSBlbnRyeS5cbiAgICB0aGlzLnBvbHlnb25zUHJvbWlzZSA/Pz0gdGhpc1xuICAgICAgLmdldEJpbmFyeShgc3BhdGlhbC8ke2VuY29kZVVSSUNvbXBvbmVudChtYW5pZmVzdC5pZCl9L3BvbHlnb25zYClcbiAgICAgIC50aGVuKGRlY29kZVBvbHlnb25zKVxuICAgICAgLmNhdGNoKChlcnIpID0+IHsgdGhpcy5wb2x5Z29uc1Byb21pc2UgPSBudWxsOyB0aHJvdyBlcnI7IH0pO1xuICAgIHJldHVybiB0aGlzLnBvbHlnb25zUHJvbWlzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgcmVmZXJlbmNlIHZvbHVtZSdzIHZveGVscywgc2luZ2xlLWZsaWdodGVkIGxpa2UgdGhlIHBvbHlnb25zLlxuICAgKlxuICAgKiBWYWxpZGF0ZWQgYWdhaW5zdCB0aGUgbWFuaWZlc3QncyBkZWNsYXJlZCBkaW1lbnNpb25zIGJlZm9yZSBpdCBpcyBoYW5kZWRcbiAgICogYmFjazogYSBzaG9ydCBvciBsb25nIGJ1ZmZlciByZWFkIGFzIGEgM0QgdGV4dHVyZSBkb2VzIG5vdCBmYWlsLCBpdCBzaGVhcnNcbiAgICogdGhlIGFuYXRvbXkgaW50byBkaWFnb25hbCBzdHJlYWtzLCBhbmQgdGhhdCBpcyBmYXIgaGFyZGVyIHRvIHJlY29nbmlzZSBhcyBhXG4gICAqIHRyYW5zcG9ydCBwcm9ibGVtIHRoYW4gYW4gZXJyb3IgaXMuXG4gICAqL1xuICBnZXRWb2x1bWUoKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gICAgY29uc3QgbWFuaWZlc3QgPSB0aGlzLnJlcXVpcmVNYW5pZmVzdCgpO1xuICAgIGNvbnN0IG1ldGEgPSBtYW5pZmVzdC52b2x1bWU7XG4gICAgaWYgKCFtZXRhKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IEVycm9yKCdbc3BhdGlhbF0gdGhpcyBkYXRhc2V0IGhhcyBubyByZWZlcmVuY2Ugdm9sdW1lJykpO1xuICAgIH1cbiAgICB0aGlzLnZvbHVtZVByb21pc2UgPz89IHRoaXNcbiAgICAgIC5nZXRCaW5hcnkoYHNwYXRpYWwvJHtlbmNvZGVVUklDb21wb25lbnQobWFuaWZlc3QuaWQpfS92b2x1bWVgKVxuICAgICAgLnRoZW4oKGJ1ZikgPT4ge1xuICAgICAgICBjb25zdCB3YW50ID0gbWV0YS53aWR0aCAqIG1ldGEuaGVpZ2h0ICogbWV0YS5kZXB0aDtcbiAgICAgICAgaWYgKGJ1Zi5ieXRlTGVuZ3RoICE9PSB3YW50KSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYFtzcGF0aWFsXSB2b2x1bWUgaXMgJHtidWYuYnl0ZUxlbmd0aH0gYnl0ZXMsIGV4cGVjdGVkICR7d2FudH0gYFxuICAgICAgICAgICAgKyBgKCR7bWV0YS53aWR0aH14JHttZXRhLmhlaWdodH14JHttZXRhLmRlcHRofSlgLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KGJ1Zik7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlcnIpID0+IHsgdGhpcy52b2x1bWVQcm9taXNlID0gbnVsbDsgdGhyb3cgZXJyOyB9KTtcbiAgICByZXR1cm4gdGhpcy52b2x1bWVQcm9taXNlO1xuICB9XG5cbiAgLy8g4pSA4pSAIGludGVybmFscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIHJlcXVpcmVNYW5pZmVzdCgpOiBTcGF0aWFsTWFuaWZlc3Qge1xuICAgIGlmICghdGhpcy5tYW5pZmVzdCB8fCAhdGhpcy5kYXRhc2V0JC52YWx1ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdbc3BhdGlhbF0gbm8gZGF0YXNldCBzZWxlY3RlZCDigJQgY2FsbCBzZWxlY3REYXRhc2V0KCkgZmlyc3QnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMubWFuaWZlc3Q7XG4gIH1cblxuICAvKipcbiAgICogQ2FjaGUgKyBzaW5nbGUtZmxpZ2h0IGFyb3VuZCBhIHZlY3RvciBmZXRjaC5cbiAgICpcbiAgICogS2V5cyBhcmUgTE9HSUNBTCDigJQgYGZlYXR1cmU6R0FQREhgLCBub3QgYDxkYXRhc2V0Pi9mZWF0dXJlOkdBUERIYCDigJQgYmVjYXVzZSBgY2xlYXIoKWBcbiAgICogZW1wdGllcyB0aGUgbWFwcyBvbiBldmVyeSBzd2l0Y2gsIHNvIHR3byBkYXRhc2V0cyBuZXZlciBob2xkIGVudHJpZXMgYXQgb25jZS4gV2hhdFxuICAgKiB0aGF0IGRvZXMgbm90IGNvdmVyIGlzIGEgcmVxdWVzdCBzdGlsbCBpbiB0aGUgYWlyIHdoZW4gdGhlIHN3aXRjaCBoYXBwZW5zOiBgY2xlYXIoKWBcbiAgICogY2Fubm90IGNhbmNlbCBhbiBIVFRQIGNhbGwsIHNvIGEgdmVjdG9yIGZldGNoZWQgZm9yIGRhdGFzZXQgQSBjYW4gcmVzb2x2ZSBhZnRlciBCIGhhc1xuICAgKiBiZWVuIHNlbGVjdGVkIGFuZCB3cml0ZSBpdHNlbGYgaW50byBCJ3MgY2FjaGUgdW5kZXIgYSBrZXkgQiB3b3VsZCByZWFkLiBCb3RoIGRhdGFzZXRzXG4gICAqIGhhdmluZyBhIGdlbmUgb2YgdGhhdCBuYW1lIGlzIHRoZSBjb21tb24gY2FzZSwgbm90IHRoZSB1bmx1Y2t5IG9uZSwgYW5kIHRoZSByZXN1bHQgaXNcbiAgICogYSBwbG90IG9mIEEncyBleHByZXNzaW9uIG92ZXIgQidzIGNlbGxzIOKAlCB3aGljaCBsb29rcyBsaWtlIGRhdGEsIG5vdCBsaWtlIGEgZmF1bHQuXG4gICAqXG4gICAqIFNvIHRoZSBnZW5lcmF0aW9uIGlzIGNoZWNrZWQgYWZ0ZXIgdGhlIGF3YWl0LCBhbmQgdGhlIGluLWZsaWdodCBzbG90IGlzIGNsZWFyZWQgb25seVxuICAgKiB3aGVuIHRoZSBwcm9taXNlIHN0aWxsIHNpdHRpbmcgaW4gaXQgaXMgdGhpcyBvbmU6IGEgbGF0ZSBhcnJpdmFsIG11c3Qgbm90IGV2aWN0IHRoZVxuICAgKiBlbnRyeSBhIG5ld2VyIHJlcXVlc3QgZm9yIHRoZSBzYW1lIGtleSBpcyBhbHJlYWR5IHNoYXJpbmcuXG4gICAqL1xuICBwcml2YXRlIGZldGNoQ2FjaGVkKGtleTogc3RyaW5nLCBsb2FkOiAoKSA9PiBQcm9taXNlPENhY2hlZFBheWxvYWQ+KTogUHJvbWlzZTxDYWNoZWRQYXlsb2FkPiB7XG4gICAgY29uc3QgaGl0ID0gdGhpcy5jYWNoZS5nZXQoa2V5KTtcbiAgICBpZiAoaGl0KSB7XG4gICAgICAvLyBSZS1pbnNlcnQgdG8gbWFyayBtb3N0LXJlY2VudGx5LXVzZWQgKE1hcCBwcmVzZXJ2ZXMgaW5zZXJ0aW9uIG9yZGVyKS5cbiAgICAgIHRoaXMuY2FjaGUuZGVsZXRlKGtleSk7XG4gICAgICB0aGlzLmNhY2hlLnNldChrZXksIGhpdCk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGhpdCk7XG4gICAgfVxuICAgIGNvbnN0IHBlbmRpbmcgPSB0aGlzLmluRmxpZ2h0LmdldChrZXkpO1xuICAgIGlmIChwZW5kaW5nKSByZXR1cm4gcGVuZGluZztcblxuICAgIGNvbnN0IG1pbmUgPSB0aGlzLnNlbGVjdFRva2VuO1xuICAgIGNvbnN0IHByb21pc2U6IFByb21pc2U8Q2FjaGVkUGF5bG9hZD4gPSBsb2FkKClcbiAgICAgIC50aGVuKCh2YWx1ZSkgPT4ge1xuICAgICAgICAvLyBTdGlsbCByZXR1cm5lZCB0byB0aGUgY2FsbGVyIHRoYXQgYXNrZWQ6IGl0IG1heSB3ZWxsIGJlIGEgY29tcG9uZW50IHRoYXQgaXNcbiAgICAgICAgLy8gaXRzZWxmIGJlaW5nIHRvcm4gZG93biwgYW5kIHJlamVjdGluZyBoZXJlIHdvdWxkIHN1cmZhY2UgYSBzd2l0Y2ggYXMgYW4gZXJyb3IuXG4gICAgICAgIC8vIFdoYXQgbXVzdCBub3QgaGFwcGVuIGlzIHRoZSB2YWx1ZSBiZWluZyBrZXB0IGZvciB3aG9ldmVyIGNvbWVzIG5leHQuXG4gICAgICAgIGlmIChtaW5lID09PSB0aGlzLnNlbGVjdFRva2VuKSB7XG4gICAgICAgICAgdGhpcy5jYWNoZS5zZXQoa2V5LCB2YWx1ZSk7XG4gICAgICAgICAgdGhpcy5ldmljdCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgIH0pXG4gICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmluRmxpZ2h0LmdldChrZXkpID09PSBwcm9taXNlKSB0aGlzLmluRmxpZ2h0LmRlbGV0ZShrZXkpO1xuICAgICAgfSk7XG4gICAgdGhpcy5pbkZsaWdodC5zZXQoa2V5LCBwcm9taXNlKTtcbiAgICByZXR1cm4gcHJvbWlzZTtcbiAgfVxuXG4gIHByaXZhdGUgZXZpY3QoKTogdm9pZCB7XG4gICAgd2hpbGUgKHRoaXMuY2FjaGUuc2l6ZSA+IFNwYXRpYWxEYXRhSHR0cFNlcnZpY2UuQ0FDSEVfTElNSVQpIHtcbiAgICAgIGNvbnN0IG9sZGVzdCA9IHRoaXMuY2FjaGUua2V5cygpLm5leHQoKS52YWx1ZSBhcyBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgICBpZiAob2xkZXN0ID09PSB1bmRlZmluZWQpIGJyZWFrO1xuICAgICAgdGhpcy5jYWNoZS5kZWxldGUob2xkZXN0KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGdldEpzb248VD4ocGF0aDogc3RyaW5nKTogUHJvbWlzZTxUPiB7XG4gICAgcmV0dXJuIGZpcnN0VmFsdWVGcm9tKFxuICAgICAgdGhpcy5odHRwLmdldDxUPihgJHt0aGlzLmJhc2VVcmx9JHtwYXRofWApLnBpcGUodGltZW91dCh0aGlzLnRpbWVvdXRNcykpLFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdldEJpbmFyeShwYXRoOiBzdHJpbmcpOiBQcm9taXNlPEFycmF5QnVmZmVyPiB7XG4gICAgcmV0dXJuIGZpcnN0VmFsdWVGcm9tKFxuICAgICAgdGhpcy5odHRwLmdldChgJHt0aGlzLmJhc2VVcmx9JHtwYXRofWAsIHsgcmVzcG9uc2VUeXBlOiAnYXJyYXlidWZmZXInIH0pXG4gICAgICAgIC5waXBlKHRpbWVvdXQodGhpcy50aW1lb3V0TXMpKSxcbiAgICApO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,179 @@
1
+ import { NO_CATEGORY, } from '../../contracts/spatial-dataset.contract';
2
+ /**
3
+ * The wire format the bundled example server speaks, and its decoders.
4
+ *
5
+ * Pure by design — no Angular, no RxJS, no HTTP — so the format is testable on
6
+ * its own and reusable by any transport (`SpatialDataHttpService` is one).
7
+ * Mirrors the split in `plotly-trace-builders.ts`: the shape lives in a pure
8
+ * module, the service just moves bytes.
9
+ *
10
+ * WHY BINARY
11
+ * ----------
12
+ * Vectors are one `Float32Array`/`Uint16Array` per request, delivered as raw
13
+ * little-endian bytes. JSON would cost ~8–12× the size and a parse that
14
+ * allocates one JS number per value; a typed-array view over the response
15
+ * buffer is zero-copy and uploads to the GPU directly.
16
+ *
17
+ * ENDIANNESS
18
+ * ----------
19
+ * Little-endian, asserted at decode. Every platform a browser runs on today is
20
+ * little-endian, so a `DataView` byte-by-byte read would cost real time for a
21
+ * case that does not occur — but failing loudly beats rendering transposed
22
+ * garbage if it ever does.
23
+ *
24
+ * ENDPOINTS (base = the server root)
25
+ * ----------------------------------
26
+ * ```
27
+ * GET {base}/spatial/datasets -> { datasets: [{ id, name, count }] }
28
+ * GET {base}/spatial/{id}/manifest -> SpatialManifest
29
+ * GET {base}/spatial/{id}/coords -> f32[N] x, f32[N] y, f32[N] z?
30
+ * GET {base}/spatial/{id}/radius -> f32[N] (per-observation radius only)
31
+ * GET {base}/spatial/{id}/ids -> { ids: string[] } (hasIds only)
32
+ * GET {base}/spatial/{id}/column/{name} -> u16[N] codes | f32[N] values
33
+ * GET {base}/spatial/{id}/feature/{name} -> f32[N]
34
+ * GET {base}/spatial/{id}/features?q=&limit= -> { names: string[] }
35
+ * GET {base}/spatial/{id}/polygons -> u32 count, u32[count+1] offsets, f32[2*rings] coords
36
+ * ```
37
+ */
38
+ /** Bumped when the layout changes incompatibly; the client refuses anything else. */
39
+ export const SPATIAL_WIRE_VERSION = 1;
40
+ /** True on a little-endian host. */
41
+ export function isLittleEndian() {
42
+ const probe = new Uint16Array([1]);
43
+ return new Uint8Array(probe.buffer)[0] === 1;
44
+ }
45
+ function assertLittleEndian() {
46
+ if (!isLittleEndian()) {
47
+ throw new Error('[spatial] wire format is little-endian; this platform is big-endian. ' +
48
+ 'Serve JSON vectors, or byte-swap in a custom SpatialDataPort adapter.');
49
+ }
50
+ }
51
+ /** Guard a decode against a truncated or oversized response. */
52
+ function assertByteLength(buf, expected, what) {
53
+ if (buf.byteLength !== expected) {
54
+ throw new Error(`[spatial] ${what}: expected ${expected} bytes, got ${buf.byteLength}. ` +
55
+ 'Manifest count and served vector length disagree.');
56
+ }
57
+ }
58
+ /** Reject a manifest this client cannot read, with a message naming the fix. */
59
+ export function assertManifestVersion(manifest) {
60
+ if (manifest.version !== SPATIAL_WIRE_VERSION) {
61
+ throw new Error(`[spatial] unsupported wire version ${manifest.version} ` +
62
+ `(this client speaks ${SPATIAL_WIRE_VERSION}). Update the server or the library.`);
63
+ }
64
+ }
65
+ /**
66
+ * `GET /coords` → x/y(/z). One request rather than two or three: the vectors
67
+ * are always fetched together, and a single response keeps them consistent if
68
+ * the dataset changes underneath.
69
+ */
70
+ export function decodeCoords(buf, count, hasZ = false) {
71
+ assertLittleEndian();
72
+ const axes = hasZ ? 3 : 2;
73
+ assertByteLength(buf, count * axes * 4, 'coords');
74
+ const x = new Float32Array(buf, 0, count);
75
+ const y = new Float32Array(buf, count * 4, count);
76
+ const z = hasZ ? new Float32Array(buf, count * 8, count) : undefined;
77
+ return { x, y, z };
78
+ }
79
+ /** `GET /radius` → per-observation radii in image pixels. */
80
+ export function decodeRadius(buf, count) {
81
+ assertLittleEndian();
82
+ assertByteLength(buf, count * 4, 'radius');
83
+ return new Float32Array(buf, 0, count);
84
+ }
85
+ /** `GET /feature/{name}` → one gene's expression vector. */
86
+ /**
87
+ * `GET /spatial/{id}/embedding/{name}` — one plane per dimension, same layout as coords.
88
+ *
89
+ * Struct of arrays, not interleaved: every dimension is contiguous, so an axis can be handed to
90
+ * the renderer as a view with no copy and no stride.
91
+ */
92
+ export function decodeEmbedding(buf, meta, count) {
93
+ assertLittleEndian();
94
+ assertByteLength(buf, count * meta.dims * 4, `embedding "${meta.name}"`);
95
+ return {
96
+ meta,
97
+ x: new Float32Array(buf, 0, count),
98
+ y: new Float32Array(buf, count * 4, count),
99
+ ...(meta.dims === 3 ? { z: new Float32Array(buf, count * 8, count) } : {}),
100
+ };
101
+ }
102
+ export function decodeFeatureVector(buf, count) {
103
+ assertLittleEndian();
104
+ assertByteLength(buf, count * 4, 'feature vector');
105
+ return new Float32Array(buf, 0, count);
106
+ }
107
+ /**
108
+ * `GET /column/{name}` → a loaded column, typed by its descriptor: `u16` codes
109
+ * for a categorical, `f32` values for a continuous. Codes outside the category
110
+ * list are normalised to {@link NO_CATEGORY} so a renderer can trust the
111
+ * invariant instead of bounds-checking every point.
112
+ */
113
+ export function decodeColumn(buf, meta, count) {
114
+ assertLittleEndian();
115
+ if (meta.kind === 'categorical') {
116
+ assertByteLength(buf, count * 2, `column "${meta.name}"`);
117
+ const codes = new Uint16Array(buf, 0, count);
118
+ const n = meta.categories.length;
119
+ for (let i = 0; i < codes.length; i++) {
120
+ if (codes[i] >= n)
121
+ codes[i] = NO_CATEGORY;
122
+ }
123
+ return { meta: meta, codes };
124
+ }
125
+ assertByteLength(buf, count * 4, `column "${meta.name}"`);
126
+ return { meta: meta, values: new Float32Array(buf, 0, count) };
127
+ }
128
+ /**
129
+ * `GET /polygons` → boundary rings. Layout is
130
+ * `[u32 count][u32 offsets × (count+1)][f32 coords × 2·offsets[count]]`; every
131
+ * field is 4-byte wide so each typed-array view stays aligned.
132
+ */
133
+ export function decodePolygons(buf) {
134
+ assertLittleEndian();
135
+ if (buf.byteLength < 8) {
136
+ throw new Error('[spatial] polygons: response too short for a header');
137
+ }
138
+ const count = new Uint32Array(buf, 0, 1)[0];
139
+ const offsets = new Uint32Array(buf, 4, count + 1);
140
+ const vertexCount = offsets[count];
141
+ const coordsByteOffset = 4 + (count + 1) * 4;
142
+ assertByteLength(buf, coordsByteOffset + vertexCount * 2 * 4, 'polygons');
143
+ const coords = new Float32Array(buf, coordsByteOffset, vertexCount * 2);
144
+ return { coords, offsets, count };
145
+ }
146
+ /**
147
+ * Fold a manifest plus its fetched coordinate/id/radius vectors into the
148
+ * library-facing {@link SpatialDataset}. Column and feature *values* are not
149
+ * part of this — they stay lazy behind the port.
150
+ */
151
+ export function datasetFromManifest(manifest, coords, extras = {}) {
152
+ assertManifestVersion(manifest);
153
+ const radius = manifest.radius?.mode === 'uniform'
154
+ ? manifest.radius.value
155
+ : extras.radius;
156
+ const observations = {
157
+ count: manifest.count,
158
+ x: coords.x,
159
+ y: coords.y,
160
+ ...(coords.z ? { z: coords.z } : {}),
161
+ ...(extras.ids ? { ids: extras.ids } : {}),
162
+ ...(radius !== undefined ? { radius } : {}),
163
+ };
164
+ return {
165
+ id: manifest.id,
166
+ name: manifest.name,
167
+ observations,
168
+ columns: manifest.columns ?? [],
169
+ ...(manifest.features ? { features: manifest.features } : {}),
170
+ ...(manifest.polygons ? { polygons: manifest.polygons } : {}),
171
+ ...(manifest.imageRef ? { imageRef: manifest.imageRef } : {}),
172
+ ...(manifest.volume ? { volume: manifest.volume } : {}),
173
+ ...(manifest.embeddings?.length ? { embeddings: manifest.embeddings } : {}),
174
+ ...(manifest.micronsPerUnit !== undefined
175
+ ? { micronsPerUnit: manifest.micronsPerUnit }
176
+ : {}),
177
+ };
178
+ }
179
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC13aXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9pbXBsZW1lbnRhdGlvbnMvc3BhdGlhbC1kYXRhLWh0dHAvc3BhdGlhbC13aXJlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFHTCxXQUFXLEdBV1osTUFBTSwwQ0FBMEMsQ0FBQztBQUVsRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQ0c7QUFFSCxxRkFBcUY7QUFDckYsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxDQUFDO0FBaUN0QyxvQ0FBb0M7QUFDcEMsTUFBTSxVQUFVLGNBQWM7SUFDNUIsTUFBTSxLQUFLLEdBQUcsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25DLE9BQU8sSUFBSSxVQUFVLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUMvQyxDQUFDO0FBRUQsU0FBUyxrQkFBa0I7SUFDekIsSUFBSSxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUM7UUFDdEIsTUFBTSxJQUFJLEtBQUssQ0FDYix1RUFBdUU7WUFDdkUsdUVBQXVFLENBQ3hFLENBQUM7SUFDSixDQUFDO0FBQ0gsQ0FBQztBQUVELGdFQUFnRTtBQUNoRSxTQUFTLGdCQUFnQixDQUFDLEdBQWdCLEVBQUUsUUFBZ0IsRUFBRSxJQUFZO0lBQ3hFLElBQUksR0FBRyxDQUFDLFVBQVUsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUNoQyxNQUFNLElBQUksS0FBSyxDQUNiLGFBQWEsSUFBSSxjQUFjLFFBQVEsZUFBZSxHQUFHLENBQUMsVUFBVSxJQUFJO1lBQ3hFLG1EQUFtRCxDQUNwRCxDQUFDO0lBQ0osQ0FBQztBQUNILENBQUM7QUFFRCxnRkFBZ0Y7QUFDaEYsTUFBTSxVQUFVLHFCQUFxQixDQUFDLFFBQXlCO0lBQzdELElBQUks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QyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDMUMsR0FBRyxDQUFDLE1BQU0sS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUM1QyxDQUFDO0lBQ0YsT0FBTztRQUNMLEVBQUUsRUFBRSxRQUFRLENBQUMsRUFBRTtRQUNmLElBQUksRUFBRSxRQUFRLENBQUMsSUFBSTtRQUNuQixZQUFZO1FBQ1osT0FBTyxFQUFFLFFBQVEsQ0FBQyxPQUFPLElBQUksRUFBRTtRQUMvQixHQUFHLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDN0QsR0FBRyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzdELEdBQUcsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM3RCxHQUFHLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDdkQsR0FBRyxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUMzRSxHQUFHLENBQUMsUUFBUSxDQUFDLGNBQWMsS0FBSyxTQUFTO1lBQ3ZDLENBQUMsQ0FBQyxFQUFFLGNBQWMsRUFBRSxRQUFRLENBQUMsY0FBYyxFQUFFO1lBQzdDLENBQUMsQ0FBQyxFQUFFLENBQUM7S0FDUixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENhdGVnb3JpY2FsQ29sdW1uTWV0YSxcbiAgQ29udGludW91c0NvbHVtbk1ldGEsXG4gIE5PX0NBVEVHT1JZLFxuICBTcGF0aWFsQ29sdW1uLFxuICBTcGF0aWFsQ29sdW1uTWV0YSxcbiAgU3BhdGlhbERhdGFzZXQsXG4gIFNwYXRpYWxFbWJlZGRpbmcsXG4gIFNwYXRpYWxFbWJlZGRpbmdNZXRhLFxuICBTcGF0aWFsRmVhdHVyZU1ldGEsXG4gIFNwYXRpYWxJbWFnZVJlZixcbiAgU3BhdGlhbE9ic2VydmF0aW9ucyxcbiAgU3BhdGlhbFBvbHlnb25zLFxuICBTcGF0aWFsVm9sdW1lTWV0YSxcbn0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5cbi8qKlxuICogVGhlIHdpcmUgZm9ybWF0IHRoZSBidW5kbGVkIGV4YW1wbGUgc2VydmVyIHNwZWFrcywgYW5kIGl0cyBkZWNvZGVycy5cbiAqXG4gKiBQdXJlIGJ5IGRlc2lnbiDigJQgbm8gQW5ndWxhciwgbm8gUnhKUywgbm8gSFRUUCDigJQgc28gdGhlIGZvcm1hdCBpcyB0ZXN0YWJsZSBvblxuICogaXRzIG93biBhbmQgcmV1c2FibGUgYnkgYW55IHRyYW5zcG9ydCAoYFNwYXRpYWxEYXRhSHR0cFNlcnZpY2VgIGlzIG9uZSkuXG4gKiBNaXJyb3JzIHRoZSBzcGxpdCBpbiBgcGxvdGx5LXRyYWNlLWJ1aWxkZXJzLnRzYDogdGhlIHNoYXBlIGxpdmVzIGluIGEgcHVyZVxuICogbW9kdWxlLCB0aGUgc2VydmljZSBqdXN0IG1vdmVzIGJ5dGVzLlxuICpcbiAqIFdIWSBCSU5BUllcbiAqIC0tLS0tLS0tLS1cbiAqIFZlY3RvcnMgYXJlIG9uZSBgRmxvYXQzMkFycmF5YC9gVWludDE2QXJyYXlgIHBlciByZXF1ZXN0LCBkZWxpdmVyZWQgYXMgcmF3XG4gKiBsaXR0bGUtZW5kaWFuIGJ5dGVzLiBKU09OIHdvdWxkIGNvc3QgfjjigJMxMsOXIHRoZSBzaXplIGFuZCBhIHBhcnNlIHRoYXRcbiAqIGFsbG9jYXRlcyBvbmUgSlMgbnVtYmVyIHBlciB2YWx1ZTsgYSB0eXBlZC1hcnJheSB2aWV3IG92ZXIgdGhlIHJlc3BvbnNlXG4gKiBidWZmZXIgaXMgemVyby1jb3B5IGFuZCB1cGxvYWRzIHRvIHRoZSBHUFUgZGlyZWN0bHkuXG4gKlxuICogRU5ESUFOTkVTU1xuICogLS0tLS0tLS0tLVxuICogTGl0dGxlLWVuZGlhbiwgYXNzZXJ0ZWQgYXQgZGVjb2RlLiBFdmVyeSBwbGF0Zm9ybSBhIGJyb3dzZXIgcnVucyBvbiB0b2RheSBpc1xuICogbGl0dGxlLWVuZGlhbiwgc28gYSBgRGF0YVZpZXdgIGJ5dGUtYnktYnl0ZSByZWFkIHdvdWxkIGNvc3QgcmVhbCB0aW1lIGZvciBhXG4gKiBjYXNlIHRoYXQgZG9lcyBub3Qgb2NjdXIg4oCUIGJ1dCBmYWlsaW5nIGxvdWRseSBiZWF0cyByZW5kZXJpbmcgdHJhbnNwb3NlZFxuICogZ2FyYmFnZSBpZiBpdCBldmVyIGRvZXMuXG4gKlxuICogRU5EUE9JTlRTIChiYXNlID0gdGhlIHNlcnZlciByb290KVxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogYGBgXG4gKiBHRVQge2Jhc2V9L3NwYXRpYWwvZGF0YXNldHMgICAgICAgICAgICAgIC0+IHsgZGF0YXNldHM6IFt7IGlkLCBuYW1lLCBjb3VudCB9XSB9XG4gKiBHRVQge2Jhc2V9L3NwYXRpYWwve2lkfS9tYW5pZmVzdCAgICAgICAgIC0+IFNwYXRpYWxNYW5pZmVzdFxuICogR0VUIHtiYXNlfS9zcGF0aWFsL3tpZH0vY29vcmRzICAgICAgICAgICAtPiBmMzJbTl0geCwgZjMyW05dIHksIGYzMltOXSB6P1xuICogR0VUIHtiYXNlfS9zcGF0aWFsL3tpZH0vcmFkaXVzICAgICAgICAgICAtPiBmMzJbTl0gICAgICAgICAgIChwZXItb2JzZXJ2YXRpb24gcmFkaXVzIG9ubHkpXG4gKiBHRVQge2Jhc2V9L3NwYXRpYWwve2lkfS9pZHMgICAgICAgICAgICAgIC0+IHsgaWRzOiBzdHJpbmdbXSB9IChoYXNJZHMgb25seSlcbiAqIEdFVCB7YmFzZX0vc3BhdGlhbC97aWR9L2NvbHVtbi97bmFtZX0gICAgLT4gdTE2W05dIGNvZGVzIHwgZjMyW05dIHZhbHVlc1xuICogR0VUIHtiYXNlfS9zcGF0aWFsL3tpZH0vZmVhdHVyZS97bmFtZX0gICAtPiBmMzJbTl1cbiAqIEdFVCB7YmFzZX0vc3BhdGlhbC97aWR9L2ZlYXR1cmVzP3E9JmxpbWl0PSAtPiB7IG5hbWVzOiBzdHJpbmdbXSB9XG4gKiBHRVQge2Jhc2V9L3NwYXRpYWwve2lkfS9wb2x5Z29ucyAgICAgICAgIC0+IHUzMiBjb3VudCwgdTMyW2NvdW50KzFdIG9mZnNldHMsIGYzMlsyKnJpbmdzXSBjb29yZHNcbiAqIGBgYFxuICovXG5cbi8qKiBCdW1wZWQgd2hlbiB0aGUgbGF5b3V0IGNoYW5nZXMgaW5jb21wYXRpYmx5OyB0aGUgY2xpZW50IHJlZnVzZXMgYW55dGhpbmcgZWxzZS4gKi9cbmV4cG9ydCBjb25zdCBTUEFUSUFMX1dJUkVfVkVSU0lPTiA9IDE7XG5cbi8qKiBQZXItb2JzZXJ2YXRpb24gbWFya2VyIHJhZGl1czogb25lIHNoYXJlZCB2YWx1ZSwgb3IgYSBzZXJ2ZWQgZjMyIHZlY3Rvci4gKi9cbmV4cG9ydCB0eXBlIFNwYXRpYWxSYWRpdXNTcGVjID1cbiAgfCB7IG1vZGU6ICd1bmlmb3JtJzsgdmFsdWU6IG51bWJlciB9XG4gIHwgeyBtb2RlOiAncGVyLW9ic2VydmF0aW9uJyB9O1xuXG4vKiogYEdFVCAvc3BhdGlhbC97aWR9L21hbmlmZXN0YCDigJQgZXZlcnl0aGluZyBjaGVhcCBlbm91Z2ggdG8gc2VuZCB1cCBmcm9udC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3BhdGlhbE1hbmlmZXN0IHtcbiAgdmVyc2lvbjogbnVtYmVyO1xuICBpZDogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKiBOIOKAlCBvYnNlcnZhdGlvbiBjb3VudDsgZXZlcnkgc2VydmVkIHZlY3RvciBoYXMgZXhhY3RseSB0aGlzIGxlbmd0aC4gKi9cbiAgY291bnQ6IG51bWJlcjtcbiAgaGFzWj86IGJvb2xlYW47XG4gIGhhc0lkcz86IGJvb2xlYW47XG4gIHJhZGl1cz86IFNwYXRpYWxSYWRpdXNTcGVjO1xuICBjb2x1bW5zOiBTcGF0aWFsQ29sdW1uTWV0YVtdO1xuICBmZWF0dXJlcz86IFNwYXRpYWxGZWF0dXJlTWV0YTtcbiAgcG9seWdvbnM/OiB7IGNvdW50OiBudW1iZXIgfTtcbiAgaW1hZ2VSZWY/OiBTcGF0aWFsSW1hZ2VSZWY7XG4gIHZvbHVtZT86IFNwYXRpYWxWb2x1bWVNZXRhO1xuICBlbWJlZGRpbmdzPzogU3BhdGlhbEVtYmVkZGluZ01ldGFbXTtcbiAgbWljcm9uc1BlclVuaXQ/OiBudW1iZXI7XG59XG5cbi8qKiBgR0VUIC9zcGF0aWFsL2RhdGFzZXRzYCAqL1xuZXhwb3J0IGludGVyZmFjZSBTcGF0aWFsRGF0YXNldFN1bW1hcnkge1xuICBpZDogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIGNvdW50OiBudW1iZXI7XG59XG5cbi8qKiBUcnVlIG9uIGEgbGl0dGxlLWVuZGlhbiBob3N0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzTGl0dGxlRW5kaWFuKCk6IGJvb2xlYW4ge1xuICBjb25zdCBwcm9iZSA9IG5ldyBVaW50MTZBcnJheShbMV0pO1xuICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkocHJvYmUuYnVmZmVyKVswXSA9PT0gMTtcbn1cblxuZnVuY3Rpb24gYXNzZXJ0TGl0dGxlRW5kaWFuKCk6IHZvaWQge1xuICBpZiAoIWlzTGl0dGxlRW5kaWFuKCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnW3NwYXRpYWxdIHdpcmUgZm9ybWF0IGlzIGxpdHRsZS1lbmRpYW47IHRoaXMgcGxhdGZvcm0gaXMgYmlnLWVuZGlhbi4gJyArXG4gICAgICAnU2VydmUgSlNPTiB2ZWN0b3JzLCBvciBieXRlLXN3YXAgaW4gYSBjdXN0b20gU3BhdGlhbERhdGFQb3J0IGFkYXB0ZXIuJyxcbiAgICApO1xuICB9XG59XG5cbi8qKiBHdWFyZCBhIGRlY29kZSBhZ2FpbnN0IGEgdHJ1bmNhdGVkIG9yIG92ZXJzaXplZCByZXNwb25zZS4gKi9cbmZ1bmN0aW9uIGFzc2VydEJ5dGVMZW5ndGgoYnVmOiBBcnJheUJ1ZmZlciwgZXhwZWN0ZWQ6IG51bWJlciwgd2hhdDogc3RyaW5nKTogdm9pZCB7XG4gIGlmIChidWYuYnl0ZUxlbmd0aCAhPT0gZXhwZWN0ZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgW3NwYXRpYWxdICR7d2hhdH06IGV4cGVjdGVkICR7ZXhwZWN0ZWR9IGJ5dGVzLCBnb3QgJHtidWYuYnl0ZUxlbmd0aH0uIGAgK1xuICAgICAgJ01hbmlmZXN0IGNvdW50IGFuZCBzZXJ2ZWQgdmVjdG9yIGxlbmd0aCBkaXNhZ3JlZS4nLFxuICAgICk7XG4gIH1cbn1cblxuLyoqIFJlamVjdCBhIG1hbmlmZXN0IHRoaXMgY2xpZW50IGNhbm5vdCByZWFkLCB3aXRoIGEgbWVzc2FnZSBuYW1pbmcgdGhlIGZpeC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhc3NlcnRNYW5pZmVzdFZlcnNpb24obWFuaWZlc3Q6IFNwYXRpYWxNYW5pZmVzdCk6IHZvaWQge1xuICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gU1BBVElBTF9XSVJFX1ZFUlNJT04pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgW3NwYXRpYWxdIHVuc3VwcG9ydGVkIHdpcmUgdmVyc2lvbiAke21hbmlmZXN0LnZlcnNpb259IGAgK1xuICAgICAgYCh0aGlzIGNsaWVudCBzcGVha3MgJHtTUEFUSUFMX1dJUkVfVkVSU0lPTn0pLiBVcGRhdGUgdGhlIHNlcnZlciBvciB0aGUgbGlicmFyeS5gLFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBgR0VUIC9jb29yZHNgIOKGkiB4L3koL3opLiBPbmUgcmVxdWVzdCByYXRoZXIgdGhhbiB0d28gb3IgdGhyZWU6IHRoZSB2ZWN0b3JzXG4gKiBhcmUgYWx3YXlzIGZldGNoZWQgdG9nZXRoZXIsIGFuZCBhIHNpbmdsZSByZXNwb25zZSBrZWVwcyB0aGVtIGNvbnNpc3RlbnQgaWZcbiAqIHRoZSBkYXRhc2V0IGNoYW5nZXMgdW5kZXJuZWF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZUNvb3JkcyhcbiAgYnVmOiBBcnJheUJ1ZmZlciwgY291bnQ6IG51bWJlciwgaGFzWiA9IGZhbHNlLFxuKTogUGljazxTcGF0aWFsT2JzZXJ2YXRpb25zLCAneCcgfCAneScgfCAneic+IHtcbiAgYXNzZXJ0TGl0dGxlRW5kaWFuKCk7XG4gIGNvbnN0IGF4ZXMgPSBoYXNaID8gMyA6IDI7XG4gIGFzc2VydEJ5dGVMZW5ndGgoYnVmLCBjb3VudCAqIGF4ZXMgKiA0LCAnY29vcmRzJyk7XG4gIGNvbnN0IHggPSBuZXcgRmxvYXQzMkFycmF5KGJ1ZiwgMCwgY291bnQpO1xuICBjb25zdCB5ID0gbmV3IEZsb2F0MzJBcnJheShidWYsIGNvdW50ICogNCwgY291bnQpO1xuICBjb25zdCB6ID0gaGFzWiA/IG5ldyBGbG9hdDMyQXJyYXkoYnVmLCBjb3VudCAqIDgsIGNvdW50KSA6IHVuZGVmaW5lZDtcbiAgcmV0dXJuIHsgeCwgeSwgeiB9O1xufVxuXG4vKiogYEdFVCAvcmFkaXVzYCDihpIgcGVyLW9ic2VydmF0aW9uIHJhZGlpIGluIGltYWdlIHBpeGVscy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWNvZGVSYWRpdXMoYnVmOiBBcnJheUJ1ZmZlciwgY291bnQ6IG51bWJlcik6IEZsb2F0MzJBcnJheSB7XG4gIGFzc2VydExpdHRsZUVuZGlhbigpO1xuICBhc3NlcnRCeXRlTGVuZ3RoKGJ1ZiwgY291bnQgKiA0LCAncmFkaXVzJyk7XG4gIHJldHVybiBuZXcgRmxvYXQzMkFycmF5KGJ1ZiwgMCwgY291bnQpO1xufVxuXG4vKiogYEdFVCAvZmVhdHVyZS97bmFtZX1gIOKGkiBvbmUgZ2VuZSdzIGV4cHJlc3Npb24gdmVjdG9yLiAqL1xuLyoqXG4gKiBgR0VUIC9zcGF0aWFsL3tpZH0vZW1iZWRkaW5nL3tuYW1lfWAg4oCUIG9uZSBwbGFuZSBwZXIgZGltZW5zaW9uLCBzYW1lIGxheW91dCBhcyBjb29yZHMuXG4gKlxuICogU3RydWN0IG9mIGFycmF5cywgbm90IGludGVybGVhdmVkOiBldmVyeSBkaW1lbnNpb24gaXMgY29udGlndW91cywgc28gYW4gYXhpcyBjYW4gYmUgaGFuZGVkIHRvXG4gKiB0aGUgcmVuZGVyZXIgYXMgYSB2aWV3IHdpdGggbm8gY29weSBhbmQgbm8gc3RyaWRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVjb2RlRW1iZWRkaW5nKFxuICBidWY6IEFycmF5QnVmZmVyLCBtZXRhOiBTcGF0aWFsRW1iZWRkaW5nTWV0YSwgY291bnQ6IG51bWJlcixcbik6IFNwYXRpYWxFbWJlZGRpbmcge1xuICBhc3NlcnRMaXR0bGVFbmRpYW4oKTtcbiAgYXNzZXJ0Qnl0ZUxlbmd0aChidWYsIGNvdW50ICogbWV0YS5kaW1zICogNCwgYGVtYmVkZGluZyBcIiR7bWV0YS5uYW1lfVwiYCk7XG4gIHJldHVybiB7XG4gICAgbWV0YSxcbiAgICB4OiBuZXcgRmxvYXQzMkFycmF5KGJ1ZiwgMCwgY291bnQpLFxuICAgIHk6IG5ldyBGbG9hdDMyQXJyYXkoYnVmLCBjb3VudCAqIDQsIGNvdW50KSxcbiAgICAuLi4obWV0YS5kaW1zID09PSAzID8geyB6OiBuZXcgRmxvYXQzMkFycmF5KGJ1ZiwgY291bnQgKiA4LCBjb3VudCkgfSA6IHt9KSxcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZUZlYXR1cmVWZWN0b3IoYnVmOiBBcnJheUJ1ZmZlciwgY291bnQ6IG51bWJlcik6IEZsb2F0MzJBcnJheSB7XG4gIGFzc2VydExpdHRsZUVuZGlhbigpO1xuICBhc3NlcnRCeXRlTGVuZ3RoKGJ1ZiwgY291bnQgKiA0LCAnZmVhdHVyZSB2ZWN0b3InKTtcbiAgcmV0dXJuIG5ldyBGbG9hdDMyQXJyYXkoYnVmLCAwLCBjb3VudCk7XG59XG5cbi8qKlxuICogYEdFVCAvY29sdW1uL3tuYW1lfWAg4oaSIGEgbG9hZGVkIGNvbHVtbiwgdHlwZWQgYnkgaXRzIGRlc2NyaXB0b3I6IGB1MTZgIGNvZGVzXG4gKiBmb3IgYSBjYXRlZ29yaWNhbCwgYGYzMmAgdmFsdWVzIGZvciBhIGNvbnRpbnVvdXMuIENvZGVzIG91dHNpZGUgdGhlIGNhdGVnb3J5XG4gKiBsaXN0IGFyZSBub3JtYWxpc2VkIHRvIHtAbGluayBOT19DQVRFR09SWX0gc28gYSByZW5kZXJlciBjYW4gdHJ1c3QgdGhlXG4gKiBpbnZhcmlhbnQgaW5zdGVhZCBvZiBib3VuZHMtY2hlY2tpbmcgZXZlcnkgcG9pbnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWNvZGVDb2x1bW4oXG4gIGJ1ZjogQXJyYXlCdWZmZXIsIG1ldGE6IFNwYXRpYWxDb2x1bW5NZXRhLCBjb3VudDogbnVtYmVyLFxuKTogU3BhdGlhbENvbHVtbiB7XG4gIGFzc2VydExpdHRsZUVuZGlhbigpO1xuICBpZiAobWV0YS5raW5kID09PSAnY2F0ZWdvcmljYWwnKSB7XG4gICAgYXNzZXJ0Qnl0ZUxlbmd0aChidWYsIGNvdW50ICogMiwgYGNvbHVtbiBcIiR7bWV0YS5uYW1lfVwiYCk7XG4gICAgY29uc3QgY29kZXMgPSBuZXcgVWludDE2QXJyYXkoYnVmLCAwLCBjb3VudCk7XG4gICAgY29uc3QgbiA9IChtZXRhIGFzIENhdGVnb3JpY2FsQ29sdW1uTWV0YSkuY2F0ZWdvcmllcy5sZW5ndGg7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2Rlcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGNvZGVzW2ldID49IG4pIGNvZGVzW2ldID0gTk9fQ0FURUdPUlk7XG4gICAgfVxuICAgIHJldHVybiB7IG1ldGE6IG1ldGEgYXMgQ2F0ZWdvcmljYWxDb2x1bW5NZXRhLCBjb2RlcyB9O1xuICB9XG4gIGFzc2VydEJ5dGVMZW5ndGgoYnVmLCBjb3VudCAqIDQsIGBjb2x1bW4gXCIke21ldGEubmFtZX1cImApO1xuICByZXR1cm4geyBtZXRhOiBtZXRhIGFzIENvbnRpbnVvdXNDb2x1bW5NZXRhLCB2YWx1ZXM6IG5ldyBGbG9hdDMyQXJyYXkoYnVmLCAwLCBjb3VudCkgfTtcbn1cblxuLyoqXG4gKiBgR0VUIC9wb2x5Z29uc2Ag4oaSIGJvdW5kYXJ5IHJpbmdzLiBMYXlvdXQgaXNcbiAqIGBbdTMyIGNvdW50XVt1MzIgb2Zmc2V0cyDDlyAoY291bnQrMSldW2YzMiBjb29yZHMgw5cgMsK3b2Zmc2V0c1tjb3VudF1dYDsgZXZlcnlcbiAqIGZpZWxkIGlzIDQtYnl0ZSB3aWRlIHNvIGVhY2ggdHlwZWQtYXJyYXkgdmlldyBzdGF5cyBhbGlnbmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVjb2RlUG9seWdvbnMoYnVmOiBBcnJheUJ1ZmZlcik6IFNwYXRpYWxQb2x5Z29ucyB7XG4gIGFzc2VydExpdHRsZUVuZGlhbigpO1xuICBpZiAoYnVmLmJ5dGVMZW5ndGggPCA4KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdbc3BhdGlhbF0gcG9seWdvbnM6IHJlc3BvbnNlIHRvbyBzaG9ydCBmb3IgYSBoZWFkZXInKTtcbiAgfVxuICBjb25zdCBjb3VudCA9IG5ldyBVaW50MzJBcnJheShidWYsIDAsIDEpWzBdO1xuICBjb25zdCBvZmZzZXRzID0gbmV3IFVpbnQzMkFycmF5KGJ1ZiwgNCwgY291bnQgKyAxKTtcbiAgY29uc3QgdmVydGV4Q291bnQgPSBvZmZzZXRzW2NvdW50XTtcbiAgY29uc3QgY29vcmRzQnl0ZU9mZnNldCA9IDQgKyAoY291bnQgKyAxKSAqIDQ7XG4gIGFzc2VydEJ5dGVMZW5ndGgoYnVmLCBjb29yZHNCeXRlT2Zmc2V0ICsgdmVydGV4Q291bnQgKiAyICogNCwgJ3BvbHlnb25zJyk7XG4gIGNvbnN0IGNvb3JkcyA9IG5ldyBGbG9hdDMyQXJyYXkoYnVmLCBjb29yZHNCeXRlT2Zmc2V0LCB2ZXJ0ZXhDb3VudCAqIDIpO1xuICByZXR1cm4geyBjb29yZHMsIG9mZnNldHMsIGNvdW50IH07XG59XG5cbi8qKlxuICogRm9sZCBhIG1hbmlmZXN0IHBsdXMgaXRzIGZldGNoZWQgY29vcmRpbmF0ZS9pZC9yYWRpdXMgdmVjdG9ycyBpbnRvIHRoZVxuICogbGlicmFyeS1mYWNpbmcge0BsaW5rIFNwYXRpYWxEYXRhc2V0fS4gQ29sdW1uIGFuZCBmZWF0dXJlICp2YWx1ZXMqIGFyZSBub3RcbiAqIHBhcnQgb2YgdGhpcyDigJQgdGhleSBzdGF5IGxhenkgYmVoaW5kIHRoZSBwb3J0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGF0YXNldEZyb21NYW5pZmVzdChcbiAgbWFuaWZlc3Q6IFNwYXRpYWxNYW5pZmVzdCxcbiAgY29vcmRzOiBQaWNrPFNwYXRpYWxPYnNlcnZhdGlvbnMsICd4JyB8ICd5JyB8ICd6Jz4sXG4gIGV4dHJhczogeyBpZHM/OiBzdHJpbmdbXTsgcmFkaXVzPzogRmxvYXQzMkFycmF5IH0gPSB7fSxcbik6IFNwYXRpYWxEYXRhc2V0IHtcbiAgYXNzZXJ0TWFuaWZlc3RWZXJzaW9uKG1hbmlmZXN0KTtcbiAgY29uc3QgcmFkaXVzID0gbWFuaWZlc3QucmFkaXVzPy5tb2RlID09PSAndW5pZm9ybSdcbiAgICA/IG1hbmlmZXN0LnJhZGl1cy52YWx1ZVxuICAgIDogZXh0cmFzLnJhZGl1cztcbiAgY29uc3Qgb2JzZXJ2YXRpb25zOiBTcGF0aWFsT2JzZXJ2YXRpb25zID0ge1xuICAgIGNvdW50OiBtYW5pZmVzdC5jb3VudCxcbiAgICB4OiBjb29yZHMueCxcbiAgICB5OiBjb29yZHMueSxcbiAgICAuLi4oY29vcmRzLnogPyB7IHo6IGNvb3Jkcy56IH0gOiB7fSksXG4gICAgLi4uKGV4dHJhcy5pZHMgPyB7IGlkczogZXh0cmFzLmlkcyB9IDoge30pLFxuICAgIC4uLihyYWRpdXMgIT09IHVuZGVmaW5lZCA/IHsgcmFkaXVzIH0gOiB7fSksXG4gIH07XG4gIHJldHVybiB7XG4gICAgaWQ6IG1hbmlmZXN0LmlkLFxuICAgIG5hbWU6IG1hbmlmZXN0Lm5hbWUsXG4gICAgb2JzZXJ2YXRpb25zLFxuICAgIGNvbHVtbnM6IG1hbmlmZXN0LmNvbHVtbnMgPz8gW10sXG4gICAgLi4uKG1hbmlmZXN0LmZlYXR1cmVzID8geyBmZWF0dXJlczogbWFuaWZlc3QuZmVhdHVyZXMgfSA6IHt9KSxcbiAgICAuLi4obWFuaWZlc3QucG9seWdvbnMgPyB7IHBvbHlnb25zOiBtYW5pZmVzdC5wb2x5Z29ucyB9IDoge30pLFxuICAgIC4uLihtYW5pZmVzdC5pbWFnZVJlZiA/IHsgaW1hZ2VSZWY6IG1hbmlmZXN0LmltYWdlUmVmIH0gOiB7fSksXG4gICAgLi4uKG1hbmlmZXN0LnZvbHVtZSA/IHsgdm9sdW1lOiBtYW5pZmVzdC52b2x1bWUgfSA6IHt9KSxcbiAgICAuLi4obWFuaWZlc3QuZW1iZWRkaW5ncz8ubGVuZ3RoID8geyBlbWJlZGRpbmdzOiBtYW5pZmVzdC5lbWJlZGRpbmdzIH0gOiB7fSksXG4gICAgLi4uKG1hbmlmZXN0Lm1pY3JvbnNQZXJVbml0ICE9PSB1bmRlZmluZWRcbiAgICAgID8geyBtaWNyb25zUGVyVW5pdDogbWFuaWZlc3QubWljcm9uc1BlclVuaXQgfVxuICAgICAgOiB7fSksXG4gIH07XG59XG4iXX0=