@jax-data-science/sci-image-visualizer 0.3.2 → 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 (93) hide show
  1. package/README.md +215 -11
  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/segmentation/cellpose-segmenter.service.mjs +2 -2
  41. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +9 -9
  42. package/esm2022/lib/toolbar/toolbar.component.mjs +30 -7
  43. package/esm2022/lib/visualization.module.mjs +23 -5
  44. package/esm2022/lib/visualizer.component.mjs +283 -22
  45. 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
  46. 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
  47. package/fesm2022/jax-data-science-sci-image-visualizer-tsne-worker-B_nXDGf0.mjs +12 -0
  48. package/fesm2022/jax-data-science-sci-image-visualizer-tsne-worker-B_nXDGf0.mjs.map +1 -0
  49. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +15282 -7829
  50. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  51. package/fesm2022/tsne.worker.js +19091 -0
  52. package/index.d.ts +15 -0
  53. package/lib/contracts/display-types.d.ts +131 -0
  54. package/lib/contracts/image.contract.d.ts +7 -0
  55. package/lib/contracts/plot-type.d.ts +42 -2
  56. package/lib/contracts/ports/spatial-data.port.d.ts +90 -0
  57. package/lib/contracts/spatial-dataset.contract.d.ts +281 -0
  58. package/lib/contracts/visualizer.contract.d.ts +99 -1
  59. package/lib/implementations/napari-js/napari-axes-labels.d.ts +9 -7
  60. package/lib/implementations/napari-js/napari-region-overlay.d.ts +38 -4
  61. package/lib/implementations/napari-js/napari-scale-bar.d.ts +7 -3
  62. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +32 -0
  63. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +497 -16
  64. package/lib/implementations/napari-js/napari-zoom.d.ts +15 -0
  65. package/lib/implementations/osd/osd-zoom.d.ts +19 -0
  66. package/lib/implementations/plotly/omics-trace-builders.d.ts +193 -0
  67. package/lib/implementations/plotly/plotly.service.d.ts +9 -0
  68. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +123 -0
  69. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +115 -0
  70. package/lib/routing-visualizer.service.d.ts +45 -6
  71. package/lib/spatial/embedding-compute.d.ts +73 -0
  72. package/lib/spatial/gene-search.d.ts +48 -0
  73. package/lib/spatial/spatial-density.d.ts +73 -0
  74. package/lib/spatial/spatial-encoding.d.ts +155 -0
  75. package/lib/spatial/spatial-expression.d.ts +144 -0
  76. package/lib/spatial/spatial-framing.d.ts +37 -0
  77. package/lib/spatial/spatial-heatmap.d.ts +111 -0
  78. package/lib/spatial/spatial-hover.d.ts +49 -0
  79. package/lib/spatial/spatial-sections.d.ts +59 -0
  80. package/lib/spatial/spatial-selection.d.ts +113 -0
  81. package/lib/spatial/spatial-volume-image.d.ts +67 -0
  82. package/lib/spatial/tsne-worker.d.ts +7 -0
  83. package/lib/spatial/world-grid.d.ts +58 -0
  84. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +439 -0
  85. package/lib/spatial-controls/spatial-controls.component.d.ts +257 -0
  86. package/lib/store/spatial-selection.service.d.ts +27 -0
  87. package/lib/store/visualizer-store.service.d.ts +13 -0
  88. package/lib/toolbar/toolbar.component.d.ts +19 -3
  89. package/lib/visualization.module.d.ts +28 -24
  90. package/lib/visualizer.component.d.ts +73 -2
  91. package/package.json +7 -3
  92. package/src/lib/assets/spatial-omics-3d.svg +31 -0
  93. package/src/lib/assets/spatial-omics.svg +27 -0
@@ -0,0 +1,232 @@
1
+ import { buildColormapLut } from '../contracts/colormap-lut';
2
+ import { fallbackColorFor } from '../store/class-color.util';
3
+ import { NO_CATEGORY, } from '../contracts/spatial-dataset.contract';
4
+ /** Neutral grey for observations with no value (NaN, or {@link NO_CATEGORY}). */
5
+ export const MISSING_COLOR = [150, 150, 150];
6
+ /** Default alpha for muted (background / unselected) points — CosMx-style context. */
7
+ export const DEFAULT_MUTED_OPACITY = 0.15;
8
+ /**
9
+ * Largest number of CATEGORIES whose colours survive the 3D points layer's LUT
10
+ * intact.
11
+ *
12
+ * That layer has no per-point RGBA — it maps a per-point SCALAR through a
13
+ * 256-entry colormap LUT — so a categorical palette is encoded as one contiguous
14
+ * block of LUT entries per value. Measured against napari-js, every K in 2..96
15
+ * blocks round-trips exactly and K=97 is the first that does not: 256 texels
16
+ * cannot keep more values apart than that.
17
+ *
18
+ * One of those 96 blocks is spent on {@link NO_CATEGORY}, which every column can
19
+ * contain, so what fits is **95 categories** — the number published here. It was
20
+ * 96 while the encoder rejected at 96, which meant a 96-category column drew flat
21
+ * with the panel showing no warning: the one failure this ceiling exists to
22
+ * prevent, arrived at from the other direction.
23
+ *
24
+ * Above it the cloud draws FLAT rather than draw a lie, because subtly wrong
25
+ * category colours under a confident legend is the failure nobody catches.
26
+ *
27
+ * A limit of that one layer, and of nothing else: the 2D markers carry per-point
28
+ * RGBA, and a density volume is a scalar field per cluster. Shared here so the
29
+ * renderer that enforces it and the panel that explains it cannot drift apart.
30
+ */
31
+ export const SPATIAL_3D_MAX_CATEGORIES = 95;
32
+ /** LUT blocks the 3D layer can keep apart — {@link SPATIAL_3D_MAX_CATEGORIES}
33
+ * plus the one reserved for a missing value. */
34
+ export const SPATIAL_3D_LUT_BLOCKS = SPATIAL_3D_MAX_CATEGORIES + 1;
35
+ /**
36
+ * Fallback categorical palette. Colour-blind-safe and stable, so a category
37
+ * without an authored colour still lands somewhere sensible and lands there
38
+ * every run (`fallbackColorFor` hashes the name — same name, same colour).
39
+ * Okabe–Ito, plus two greys for long tails.
40
+ */
41
+ export const DEFAULT_CATEGORICAL_PALETTE = [
42
+ '#0072B2', '#E69F00', '#009E73', '#CC79A7', '#56B4E9',
43
+ '#D55E00', '#F0E442', '#000000', '#7F7F7F', '#BFBFBF',
44
+ ];
45
+ /** Parse `#rgb` / `#rrggbb` to 0–255 RGB; unparseable input falls back to grey.
46
+ * Exported so the 3D LUT path parses palettes exactly as the 2D path does. */
47
+ export function parseHex(hex) {
48
+ const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec((hex ?? '').trim());
49
+ if (!m)
50
+ return MISSING_COLOR;
51
+ let h = m[1];
52
+ if (h.length === 3)
53
+ h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
54
+ return [
55
+ parseInt(h.slice(0, 2), 16),
56
+ parseInt(h.slice(2, 4), 16),
57
+ parseInt(h.slice(4, 6), 16),
58
+ ];
59
+ }
60
+ function alphaAt(i, opts) {
61
+ const on = opts.opacity ?? 1;
62
+ const off = opts.mutedOpacity ?? DEFAULT_MUTED_OPACITY;
63
+ return opts.muted && opts.muted[i] ? off : on;
64
+ }
65
+ /**
66
+ * Per-category colours: the column's authored `colors` where present (so the
67
+ * viewer matches the figures the same analysis produced elsewhere), otherwise
68
+ * the palette by position, wrapping through a name-hash past its end so a
69
+ * 40-cluster column still gets stable, distinct-ish colours.
70
+ */
71
+ export function resolveCategoryColors(meta, palette = DEFAULT_CATEGORICAL_PALETTE) {
72
+ const authored = meta.colors;
73
+ return meta.categories.map((name, i) => {
74
+ const given = authored?.[i];
75
+ if (given)
76
+ return given;
77
+ if (i < palette.length)
78
+ return palette[i];
79
+ return fallbackColorFor(name, palette);
80
+ });
81
+ }
82
+ /** Categorical column → flat per-point RGBA (length `4 * codes.length`). */
83
+ export function encodeCategorical(codes, opts) {
84
+ const n = codes.length;
85
+ const out = new Float32Array(n * 4);
86
+ // Resolve each category once — parsing a hex string per point would dominate.
87
+ const rgb = opts.colors.map(parseHex);
88
+ const missing = opts.missingColor ?? MISSING_COLOR;
89
+ for (let i = 0; i < n; i++) {
90
+ const code = codes[i];
91
+ const c = code === NO_CATEGORY || code >= rgb.length ? missing : rgb[code];
92
+ const o = i * 4;
93
+ out[o] = c[0] / 255;
94
+ out[o + 1] = c[1] / 255;
95
+ out[o + 2] = c[2] / 255;
96
+ // A point with no category is background by definition — never emphasised.
97
+ out[o + 3] = code === NO_CATEGORY
98
+ ? Math.min(alphaAt(i, opts), opts.mutedOpacity ?? DEFAULT_MUTED_OPACITY)
99
+ : alphaAt(i, opts);
100
+ }
101
+ return out;
102
+ }
103
+ /** Continuous column / gene vector → flat per-point RGBA. */
104
+ export function encodeContinuous(values, opts) {
105
+ const n = values.length;
106
+ const out = new Float32Array(n * 4);
107
+ const missing = opts.missingColor ?? MISSING_COLOR;
108
+ const lut = opts.lut;
109
+ const lo = opts.log ? Math.log1p(Math.max(0, opts.min)) : opts.min;
110
+ const hi = opts.log ? Math.log1p(Math.max(0, opts.max)) : opts.max;
111
+ // A degenerate window (all values equal) maps everything to the LUT midpoint
112
+ // rather than dividing by zero.
113
+ const span = hi - lo;
114
+ for (let i = 0; i < n; i++) {
115
+ const raw = values[i];
116
+ const o = i * 4;
117
+ if (!Number.isFinite(raw)) {
118
+ out[o] = missing[0] / 255;
119
+ out[o + 1] = missing[1] / 255;
120
+ out[o + 2] = missing[2] / 255;
121
+ out[o + 3] = opts.mutedOpacity ?? DEFAULT_MUTED_OPACITY;
122
+ continue;
123
+ }
124
+ const v = opts.log ? Math.log1p(Math.max(0, raw)) : raw;
125
+ const t = span > 0 ? (v - lo) / span : 0.5;
126
+ const idx = Math.max(0, Math.min(255, Math.round(t * 255)));
127
+ const c = lut[idx] ?? missing;
128
+ out[o] = c[0] / 255;
129
+ out[o + 1] = c[1] / 255;
130
+ out[o + 2] = c[2] / 255;
131
+ out[o + 3] = alphaAt(i, opts);
132
+ }
133
+ return out;
134
+ }
135
+ /**
136
+ * Contrast window from percentiles of the finite values — the CosMx
137
+ * "cap outliers at percentiles to improve contrast" rule. `lo`/`hi` are
138
+ * fractions (0.01 / 0.99 clips the extreme 1% at each end).
139
+ *
140
+ * Returns `[0, 1]` for an empty or all-missing vector so callers always get a
141
+ * usable window.
142
+ */
143
+ export function contrastWindow(values, lo = 0.01, hi = 0.99) {
144
+ const finite = [];
145
+ for (let i = 0; i < values.length; i++) {
146
+ if (Number.isFinite(values[i]))
147
+ finite.push(values[i]);
148
+ }
149
+ if (finite.length === 0)
150
+ return [0, 1];
151
+ finite.sort((a, b) => a - b);
152
+ const at = (f) => {
153
+ const k = Math.max(0, Math.min(finite.length - 1, Math.round(f * (finite.length - 1))));
154
+ return finite[k];
155
+ };
156
+ const min = at(Math.max(0, Math.min(1, lo)));
157
+ const max = at(Math.max(0, Math.min(1, hi)));
158
+ // A flat or inverted window would divide by zero downstream; widen it.
159
+ return max > min ? [min, max] : [min, min + 1];
160
+ }
161
+ /**
162
+ * Marker sizes for the points layer. napari-js `PointsLayer.size` is a
163
+ * **diameter** in data units while `SpatialObservations.radius` is a radius —
164
+ * the doubling lives here so no call site has to remember it.
165
+ *
166
+ * `fallbackRadius` covers a dataset that declares no radius (segmented cells
167
+ * often don't); it is in image pixels, like everything else in this space.
168
+ */
169
+ export function markerDiameters(observations, fallbackRadius = 4) {
170
+ const r = observations.radius;
171
+ if (typeof r === 'number')
172
+ return r * 2;
173
+ if (r instanceof Float32Array) {
174
+ const out = new Float32Array(r.length);
175
+ for (let i = 0; i < r.length; i++)
176
+ out[i] = r[i] * 2;
177
+ return out;
178
+ }
179
+ return fallbackRadius * 2;
180
+ }
181
+ /**
182
+ * Adapt a flat RGBA buffer to the `RGBA[]` shape napari-js 0.12.0's
183
+ * `PointsLayer.faceColor` accepts. One 4-element array per point — the reason
184
+ * this is a named boundary rather than inlined: it is the one place the model
185
+ * stops being typed-array shaped, and it is what a future napari-js taking a
186
+ * `Float32Array` would delete.
187
+ */
188
+ export function toRgbaTuples(flat) {
189
+ const n = flat.length / 4;
190
+ const out = new Array(n);
191
+ for (let i = 0; i < n; i++) {
192
+ const o = i * 4;
193
+ out[i] = [flat[o], flat[o + 1], flat[o + 2], flat[o + 3]];
194
+ }
195
+ return out;
196
+ }
197
+ /** Convenience: a 256-entry LUT for a colormap value, falling back to Viridis. */
198
+ export function lutFor(colormapValue, reverse = false) {
199
+ return buildColormapLut(colormapValue, reverse)
200
+ ?? buildColormapLut('Viridis', reverse);
201
+ }
202
+ /** True when every entry of a LUT is a neutral grey. Tested on the VALUES rather
203
+ * than the colormap's name, so a reversed or renamed grey ramp still counts. */
204
+ export function isGrayscaleLut(lut) {
205
+ return lut.every(([r, g, b]) => r === g && g === b);
206
+ }
207
+ /**
208
+ * LUT for a spatial CONTINUOUS encoding — a gene, a numeric column.
209
+ *
210
+ * `override` is the caller's explicit choice and wins outright, grey included: a
211
+ * grey ramp picked FOR the data is a decision, not the image's colormap leaking
212
+ * in.
213
+ *
214
+ * Without one, the display colormap — unless that colormap is grayscale. The
215
+ * tissue underneath is grayscale, so a grey overlay of a measurement is
216
+ * indistinguishable from the anatomy it is drawn over, and the reader cannot tell
217
+ * which channel a bright pixel belongs to. Viridis is then the fallback, which is
218
+ * what the CosMx guidance prescribes for continuous values anyway.
219
+ *
220
+ * Shared by the markers, both gene maps and the panel's colour bar, so none of
221
+ * them can disagree about what a colour means, whichever way the choice falls.
222
+ */
223
+ export function spatialContinuousLut(colormapValue, reverse = false, override) {
224
+ // An inline scale is an array, so emptiness has to be checked as well as
225
+ // presence: `[]` is truthy and would resolve to the fallback LUT silently.
226
+ const chosen = Array.isArray(override) ? (override.length ? override : null) : override;
227
+ if (chosen)
228
+ return lutFor(chosen, reverse);
229
+ const lut = lutFor(colormapValue, reverse);
230
+ return isGrayscaleLut(lut) ? buildColormapLut('Viridis', reverse) : lut;
231
+ }
232
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1lbmNvZGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC9zcGF0aWFsLWVuY29kaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBTyxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzdELE9BQU8sRUFDa0IsV0FBVyxHQUNuQyxNQUFNLHVDQUF1QyxDQUFDO0FBK0IvQyxpRkFBaUY7QUFDakYsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFRLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztBQUVsRCxzRkFBc0Y7QUFDdEYsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDO0FBRTFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBQ0gsTUFBTSxDQUFDLE1BQU0seUJBQXlCLEdBQUcsRUFBRSxDQUFDO0FBRTVDO2lEQUNpRDtBQUNqRCxNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyx5QkFBeUIsR0FBRyxDQUFDLENBQUM7QUFFbkU7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsTUFBTSwyQkFBMkIsR0FBYTtJQUNuRCxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUztJQUNyRCxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUztDQUN0RCxDQUFDO0FBOEJGOytFQUMrRTtBQUMvRSxNQUFNLFVBQVUsUUFBUSxDQUFDLEdBQVc7SUFDbEMsTUFBTSxDQUFDLEdBQUcsZ0NBQWdDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDcEUsSUFBSSxDQUFDLENBQUM7UUFBRSxPQUFPLGFBQWEsQ0FBQztJ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TUFBTSxDQUFDLGFBQXNCLEVBQUUsT0FBTyxHQUFHLEtBQUs7SUFDNUQsT0FBTyxnQkFBZ0IsQ0FBQyxhQUFhLEVBQUUsT0FBTyxDQUFDO1dBQzFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUUsQ0FBQztBQUM3QyxDQUFDO0FBRUQ7aUZBQ2lGO0FBQ2pGLE1BQU0sVUFBVSxjQUFjLENBQUMsR0FBbUI7SUFDaEQsT0FBTyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUN0RCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUNsQyxhQUFzQixFQUFFLE9BQU8sR0FBRyxLQUFLLEVBQUUsUUFBK0I7SUFFeEUseUVBQXlFO0lBQ3pFLDJFQUEyRTtJQUMzRSxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztJQUN4RixJQUFJLE1BQU07UUFBRSxPQUFPLE1BQU0sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDM0MsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLGFBQWEsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUMzQyxPQUFPLGNBQWMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7QUFDM0UsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJnYiwgYnVpbGRDb2xvcm1hcEx1dCB9IGZyb20gJy4uL2NvbnRyYWN0cy9jb2xvcm1hcC1sdXQnO1xuaW1wb3J0IHsgZmFsbGJhY2tDb2xvckZvciB9IGZyb20gJy4uL3N0b3JlL2NsYXNzLWNvbG9yLnV0aWwnO1xuaW1wb3J0IHtcbiAgQ2F0ZWdvcmljYWxDb2x1bW5NZXRhLCBOT19DQVRFR09SWSwgU3BhdGlhbE9ic2VydmF0aW9ucyxcbn0gZnJvbSAnLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQgeyBDb2xvcm1hcFZhbHVlIH0gZnJvbSAnLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuXG4vKipcbiAqIFR1cm5pbmcgc3BhdGlhbC1vbWljcyBjb2x1bW5zIGludG8gcGVyLXBvaW50IHZpc3VhbCBhdHRyaWJ1dGVzLlxuICpcbiAqIFB1cmUg4oCUIG5vIEFuZ3VsYXIsIG5vIFJ4SlMsIG5vIHJlbmRlcmVyIOKAlCBsaWtlIGBwbG90bHktdHJhY2UtYnVpbGRlcnMudHNgLCBzb1xuICogdGhlIGVuY29kaW5ncyBhcmUgdGVzdGFibGUgb24gdGhlaXIgb3duIGFuZCBzaGFyZWQgYnkgYW55IGJhY2tlbmQgdGhhdCBncm93c1xuICogYSBzcGF0aWFsIG1vZGUuXG4gKlxuICogVGhlIHJ1bGVzIGhlcmUgYXJlIHRoZSBvbmVzIHRoZSBDb3NNeCBhbmFseXNpcyBndWlkYW5jZSBwcmVzY3JpYmVzLCBtYWRlXG4gKiBleHBsaWNpdCByYXRoZXIgdGhhbiBsZWZ0IHRvIGVhY2ggY2FsbCBzaXRlOlxuICogIC0gY291bnQtbGlrZSBjb2x1bW5zIHJlYWQgb24gYSAqKmxvZyoqIHNjYWxlIChsaW5lYXIgY29sbGFwc2VzIHRoZW0gYWdhaW5zdCBhXG4gKiAgICBmZXcgYnJpZ2h0IG91dGxpZXJzKTtcbiAqICAtIGNvbnRyYXN0IHdpbmRvd3MgY29tZSBmcm9tICoqcGVyY2VudGlsZXMqKiwgbm90IG1pbi9tYXgsIHNvIGEgc2luZ2xlXG4gKiAgICBzYXR1cmF0ZWQgc3BvdCBkb2Vzbid0IGZsYXR0ZW4gZXZlcnl0aGluZyBlbHNlO1xuICogIC0gY29udGV4dCBpcyBrZXB0IGJ5ICoqbXV0aW5nKiogcmF0aGVyIHRoYW4gaGlkaW5nIOKAlCBiYWNrZ3JvdW5kIHBvaW50cyBzdGF5XG4gKiAgICB2aXNpYmxlIGF0IGxvdyBhbHBoYSBzbyB0aGUgdGlzc3VlIHNoYXBlIHN1cnZpdmVzLlxuICpcbiAqIENPTE9VUiBSRVBSRVNFTlRBVElPTlxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiBJbnRlcm5hbGx5IGV2ZXJ5dGhpbmcgaXMgYSBmbGF0IGBGbG9hdDMyQXJyYXlgIG9mIGBbcixnLGIsYSwg4oCmXWAgaW4gMC4uMSDigJRcbiAqIG9uZSBhbGxvY2F0aW9uIGZvciBOIHBvaW50cywgR1BVLXVwbG9hZCBzaGFwZWQuIG5hcGFyaS1qcyAwLjEyLjAnc1xuICogYFBvaW50c0xheWVyLmZhY2VDb2xvcmAgdGFrZXMgYFJHQkFbXWAgKGFuIGFycmF5IG9mIDQtdHVwbGVzKSBpbnN0ZWFkLCBzb1xuICoge0BsaW5rIHRvUmdiYVR1cGxlc30gYWRhcHRzIGF0IHRoZSBib3VuZGFyeTsgd2hlbiB0aGUgbGF5ZXIgYWNjZXB0cyBhIHR5cGVkXG4gKiBhcnJheSB0aGUgYWRhcHRlciBnb2VzIGF3YXkgYW5kIHRoZSBmbGF0IGJ1ZmZlciBpcyBwYXNzZWQgc3RyYWlnaHQgdGhyb3VnaC5cbiAqL1xuXG4vKiogbmFwYXJpLWpzIHBlci1wb2ludCBjb2xvdXIgdHVwbGU6IHIsIGcsIGIsIGEgaW4gMC4uMS4gKi9cbmV4cG9ydCB0eXBlIFJHQkEgPSBbbnVtYmVyLCBudW1iZXIsIG51bWJlciwgbnVtYmVyXTtcblxuLyoqIE5ldXRyYWwgZ3JleSBmb3Igb2JzZXJ2YXRpb25zIHdpdGggbm8gdmFsdWUgKE5hTiwgb3Ige0BsaW5rIE5PX0NBVEVHT1JZfSkuICovXG5leHBvcnQgY29uc3QgTUlTU0lOR19DT0xPUjogUmdiID0gWzE1MCwgMTUwLCAxNTBdO1xuXG4vKiogRGVmYXVsdCBhbHBoYSBmb3IgbXV0ZWQgKGJhY2tncm91bmQgLyB1bnNlbGVjdGVkKSBwb2ludHMg4oCUIENvc014LXN0eWxlIGNvbnRleHQuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9NVVRFRF9PUEFDSVRZID0gMC4xNTtcblxuLyoqXG4gKiBMYXJnZXN0IG51bWJlciBvZiBDQVRFR09SSUVTIHdob3NlIGNvbG91cnMgc3Vydml2ZSB0aGUgM0QgcG9pbnRzIGxheWVyJ3MgTFVUXG4gKiBpbnRhY3QuXG4gKlxuICogVGhhdCBsYXllciBoYXMgbm8gcGVyLXBvaW50IFJHQkEg4oCUIGl0IG1hcHMgYSBwZXItcG9pbnQgU0NBTEFSIHRocm91Z2ggYVxuICogMjU2LWVudHJ5IGNvbG9ybWFwIExVVCDigJQgc28gYSBjYXRlZ29yaWNhbCBwYWxldHRlIGlzIGVuY29kZWQgYXMgb25lIGNvbnRpZ3VvdXNcbiAqIGJsb2NrIG9mIExVVCBlbnRyaWVzIHBlciB2YWx1ZS4gTWVhc3VyZWQgYWdhaW5zdCBuYXBhcmktanMsIGV2ZXJ5IEsgaW4gMi4uOTZcbiAqIGJsb2NrcyByb3VuZC10cmlwcyBleGFjdGx5IGFuZCBLPTk3IGlzIHRoZSBmaXJzdCB0aGF0IGRvZXMgbm90OiAyNTYgdGV4ZWxzXG4gKiBjYW5ub3Qga2VlcCBtb3JlIHZhbHVlcyBhcGFydCB0aGFuIHRoYXQuXG4gKlxuICogT25lIG9mIHRob3NlIDk2IGJsb2NrcyBpcyBzcGVudCBvbiB7QGxpbmsgTk9fQ0FURUdPUll9LCB3aGljaCBldmVyeSBjb2x1bW4gY2FuXG4gKiBjb250YWluLCBzbyB3aGF0IGZpdHMgaXMgKio5NSBjYXRlZ29yaWVzKiog4oCUIHRoZSBudW1iZXIgcHVibGlzaGVkIGhlcmUuIEl0IHdhc1xuICogOTYgd2hpbGUgdGhlIGVuY29kZXIgcmVqZWN0ZWQgYXQgOTYsIHdoaWNoIG1lYW50IGEgOTYtY2F0ZWdvcnkgY29sdW1uIGRyZXcgZmxhdFxuICogd2l0aCB0aGUgcGFuZWwgc2hvd2luZyBubyB3YXJuaW5nOiB0aGUgb25lIGZhaWx1cmUgdGhpcyBjZWlsaW5nIGV4aXN0cyB0b1xuICogcHJldmVudCwgYXJyaXZlZCBhdCBmcm9tIHRoZSBvdGhlciBkaXJlY3Rpb24uXG4gKlxuICogQWJvdmUgaXQgdGhlIGNsb3VkIGRyYXdzIEZMQVQgcmF0aGVyIHRoYW4gZHJhdyBhIGxpZSwgYmVjYXVzZSBzdWJ0bHkgd3JvbmdcbiAqIGNhdGVnb3J5IGNvbG91cnMgdW5kZXIgYSBjb25maWRlbnQgbGVnZW5kIGlzIHRoZSBmYWlsdXJlIG5vYm9keSBjYXRjaGVzLlxuICpcbiAqIEEgbGltaXQgb2YgdGhhdCBvbmUgbGF5ZXIsIGFuZCBvZiBub3RoaW5nIGVsc2U6IHRoZSAyRCBtYXJrZXJzIGNhcnJ5IHBlci1wb2ludFxuICogUkdCQSwgYW5kIGEgZGVuc2l0eSB2b2x1bWUgaXMgYSBzY2FsYXIgZmllbGQgcGVyIGNsdXN0ZXIuIFNoYXJlZCBoZXJlIHNvIHRoZVxuICogcmVuZGVyZXIgdGhhdCBlbmZvcmNlcyBpdCBhbmQgdGhlIHBhbmVsIHRoYXQgZXhwbGFpbnMgaXQgY2Fubm90IGRyaWZ0IGFwYXJ0LlxuICovXG5leHBvcnQgY29uc3QgU1BBVElBTF8zRF9NQVhfQ0FURUdPUklFUyA9IDk1O1xuXG4vKiogTFVUIGJsb2NrcyB0aGUgM0QgbGF5ZXIgY2FuIGtlZXAgYXBhcnQg4oCUIHtAbGluayBTUEFUSUFMXzNEX01BWF9DQVRFR09SSUVTfVxuICogIHBsdXMgdGhlIG9uZSByZXNlcnZlZCBmb3IgYSBtaXNzaW5nIHZhbHVlLiAqL1xuZXhwb3J0IGNvbnN0IFNQQVRJQUxfM0RfTFVUX0JMT0NLUyA9IFNQQVRJQUxfM0RfTUFYX0NBVEVHT1JJRVMgKyAxO1xuXG4vKipcbiAqIEZhbGxiYWNrIGNhdGVnb3JpY2FsIHBhbGV0dGUuIENvbG91ci1ibGluZC1zYWZlIGFuZCBzdGFibGUsIHNvIGEgY2F0ZWdvcnlcbiAqIHdpdGhvdXQgYW4gYXV0aG9yZWQgY29sb3VyIHN0aWxsIGxhbmRzIHNvbWV3aGVyZSBzZW5zaWJsZSBhbmQgbGFuZHMgdGhlcmVcbiAqIGV2ZXJ5IHJ1biAoYGZhbGxiYWNrQ29sb3JGb3JgIGhhc2hlcyB0aGUgbmFtZSDigJQgc2FtZSBuYW1lLCBzYW1lIGNvbG91cikuXG4gKiBPa2FiZeKAk0l0bywgcGx1cyB0d28gZ3JleXMgZm9yIGxvbmcgdGFpbHMuXG4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEU6IHN0cmluZ1tdID0gW1xuICAnIzAwNzJCMicsICcjRTY5RjAwJywgJyMwMDlFNzMnLCAnI0NDNzlBNycsICcjNTZCNEU5JyxcbiAgJyNENTVFMDAnLCAnI0YwRTQ0MicsICcjMDAwMDAwJywgJyM3RjdGN0YnLCAnI0JGQkZCRicsXG5dO1xuXG5pbnRlcmZhY2UgTXV0ZU9wdGlvbnMge1xuICAvKiogQWxwaGEgZm9yIHBvaW50cyB0aGF0IGFyZSBub3QgbXV0ZWQuIERlZmF1bHQgMS4gKi9cbiAgb3BhY2l0eT86IG51bWJlcjtcbiAgLyoqIEFscGhhIGZvciBtdXRlZCBwb2ludHMuIERlZmF1bHQge0BsaW5rIERFRkFVTFRfTVVURURfT1BBQ0lUWX0uICovXG4gIG11dGVkT3BhY2l0eT86IG51bWJlcjtcbiAgLyoqIGAxYCBhdCBpbmRleCBpIG11dGVzIG9ic2VydmF0aW9uIGkuIEFic2VudCDih5Igbm90aGluZyBpcyBtdXRlZC4gKi9cbiAgbXV0ZWQ/OiBVaW50OEFycmF5IHwgbnVsbDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDYXRlZ29yaWNhbEVuY29kaW5nT3B0aW9ucyBleHRlbmRzIE11dGVPcHRpb25zIHtcbiAgLyoqIFBlci1jYXRlZ29yeSBgI3JyZ2diYmAsIGluZGV4LWFsaWduZWQgd2l0aCB0aGUgY29sdW1uJ3MgY2F0ZWdvcmllcy4gKi9cbiAgY29sb3JzOiBzdHJpbmdbXTtcbiAgLyoqIENvbG91ciBmb3Ige0BsaW5rIE5PX0NBVEVHT1JZfS4gRGVmYXVsdCB7QGxpbmsgTUlTU0lOR19DT0xPUn0uICovXG4gIG1pc3NpbmdDb2xvcj86IFJnYjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb250aW51b3VzRW5jb2RpbmdPcHRpb25zIGV4dGVuZHMgTXV0ZU9wdGlvbnMge1xuICAvKiogMjU2LWVudHJ5IFJHQiB0YWJsZSBmcm9tIHtAbGluayBidWlsZENvbG9ybWFwTHV0fS4gKi9cbiAgbHV0OiBSZ2JbXTtcbiAgLyoqIENvbnRyYXN0IHdpbmRvdyBpbiBWQUxVRSB1bml0cyAocHJlLWxvZykuICovXG4gIG1pbjogbnVtYmVyO1xuICBtYXg6IG51bWJlcjtcbiAgLyoqIEFwcGx5IGBsb2cxcGAgdG8gdGhlIHZhbHVlIGFuZCB0aGUgd2luZG93IGJlZm9yZSBub3JtYWxpc2luZy4gKi9cbiAgbG9nPzogYm9vbGVhbjtcbiAgLyoqIENvbG91ciBmb3IgYE5hTmAuIERlZmF1bHQge0BsaW5rIE1JU1NJTkdfQ09MT1J9LiAqL1xuICBtaXNzaW5nQ29sb3I/OiBSZ2I7XG59XG5cbi8qKiBQYXJzZSBgI3JnYmAgLyBgI3JyZ2diYmAgdG8gMOKAkzI1NSBSR0I7IHVucGFyc2VhYmxlIGlucHV0IGZhbGxzIGJhY2sgdG8gZ3JleS5cbiAqICBFeHBvcnRlZCBzbyB0aGUgM0QgTFVUIHBhdGggcGFyc2VzIHBhbGV0dGVzIGV4YWN0bHkgYXMgdGhlIDJEIHBhdGggZG9lcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUhleChoZXg6IHN0cmluZyk6IFJnYiB7XG4gIGNvbnN0IG0gPSAvXiM/KFswLTlhLWZdezN9fFswLTlhLWZdezZ9KSQvaS5leGVjKChoZXggPz8gJycpLnRyaW0oKSk7XG4gIGlmICghbSkgcmV0dXJuIE1JU1NJTkdfQ09MT1I7XG4gIGxldCBoID0gbVsxXTtcbiAgaWYgKGgubGVuZ3RoID09PSAzKSBoID0gaFswXSArIGhbMF0gKyBoWzFdICsgaFsxXSArIGhbMl0gKyBoWzJdO1xuICByZXR1cm4gW1xuICAgIHBhcnNlSW50KGguc2xpY2UoMCwgMiksIDE2KSxcbiAgICBwYXJzZUludChoLnNsaWNlKDIsIDQpLCAxNiksXG4gICAgcGFyc2VJbnQoaC5zbGljZSg0LCA2KSwgMTYpLFxuICBdO1xufVxuXG5mdW5jdGlvbiBhbHBoYUF0KGk6IG51bWJlciwgb3B0czogTXV0ZU9wdGlvbnMpOiBudW1iZXIge1xuICBjb25zdCBvbiA9IG9wdHMub3BhY2l0eSA/PyAxO1xuICBjb25zdCBvZmYgPSBvcHRzLm11dGVkT3BhY2l0eSA/PyBERUZBVUxUX01VVEVEX09QQUNJVFk7XG4gIHJldHVybiBvcHRzLm11dGVkICYmIG9wdHMubXV0ZWRbaV0gPyBvZmYgOiBvbjtcbn1cblxuLyoqXG4gKiBQZXItY2F0ZWdvcnkgY29sb3VyczogdGhlIGNvbHVtbidzIGF1dGhvcmVkIGBjb2xvcnNgIHdoZXJlIHByZXNlbnQgKHNvIHRoZVxuICogdmlld2VyIG1hdGNoZXMgdGhlIGZpZ3VyZXMgdGhlIHNhbWUgYW5hbHlzaXMgcHJvZHVjZWQgZWxzZXdoZXJlKSwgb3RoZXJ3aXNlXG4gKiB0aGUgcGFsZXR0ZSBieSBwb3NpdGlvbiwgd3JhcHBpbmcgdGhyb3VnaCBhIG5hbWUtaGFzaCBwYXN0IGl0cyBlbmQgc28gYVxuICogNDAtY2x1c3RlciBjb2x1bW4gc3RpbGwgZ2V0cyBzdGFibGUsIGRpc3RpbmN0LWlzaCBjb2xvdXJzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUNhdGVnb3J5Q29sb3JzKFxuICBtZXRhOiBDYXRlZ29yaWNhbENvbHVtbk1ldGEsIHBhbGV0dGU6IHN0cmluZ1tdID0gREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFLFxuKTogc3RyaW5nW10ge1xuICBjb25zdCBhdXRob3JlZCA9IG1ldGEuY29sb3JzO1xuICByZXR1cm4gbWV0YS5jYXRlZ29yaWVzLm1hcCgobmFtZSwgaSkgPT4ge1xuICAgIGNvbnN0IGdpdmVuID0gYXV0aG9yZWQ/LltpXTtcbiAgICBpZiAoZ2l2ZW4pIHJldHVybiBnaXZlbjtcbiAgICBpZiAoaSA8IHBhbGV0dGUubGVuZ3RoKSByZXR1cm4gcGFsZXR0ZVtpXTtcbiAgICByZXR1cm4gZmFsbGJhY2tDb2xvckZvcihuYW1lLCBwYWxldHRlKTtcbiAgfSk7XG59XG5cbi8qKiBDYXRlZ29yaWNhbCBjb2x1bW4g4oaSIGZsYXQgcGVyLXBvaW50IFJHQkEgKGxlbmd0aCBgNCAqIGNvZGVzLmxlbmd0aGApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVuY29kZUNhdGVnb3JpY2FsKFxuICBjb2RlczogVWludDE2QXJyYXksIG9wdHM6IENhdGVnb3JpY2FsRW5jb2RpbmdPcHRpb25zLFxuKTogRmxvYXQzMkFycmF5IHtcbiAgY29uc3QgbiA9IGNvZGVzLmxlbmd0aDtcbiAgY29uc3Qgb3V0ID0gbmV3IEZsb2F0MzJBcnJheShuICogNCk7XG4gIC8vIFJlc29sdmUgZWFjaCBjYXRlZ29yeSBvbmNlIOKAlCBwYXJzaW5nIGEgaGV4IHN0cmluZyBwZXIgcG9pbnQgd291bGQgZG9taW5hdGUuXG4gIGNvbnN0IHJnYiA9IG9wdHMuY29sb3JzLm1hcChwYXJzZUhleCk7XG4gIGNvbnN0IG1pc3NpbmcgPSBvcHRzLm1pc3NpbmdDb2xvciA/PyBNSVNTSU5HX0NPTE9SO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgIGNvbnN0IGNvZGUgPSBjb2Rlc1tpXTtcbiAgICBjb25zdCBjID0gY29kZSA9PT0gTk9fQ0FURUdPUlkgfHwgY29kZSA+PSByZ2IubGVuZ3RoID8gbWlzc2luZyA6IHJnYltjb2RlXTtcbiAgICBjb25zdCBvID0gaSAqIDQ7XG4gICAgb3V0W29dID0gY1swXSAvIDI1NTtcbiAgICBvdXRbbyArIDFdID0gY1sxXSAvIDI1NTtcbiAgICBvdXRbbyArIDJdID0gY1syXSAvIDI1NTtcbiAgICAvLyBBIHBvaW50IHdpdGggbm8gY2F0ZWdvcnkgaXMgYmFja2dyb3VuZCBieSBkZWZpbml0aW9uIOKAlCBuZXZlciBlbXBoYXNpc2VkLlxuICAgIG91dFtvICsgM10gPSBjb2RlID09PSBOT19DQVRFR09SWVxuICAgICAgPyBNYXRoLm1pbihhbHBoYUF0KGksIG9wdHMpLCBvcHRzLm11dGVkT3BhY2l0eSA/PyBERUZBVUxUX01VVEVEX09QQUNJVFkpXG4gICAgICA6IGFscGhhQXQoaSwgb3B0cyk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIENvbnRpbnVvdXMgY29sdW1uIC8gZ2VuZSB2ZWN0b3Ig4oaSIGZsYXQgcGVyLXBvaW50IFJHQkEuICovXG5leHBvcnQgZnVuY3Rpb24gZW5jb2RlQ29udGludW91cyhcbiAgdmFsdWVzOiBGbG9hdDMyQXJyYXksIG9wdHM6IENvbnRpbnVvdXNFbmNvZGluZ09wdGlvbnMsXG4pOiBGbG9hdDMyQXJyYXkge1xuICBjb25zdCBuID0gdmFsdWVzLmxlbmd0aDtcbiAgY29uc3Qgb3V0ID0gbmV3IEZsb2F0MzJBcnJheShuICogNCk7XG4gIGNvbnN0IG1pc3NpbmcgPSBvcHRzLm1pc3NpbmdDb2xvciA/PyBNSVNTSU5HX0NPTE9SO1xuICBjb25zdCBsdXQgPSBvcHRzLmx1dDtcbiAgY29uc3QgbG8gPSBvcHRzLmxvZyA/IE1hdGgubG9nMXAoTWF0aC5tYXgoMCwgb3B0cy5taW4pKSA6IG9wdHMubWluO1xuICBjb25zdCBoaSA9IG9wdHMubG9nID8gTWF0aC5sb2cxcChNYXRoLm1heCgwLCBvcHRzLm1heCkpIDogb3B0cy5tYXg7XG4gIC8vIEEgZGVnZW5lcmF0ZSB3aW5kb3cgKGFsbCB2YWx1ZXMgZXF1YWwpIG1hcHMgZXZlcnl0aGluZyB0byB0aGUgTFVUIG1pZHBvaW50XG4gIC8vIHJhdGhlciB0aGFuIGRpdmlkaW5nIGJ5IHplcm8uXG4gIGNvbnN0IHNwYW4gPSBoaSAtIGxvO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgIGNvbnN0IHJhdyA9IHZhbHVlc1tpXTtcbiAgICBjb25zdCBvID0gaSAqIDQ7XG4gICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUocmF3KSkge1xuICAgICAgb3V0W29dID0gbWlzc2luZ1swXSAvIDI1NTtcbiAgICAgIG91dFtvICsgMV0gPSBtaXNzaW5nWzFdIC8gMjU1O1xuICAgICAgb3V0W28gKyAyXSA9IG1pc3NpbmdbMl0gLyAyNTU7XG4gICAgICBvdXRbbyArIDNdID0gb3B0cy5tdXRlZE9wYWNpdHkgPz8gREVGQVVMVF9NVVRFRF9PUEFDSVRZO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IHYgPSBvcHRzLmxvZyA/IE1hdGgubG9nMXAoTWF0aC5tYXgoMCwgcmF3KSkgOiByYXc7XG4gICAgY29uc3QgdCA9IHNwYW4gPiAwID8gKHYgLSBsbykgLyBzcGFuIDogMC41O1xuICAgIGNvbnN0IGlkeCA9IE1hdGgubWF4KDAsIE1hdGgubWluKDI1NSwgTWF0aC5yb3VuZCh0ICogMjU1KSkpO1xuICAgIGNvbnN0IGMgPSBsdXRbaWR4XSA/PyBtaXNzaW5nO1xuICAgIG91dFtvXSA9IGNbMF0gLyAyNTU7XG4gICAgb3V0W28gKyAxXSA9IGNbMV0gLyAyNTU7XG4gICAgb3V0W28gKyAyXSA9IGNbMl0gLyAyNTU7XG4gICAgb3V0W28gKyAzXSA9IGFscGhhQXQoaSwgb3B0cyk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqXG4gKiBDb250cmFzdCB3aW5kb3cgZnJvbSBwZXJjZW50aWxlcyBvZiB0aGUgZmluaXRlIHZhbHVlcyDigJQgdGhlIENvc014XG4gKiBcImNhcCBvdXRsaWVycyBhdCBwZXJjZW50aWxlcyB0byBpbXByb3ZlIGNvbnRyYXN0XCIgcnVsZS4gYGxvYC9gaGlgIGFyZVxuICogZnJhY3Rpb25zICgwLjAxIC8gMC45OSBjbGlwcyB0aGUgZXh0cmVtZSAxJSBhdCBlYWNoIGVuZCkuXG4gKlxuICogUmV0dXJucyBgWzAsIDFdYCBmb3IgYW4gZW1wdHkgb3IgYWxsLW1pc3NpbmcgdmVjdG9yIHNvIGNhbGxlcnMgYWx3YXlzIGdldCBhXG4gKiB1c2FibGUgd2luZG93LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29udHJhc3RXaW5kb3coXG4gIHZhbHVlczogRmxvYXQzMkFycmF5LCBsbyA9IDAuMDEsIGhpID0gMC45OSxcbik6IFtudW1iZXIsIG51bWJlcl0ge1xuICBjb25zdCBmaW5pdGU6IG51bWJlcltdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdmFsdWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKE51bWJlci5pc0Zpbml0ZSh2YWx1ZXNbaV0pKSBmaW5pdGUucHVzaCh2YWx1ZXNbaV0pO1xuICB9XG4gIGlmIChmaW5pdGUubGVuZ3RoID09PSAwKSByZXR1cm4gWzAsIDFdO1xuICBmaW5pdGUuc29ydCgoYSwgYikgPT4gYSAtIGIpO1xuICBjb25zdCBhdCA9IChmOiBudW1iZXIpID0+IHtcbiAgICBjb25zdCBrID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oZmluaXRlLmxlbmd0aCAtIDEsIE1hdGgucm91bmQoZiAqIChmaW5pdGUubGVuZ3RoIC0gMSkpKSk7XG4gICAgcmV0dXJuIGZpbml0ZVtrXTtcbiAgfTtcbiAgY29uc3QgbWluID0gYXQoTWF0aC5tYXgoMCwgTWF0aC5taW4oMSwgbG8pKSk7XG4gIGNvbnN0IG1heCA9IGF0KE1hdGgubWF4KDAsIE1hdGgubWluKDEsIGhpKSkpO1xuICAvLyBBIGZsYXQgb3IgaW52ZXJ0ZWQgd2luZG93IHdvdWxkIGRpdmlkZSBieSB6ZXJvIGRvd25zdHJlYW07IHdpZGVuIGl0LlxuICByZXR1cm4gbWF4ID4gbWluID8gW21pbiwgbWF4XSA6IFttaW4sIG1pbiArIDFdO1xufVxuXG4vKipcbiAqIE1hcmtlciBzaXplcyBmb3IgdGhlIHBvaW50cyBsYXllci4gbmFwYXJpLWpzIGBQb2ludHNMYXllci5zaXplYCBpcyBhXG4gKiAqKmRpYW1ldGVyKiogaW4gZGF0YSB1bml0cyB3aGlsZSBgU3BhdGlhbE9ic2VydmF0aW9ucy5yYWRpdXNgIGlzIGEgcmFkaXVzIOKAlFxuICogdGhlIGRvdWJsaW5nIGxpdmVzIGhlcmUgc28gbm8gY2FsbCBzaXRlIGhhcyB0byByZW1lbWJlciBpdC5cbiAqXG4gKiBgZmFsbGJhY2tSYWRpdXNgIGNvdmVycyBhIGRhdGFzZXQgdGhhdCBkZWNsYXJlcyBubyByYWRpdXMgKHNlZ21lbnRlZCBjZWxsc1xuICogb2Z0ZW4gZG9uJ3QpOyBpdCBpcyBpbiBpbWFnZSBwaXhlbHMsIGxpa2UgZXZlcnl0aGluZyBlbHNlIGluIHRoaXMgc3BhY2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXJrZXJEaWFtZXRlcnMoXG4gIG9ic2VydmF0aW9uczogU3BhdGlhbE9ic2VydmF0aW9ucywgZmFsbGJhY2tSYWRpdXMgPSA0LFxuKTogbnVtYmVyIHwgRmxvYXQzMkFycmF5IHtcbiAgY29uc3QgciA9IG9ic2VydmF0aW9ucy5yYWRpdXM7XG4gIGlmICh0eXBlb2YgciA9PT0gJ251bWJlcicpIHJldHVybiByICogMjtcbiAgaWYgKHIgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpIHtcbiAgICBjb25zdCBvdXQgPSBuZXcgRmxvYXQzMkFycmF5KHIubGVuZ3RoKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHIubGVuZ3RoOyBpKyspIG91dFtpXSA9IHJbaV0gKiAyO1xuICAgIHJldHVybiBvdXQ7XG4gIH1cbiAgcmV0dXJuIGZhbGxiYWNrUmFkaXVzICogMjtcbn1cblxuLyoqXG4gKiBBZGFwdCBhIGZsYXQgUkdCQSBidWZmZXIgdG8gdGhlIGBSR0JBW11gIHNoYXBlIG5hcGFyaS1qcyAwLjEyLjAnc1xuICogYFBvaW50c0xheWVyLmZhY2VDb2xvcmAgYWNjZXB0cy4gT25lIDQtZWxlbWVudCBhcnJheSBwZXIgcG9pbnQg4oCUIHRoZSByZWFzb25cbiAqIHRoaXMgaXMgYSBuYW1lZCBib3VuZGFyeSByYXRoZXIgdGhhbiBpbmxpbmVkOiBpdCBpcyB0aGUgb25lIHBsYWNlIHRoZSBtb2RlbFxuICogc3RvcHMgYmVpbmcgdHlwZWQtYXJyYXkgc2hhcGVkLCBhbmQgaXQgaXMgd2hhdCBhIGZ1dHVyZSBuYXBhcmktanMgdGFraW5nIGFcbiAqIGBGbG9hdDMyQXJyYXlgIHdvdWxkIGRlbGV0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvUmdiYVR1cGxlcyhmbGF0OiBGbG9hdDMyQXJyYXkpOiBSR0JBW10ge1xuICBjb25zdCBuID0gZmxhdC5sZW5ndGggLyA0O1xuICBjb25zdCBvdXQ6IFJHQkFbXSA9IG5ldyBBcnJheShuKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpKyspIHtcbiAgICBjb25zdCBvID0gaSAqIDQ7XG4gICAgb3V0W2ldID0gW2ZsYXRbb10sIGZsYXRbbyArIDFdLCBmbGF0W28gKyAyXSwgZmxhdFtvICsgM11dO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbi8qKiBDb252ZW5pZW5jZTogYSAyNTYtZW50cnkgTFVUIGZvciBhIGNvbG9ybWFwIHZhbHVlLCBmYWxsaW5nIGJhY2sgdG8gVmlyaWRpcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsdXRGb3IoY29sb3JtYXBWYWx1ZTogdW5rbm93biwgcmV2ZXJzZSA9IGZhbHNlKTogUmdiW10ge1xuICByZXR1cm4gYnVpbGRDb2xvcm1hcEx1dChjb2xvcm1hcFZhbHVlLCByZXZlcnNlKVxuICAgID8/IGJ1aWxkQ29sb3JtYXBMdXQoJ1ZpcmlkaXMnLCByZXZlcnNlKSE7XG59XG5cbi8qKiBUcnVlIHdoZW4gZXZlcnkgZW50cnkgb2YgYSBMVVQgaXMgYSBuZXV0cmFsIGdyZXkuIFRlc3RlZCBvbiB0aGUgVkFMVUVTIHJhdGhlclxuICogIHRoYW4gdGhlIGNvbG9ybWFwJ3MgbmFtZSwgc28gYSByZXZlcnNlZCBvciByZW5hbWVkIGdyZXkgcmFtcCBzdGlsbCBjb3VudHMuICovXG5leHBvcnQgZnVuY3Rpb24gaXNHcmF5c2NhbGVMdXQobHV0OiByZWFkb25seSBSZ2JbXSk6IGJvb2xlYW4ge1xuICByZXR1cm4gbHV0LmV2ZXJ5KChbciwgZywgYl0pID0+IHIgPT09IGcgJiYgZyA9PT0gYik7XG59XG5cbi8qKlxuICogTFVUIGZvciBhIHNwYXRpYWwgQ09OVElOVU9VUyBlbmNvZGluZyDigJQgYSBnZW5lLCBhIG51bWVyaWMgY29sdW1uLlxuICpcbiAqIGBvdmVycmlkZWAgaXMgdGhlIGNhbGxlcidzIGV4cGxpY2l0IGNob2ljZSBhbmQgd2lucyBvdXRyaWdodCwgZ3JleSBpbmNsdWRlZDogYVxuICogZ3JleSByYW1wIHBpY2tlZCBGT1IgdGhlIGRhdGEgaXMgYSBkZWNpc2lvbiwgbm90IHRoZSBpbWFnZSdzIGNvbG9ybWFwIGxlYWtpbmdcbiAqIGluLlxuICpcbiAqIFdpdGhvdXQgb25lLCB0aGUgZGlzcGxheSBjb2xvcm1hcCDigJQgdW5sZXNzIHRoYXQgY29sb3JtYXAgaXMgZ3JheXNjYWxlLiBUaGVcbiAqIHRpc3N1ZSB1bmRlcm5lYXRoIGlzIGdyYXlzY2FsZSwgc28gYSBncmV5IG92ZXJsYXkgb2YgYSBtZWFzdXJlbWVudCBpc1xuICogaW5kaXN0aW5ndWlzaGFibGUgZnJvbSB0aGUgYW5hdG9teSBpdCBpcyBkcmF3biBvdmVyLCBhbmQgdGhlIHJlYWRlciBjYW5ub3QgdGVsbFxuICogd2hpY2ggY2hhbm5lbCBhIGJyaWdodCBwaXhlbCBiZWxvbmdzIHRvLiBWaXJpZGlzIGlzIHRoZW4gdGhlIGZhbGxiYWNrLCB3aGljaCBpc1xuICogd2hhdCB0aGUgQ29zTXggZ3VpZGFuY2UgcHJlc2NyaWJlcyBmb3IgY29udGludW91cyB2YWx1ZXMgYW55d2F5LlxuICpcbiAqIFNoYXJlZCBieSB0aGUgbWFya2VycywgYm90aCBnZW5lIG1hcHMgYW5kIHRoZSBwYW5lbCdzIGNvbG91ciBiYXIsIHNvIG5vbmUgb2ZcbiAqIHRoZW0gY2FuIGRpc2FncmVlIGFib3V0IHdoYXQgYSBjb2xvdXIgbWVhbnMsIHdoaWNoZXZlciB3YXkgdGhlIGNob2ljZSBmYWxscy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNwYXRpYWxDb250aW51b3VzTHV0KFxuICBjb2xvcm1hcFZhbHVlOiB1bmtub3duLCByZXZlcnNlID0gZmFsc2UsIG92ZXJyaWRlPzogQ29sb3JtYXBWYWx1ZSB8IG51bGwsXG4pOiBSZ2JbXSB7XG4gIC8vIEFuIGlubGluZSBzY2FsZSBpcyBhbiBhcnJheSwgc28gZW1wdGluZXNzIGhhcyB0byBiZSBjaGVja2VkIGFzIHdlbGwgYXNcbiAgLy8gcHJlc2VuY2U6IGBbXWAgaXMgdHJ1dGh5IGFuZCB3b3VsZCByZXNvbHZlIHRvIHRoZSBmYWxsYmFjayBMVVQgc2lsZW50bHkuXG4gIGNvbnN0IGNob3NlbiA9IEFycmF5LmlzQXJyYXkob3ZlcnJpZGUpID8gKG92ZXJyaWRlLmxlbmd0aCA/IG92ZXJyaWRlIDogbnVsbCkgOiBvdmVycmlkZTtcbiAgaWYgKGNob3NlbikgcmV0dXJuIGx1dEZvcihjaG9zZW4sIHJldmVyc2UpO1xuICBjb25zdCBsdXQgPSBsdXRGb3IoY29sb3JtYXBWYWx1ZSwgcmV2ZXJzZSk7XG4gIHJldHVybiBpc0dyYXlzY2FsZUx1dChsdXQpID8gYnVpbGRDb2xvcm1hcEx1dCgnVmlyaWRpcycsIHJldmVyc2UpISA6IGx1dDtcbn1cbiJdfQ==
@@ -0,0 +1,257 @@
1
+ import { blurVolumeAxis } from './spatial-density';
2
+ /** In-place separable Gaussian along one axis of a `w × h` field. */
3
+ function blurAxis(field, w, h, axis, sigma) {
4
+ if (!(sigma > 0.01))
5
+ return;
6
+ const radius = Math.max(1, Math.ceil(sigma * 3));
7
+ const kernel = new Float32Array(radius * 2 + 1);
8
+ let sum = 0;
9
+ for (let i = -radius; i <= radius; i++) {
10
+ const v = Math.exp(-(i * i) / (2 * sigma * sigma));
11
+ kernel[i + radius] = v;
12
+ sum += v;
13
+ }
14
+ for (let i = 0; i < kernel.length; i++)
15
+ kernel[i] /= sum;
16
+ const len = axis === 0 ? w : h;
17
+ const stride = axis === 0 ? 1 : w;
18
+ const lines = axis === 0 ? h : w;
19
+ const line = new Float32Array(len);
20
+ for (let l = 0; l < lines; l++) {
21
+ const base = axis === 0 ? l * w : l;
22
+ for (let i = 0; i < len; i++)
23
+ line[i] = field[base + i * stride];
24
+ for (let i = 0; i < len; i++) {
25
+ let acc = 0;
26
+ for (let k = -radius; k <= radius; k++) {
27
+ // Clamped edges: zero-padding would darken the specimen's own boundary,
28
+ // and the support channel already says where there is no data at all.
29
+ const j = Math.min(len - 1, Math.max(0, i + k));
30
+ acc += line[j] * kernel[k + radius];
31
+ }
32
+ field[base + i * stride] = acc;
33
+ }
34
+ }
35
+ }
36
+ /**
37
+ * Estimate a gene's expression field over the image the observations sit in.
38
+ *
39
+ * Null when nothing lands on the raster — the caller then draws no layer, rather
40
+ * than an empty one the reader has to interpret.
41
+ */
42
+ export function expressionField(obs, opts) {
43
+ const { width: w, height: h, step, sigma, values, indices } = opts;
44
+ if (w <= 0 || h <= 0)
45
+ return null;
46
+ const [sx, sy] = opts.ref?.scale ?? [1, 1];
47
+ const [tx, ty] = opts.ref?.translate ?? [0, 0];
48
+ const num = new Float32Array(w * h);
49
+ const den = new Float32Array(w * h);
50
+ const n = indices ? indices.length : obs.count;
51
+ let placed = 0;
52
+ for (let k = 0; k < n; k++) {
53
+ const i = indices ? indices[k] : k;
54
+ const e = values[i];
55
+ // A NaN is "not measured for this cell", which must not become a zero: it
56
+ // would pull the local mean down as if the gene were absent there.
57
+ if (!Number.isFinite(e))
58
+ continue;
59
+ const px = Math.floor((obs.x[i] * sx + tx) / step);
60
+ const py = Math.floor((obs.y[i] * sy + ty) / step);
61
+ if (px < 0 || px >= w || py < 0 || py >= h)
62
+ continue;
63
+ const at = py * w + px;
64
+ num[at] += e;
65
+ den[at] += 1;
66
+ placed++;
67
+ }
68
+ if (!placed)
69
+ return null;
70
+ for (const axis of [0, 1]) {
71
+ blurAxis(num, w, h, axis, sigma);
72
+ blurAxis(den, w, h, axis, sigma);
73
+ }
74
+ const mean = new Float32Array(w * h);
75
+ let lo = Infinity;
76
+ let hi = -Infinity;
77
+ const positives = [];
78
+ for (let i = 0; i < mean.length; i++) {
79
+ const d = den[i];
80
+ if (d <= 0)
81
+ continue;
82
+ const m = num[i] / d;
83
+ mean[i] = m;
84
+ positives.push(d);
85
+ if (m < lo)
86
+ lo = m;
87
+ if (m > hi)
88
+ hi = m;
89
+ }
90
+ if (!Number.isFinite(lo))
91
+ return null;
92
+ positives.sort((a, b) => a - b);
93
+ const supportScale = positives[positives.length >> 1] || 0;
94
+ return {
95
+ width: w,
96
+ height: h,
97
+ mean,
98
+ support: den,
99
+ supportScale,
100
+ range: hi > lo ? [lo, hi] : [lo, lo + 1],
101
+ };
102
+ }
103
+ /**
104
+ * Colour a field into RGBA8 for a `channels: 4` image source.
105
+ *
106
+ * Alpha comes from the SUPPORT, ramped to the field's own median support rather
107
+ * than a constant: a pixel backed by one distant cell is faint, a properly sampled
108
+ * one is solid, and unmeasured tissue is fully transparent — so the map never
109
+ * asserts a measurement where there was none. `opacity` scales the whole layer on
110
+ * top of that.
111
+ */
112
+ export function colorExpressionField(field, lut, window, opts = {}) {
113
+ const { mean, support, supportScale } = field;
114
+ const rgba = new Uint8Array(mean.length * 4);
115
+ const log = !!opts.log;
116
+ const opacity = opts.opacity ?? 1;
117
+ const norm = (v) => (log ? Math.log1p(Math.max(0, v)) : v);
118
+ const lo = norm(window[0]);
119
+ const hi = norm(window[1]);
120
+ const span = hi > lo ? hi - lo : 1;
121
+ const last = lut.length - 1;
122
+ const sat = supportScale > 0 ? supportScale : 1;
123
+ for (let i = 0; i < mean.length; i++) {
124
+ const d = support[i];
125
+ if (d <= 0)
126
+ continue; // unmeasured — leave it transparent
127
+ const t = Math.min(1, Math.max(0, (norm(mean[i]) - lo) / span));
128
+ const c = lut[Math.round(t * last)] ?? lut[last];
129
+ const a = Math.min(1, d / sat) * opacity;
130
+ const o = i * 4;
131
+ // Premultiplied, matching the canvas alpha mode the renderer configures.
132
+ rgba[o] = Math.round(c[0] * a);
133
+ rgba[o + 1] = Math.round(c[1] * a);
134
+ rgba[o + 2] = Math.round(c[2] * a);
135
+ rgba[o + 3] = Math.round(a * 255);
136
+ }
137
+ return rgba;
138
+ }
139
+ export function expressionVolume(obs, grid, opts) {
140
+ const { width: w, height: h, depth: d, voxelSize } = grid;
141
+ if (w <= 0 || h <= 0 || d <= 0)
142
+ return null;
143
+ const num = new Float32Array(w * h * d);
144
+ const den = new Float32Array(w * h * d);
145
+ const idx = opts.indices;
146
+ const n = idx ? idx.length : obs.count;
147
+ const z = obs.z;
148
+ let placed = 0;
149
+ // The imaged range, taken from the observations that were actually included:
150
+ // the estimate may not reach past the outermost section it was built from.
151
+ let first = d;
152
+ let last = -1;
153
+ for (let k = 0; k < n; k++) {
154
+ const i = idx ? idx[k] : k;
155
+ const e = opts.values[i];
156
+ // Not measured for this cell — must not be read as "the gene is absent here".
157
+ if (!Number.isFinite(e))
158
+ continue;
159
+ const vx = Math.floor(obs.x[i] / voxelSize[0]);
160
+ const vy = Math.floor(obs.y[i] / voxelSize[1]);
161
+ const vz = z ? Math.floor(z[i] / voxelSize[2]) : 0;
162
+ if (vx < 0 || vx >= w || vy < 0 || vy >= h || vz < 0 || vz >= d)
163
+ continue;
164
+ const at = (vz * h + vy) * w + vx;
165
+ num[at] += e;
166
+ den[at] += 1;
167
+ placed++;
168
+ if (vz < first)
169
+ first = vz;
170
+ if (vz > last)
171
+ last = vz;
172
+ }
173
+ if (!placed)
174
+ return null;
175
+ const sigmaVox = [
176
+ opts.sigma[0] / voxelSize[0], opts.sigma[1] / voxelSize[1], opts.sigma[2] / voxelSize[2],
177
+ ];
178
+ // In-plane always: a section's own gene map is a 2D field, whichever mode this is.
179
+ for (const axis of [0, 1]) {
180
+ blurVolumeAxis(num, w, h, d, axis, sigmaVox[axis]);
181
+ blurVolumeAxis(den, w, h, d, axis, sigmaVox[axis]);
182
+ }
183
+ if (opts.interpolate) {
184
+ blurVolumeAxis(num, w, h, d, 2, sigmaVox[2]);
185
+ blurVolumeAxis(den, w, h, d, 2, sigmaVox[2]);
186
+ const plane = w * h;
187
+ for (let k = 0; k < d; k++) {
188
+ if (k >= first && k <= last)
189
+ continue;
190
+ // The blur leaves a tail past the outermost sections; keeping it would draw
191
+ // expression where the specimen was never sectioned.
192
+ num.fill(0, k * plane, (k + 1) * plane);
193
+ den.fill(0, k * plane, (k + 1) * plane);
194
+ }
195
+ }
196
+ const mean = new Float32Array(num.length);
197
+ let lo = Infinity;
198
+ let hi = -Infinity;
199
+ for (let i = 0; i < mean.length; i++) {
200
+ const support = den[i];
201
+ if (support <= 0)
202
+ continue;
203
+ const m = num[i] / support;
204
+ mean[i] = m;
205
+ if (m < lo)
206
+ lo = m;
207
+ if (m > hi)
208
+ hi = m;
209
+ }
210
+ if (!Number.isFinite(lo))
211
+ return null;
212
+ return {
213
+ width: w,
214
+ height: h,
215
+ depth: d,
216
+ mean,
217
+ support: den,
218
+ range: hi > lo ? [lo, hi] : [lo, lo + 1],
219
+ };
220
+ }
221
+ /**
222
+ * Encode a field into the uint8 scalar a `VolumeLayer` renders, windowed the same
223
+ * way the 2D map and the markers are so the three cannot disagree.
224
+ *
225
+ * `floor` lifts every MEASURED voxel to at least this fraction of full scale, so
226
+ * that "the gene is not here" can be told from "nobody sectioned here" — the
227
+ * distinction the 2D map keeps with its separate support channel, which a scalar
228
+ * volume cannot express because its raymarch takes alpha from the same number it
229
+ * takes colour from.
230
+ *
231
+ * It defaults to OFF, because in a volume that trade does not pay. A ray crosses
232
+ * tens of measured planes and the DVR composites every one of them, so a floor
233
+ * large enough to see on a single plane saturates to an opaque shell over the
234
+ * whole specimen and buries the signal it was meant to contextualise, while one
235
+ * small enough to stay faint is already invisible per plane. The measured envelope
236
+ * is better read from the anatomy layer and the observations, which are drawn in
237
+ * the same scene — and the surrounding density volumes take the same no-floor
238
+ * approach, so the scene stays internally consistent.
239
+ */
240
+ export function encodeExpressionVolume(field, window, opts = {}) {
241
+ const { mean, support } = field;
242
+ const out = new Uint8Array(mean.length);
243
+ const log = !!opts.log;
244
+ const floor = Math.min(1, Math.max(0, opts.floor ?? 0));
245
+ const norm = (v) => (log ? Math.log1p(Math.max(0, v)) : v);
246
+ const lo = norm(window[0]);
247
+ const hi = norm(window[1]);
248
+ const span = hi > lo ? hi - lo : 1;
249
+ for (let i = 0; i < mean.length; i++) {
250
+ if (support[i] <= 0)
251
+ continue; // unmeasured — zero, so the raymarch skips it
252
+ const t = Math.min(1, Math.max(0, (norm(mean[i]) - lo) / span));
253
+ out[i] = Math.round((floor + (1 - floor) * t) * 255);
254
+ }
255
+ return out;
256
+ }
257
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1leHByZXNzaW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsL3NwYXRpYWwtZXhwcmVzc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsY0FBYyxFQUFlLE1BQU0sbUJBQW1CLENBQUM7QUEwRGhFLHFFQUFxRTtBQUNyRSxTQUFTLFFBQVEsQ0FBQyxLQUFtQixFQUFFLENBQVMsRUFBRSxDQUFTLEVBQUUsSUFBVyxFQUFFLEtBQWE7SUFDckYsSUFBSSxDQUFDLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQztRQUFFLE9BQU87SUFDNUIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqRCxNQUFNLE1BQU0sR0FBRyxJQUFJLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ2hELElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztJQUNaLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxLQUFLLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUNuRCxNQUFNLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QixHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUNELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRTtRQUFFLE1BQU0sQ0FB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LENBQVUsRUFBRSxDQUFDO1FBQ25DLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDakMsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxZQUFZLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3JDLElBQUksRUFBRSxHQUFHLFFBQVEsQ0FBQztJQUNsQixJQUFJLEVBQUUsR0FBRyxDQUFDLFFBQVEsQ0FBQztJQUNuQixNQUFNLFNBQVMsR0FBYSxFQUFFLENBQUM7SUFDL0IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNyQyxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakIsSUFBSSxDQUFDLElBQUksQ0FBQztZQUFFLFNBQVM7UUFDckIsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNyQixJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ1osU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsR0FBRyxFQUFFO1lBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNuQixJQUFJLENBQUMsR0FBRyxFQUFFO1lBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNyQixDQUFDO0lBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFFdEMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNo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RSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNFLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzQixNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0IsTUFBTSxJQUFJLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25DLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDckMsSUFBSSxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUFFLFNBQVMsQ0FBQyw4Q0FBOEM7UUFDN0UsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNoRSxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQztJQUN2RCxDQUFDO0lBQ0QsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU3BhdGlhbEltYWdlUmVmLCBTcGF0aWFsT2JzZXJ2YXRpb25zIH0gZnJvbSAnLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQgeyBibHVyVm9sdW1lQXhpcywgRGVuc2l0eUdyaWQgfSBmcm9tICcuL3NwYXRpYWwtZGVuc2l0eSc7XG5cbi8qKlxuICogVHVybmluZyBwZXItY2VsbCBleHByZXNzaW9uIGludG8gYSAqKmdlbmUgbWFwKiog4oCUIGEgY29udGludW91cyBmaWVsZCBvdmVyIHRoZVxuICogdGlzc3VlLCBkcmF3biB1bmRlciB0aGUgY2VsbHMgcmF0aGVyIHRoYW4gaW5zdGVhZCBvZiB0aGVtLlxuICpcbiAqIEEgc2NhdHRlciBjb2xvdXJlZCBieSBhIGdlbmUgYW5zd2VycyBcIndoaWNoIGNlbGxzIGV4cHJlc3MgaXRcIjsgaXQgZG9lcyBub3QgYW5zd2VyXG4gKiBcIndoZXJlIGlzIGl0IGV4cHJlc3NlZFwiLCBiZWNhdXNlIHRoZSBleWUgY2Fubm90IGludGVncmF0ZSB0aG91c2FuZHMgb2Ygc21hbGwgZG90c1xuICogaW50byBhIHRlcnJpdG9yeS4gQSBmaWVsZCBjYW4gYmUgZXN0aW1hdGVkIGJldHdlZW4gdGhlIGNlbGxzIGFuZCByZWFkIGFzIGFcbiAqIHJlZ2lvbiwgd2hpY2ggaXMgd2hhdCB0aGUgQ29zTXggZ3VpZGFuY2UgYW5kIFNwYXRpYWwtTGl2ZSdzIGhlYXQgbGF5ZXIgYm90aCBkby5cbiAqXG4gKiBUaGUgcXVhbnRpdHkgaXMgdGhlIGtlcm5lbC13ZWlnaHRlZCAqKk1FQU4gcGVyIGNlbGwqKiwgbm90IGEgc3VtOlxuICpcbiAqIGBgYFxuICogICBtZWFuKHApID0gzqPhtaIgdyhwLCB44bWiKcK3ZeG1oiAgLyAgzqPhtaIgdyhwLCB44bWiKVxuICogYGBgXG4gKlxuICogQSBzdW0gd291bGQgY29uZmxhdGUgXCJtYW55IGNlbGxzIGhlcmVcIiB3aXRoIFwiaGlnaCBleHByZXNzaW9uIGhlcmVcIiDigJQgYSBkZW5zZVxuICogcmVnaW9uIHdvdWxkIGdsb3cgd2hhdGV2ZXIgaXRzIGNlbGxzIHdlcmUgZG9pbmcsIHdoaWNoIGlzIHRoZSBzaW5nbGUgZWFzaWVzdCB3YXlcbiAqIHRvIHJlYWQgYSBnZW5lIG1hcCB3cm9uZ2x5LiBUaGUgZGVub21pbmF0b3IgaXMgYWxzbyB3aGF0IG1ha2VzIGVtcHRpbmVzc1xuICogZXhwcmVzc2libGU6IHdoZXJlIG5vIGNlbGwgd2FzIG1lYXN1cmVkIHRoZSBtZWFuIGlzICp1bmRlZmluZWQqLCBub3QgemVybywgc28gdGhlXG4gKiBjYWxsZXIgZ2V0cyBhIGBzdXBwb3J0YCBjaGFubmVsIGFuZCBjYW4gZHJhdyBub3RoaW5nIHRoZXJlIGluc3RlYWQgb2YgZHJhd2luZyB0aGVcbiAqIGNvbG9ybWFwJ3MgbG93IGVuZCBvdmVyIHVubWVhc3VyZWQgdGlzc3VlLlxuICpcbiAqIFB1cmUg4oCUIG5vIEFuZ3VsYXIsIG5vIEdQVSwgbm8gY29sb3VyIOKAlCBsaWtlIGBzcGF0aWFsLWRlbnNpdHkudHNgLCBhbmQgdGVzdGVkIHRoZVxuICogc2FtZSB3YXkuXG4gKi9cblxuZXhwb3J0IGludGVyZmFjZSBFeHByZXNzaW9uRmllbGRPcHRpb25zIHtcbiAgLyoqIERhdGHihpJpbWFnZSBhZmZpbmUsIHNvIHRoZSBmaWVsZCBsYW5kcyBpbiB0aGUgZGlzcGxheWVkIGltYWdlJ3MgcGl4ZWxzLiAqL1xuICByZWY/OiBTcGF0aWFsSW1hZ2VSZWY7XG4gIC8qKiBSYXN0ZXIgc2l6ZSBpbiBmaWVsZCBwaXhlbHMuICovXG4gIHdpZHRoOiBudW1iZXI7XG4gIGhlaWdodDogbnVtYmVyO1xuICAvKiogSW1hZ2UgcGl4ZWxzIHBlciBmaWVsZCBwaXhlbCDigJQgdGhlIGZpZWxkIGlzIGNvYXJzZXIgdGhhbiB0aGUgc2xpZGUgaXQgY292ZXJzLiAqL1xuICBzdGVwOiBudW1iZXI7XG4gIC8qKiBLZXJuZWwgz4MgaW4gRklFTEQgcGl4ZWxzLiAqL1xuICBzaWdtYTogbnVtYmVyO1xuICAvKiogT25lIGV4cHJlc3Npb24gdmFsdWUgcGVyIG9ic2VydmF0aW9uLiAqL1xuICB2YWx1ZXM6IEZsb2F0MzJBcnJheTtcbiAgLyoqIE9ic2VydmF0aW9ucyB0byBpbmNsdWRlOyBldmVyeSBvbmUgd2hlbiBhYnNlbnQgKGEgcGxhbmUsIGEgc2VsZWN0aW9uKS4gKi9cbiAgaW5kaWNlcz86IFVpbnQzMkFycmF5O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEV4cHJlc3Npb25GaWVsZCB7XG4gIHdpZHRoOiBudW1iZXI7XG4gIGhlaWdodDogbnVtYmVyO1xuICAvKiogS2VybmVsLXdlaWdodGVkIG1lYW4gZXhwcmVzc2lvbiwgdmFsaWQgb25seSB3aGVyZSBgc3VwcG9ydCA+IDBgLiAqL1xuICBtZWFuOiBGbG9hdDMyQXJyYXk7XG4gIC8qKiBLZXJuZWwtd2VpZ2h0ZWQgY2VsbCBjb3VudCBwZXIgZmllbGQgcGl4ZWwg4oCUIDAgd2hlcmUgbm90aGluZyB3YXMgbWVhc3VyZWQuICovXG4gIHN1cHBvcnQ6IEZsb2F0MzJBcnJheTtcbiAgLyoqIE1lZGlhbiBwb3NpdGl2ZSBzdXBwb3J0OiB0aGUgc2NhbGUgYXQgd2hpY2ggYSBwaXhlbCBpcyBcInByb3Blcmx5IHNhbXBsZWRcIixcbiAgICogIGFuZCBhIGRhdGEtZHJpdmVuIHNhdHVyYXRpb24gcG9pbnQgZm9yIGFuIG9wYWNpdHkgcmFtcC4gKi9cbiAgc3VwcG9ydFNjYWxlOiBudW1iZXI7XG4gIC8qKiBGaW5pdGUgcmFuZ2Ugb2YgYG1lYW5gIG92ZXIgdGhlIHN1cHBvcnRlZCBwaXhlbHMsIGZvciBhIGNvbnRyYXN0IHdpbmRvdy4gKi9cbiAgcmFuZ2U6IFtudW1iZXIsIG51bWJlcl07XG59XG5cbi8qKiBJbi1wbGFjZSBzZXBhcmFibGUgR2F1c3NpYW4gYWxvbmcgb25lIGF4aXMgb2YgYSBgdyDDlyBoYCBmaWVsZC4gKi9cbmZ1bmN0aW9uIGJsdXJBeGlzKGZpZWxkOiBGbG9hdDMyQXJyYXksIHc6IG51bWJlciwgaDogbnVtYmVyLCBheGlzOiAwIHwgMSwgc2lnbWE6IG51bWJlcik6IHZvaWQge1xuICBpZiAoIShzaWdtYSA+IDAuMDEpKSByZXR1cm47XG4gIGNvbnN0IHJhZGl1cyA9IE1hdGgubWF4KDEsIE1hdGguY2VpbChzaWdtYSAqIDMpKTtcbiAgY29uc3Qga2VybmVsID0gbmV3IEZsb2F0MzJBcnJheShyYWRpdXMgKiAyICsgMSk7XG4gIGxldCBzdW0gPSAwO1xuICBmb3IgKGxldCBpID0gLXJhZGl1czsgaSA8PSByYWRpdXM7IGkrKykge1xuICAgIGNvbnN0IHYgPSBNYXRoLmV4cCgtKGkgKiBpKSAvICgyICogc2lnbWEgKiBzaWdtYSkpO1xuICAgIGtlcm5lbFtpICsgcmFkaXVzXSA9IHY7XG4gICAgc3VtICs9IHY7XG4gIH1cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXJuZWwubGVuZ3RoOyBpKyspIGtlcm5lbFtpXSAvPSBzdW07XG5cbiAgY29uc3QgbGVuID0gYXhpcyA9PT0gMCA/IHcgOiBoO1xuICBjb25zdCBzdHJpZGUgPSBheGlzID09PSAwID8gMSA6IHc7XG4gIGNvbnN0IGxpbmVzID0gYXhpcyA9PT0gMCA/IGggOiB3O1xuICBjb25zdCBsaW5lID0gbmV3IEZsb2F0MzJBcnJheShsZW4pO1xuICBmb3IgKGxldCBsID0gMDsgbCA8IGxpbmVzOyBsKyspIHtcbiAgICBjb25zdCBiYXNlID0gYXhpcyA9PT0gMCA/IGwgKiB3IDogbDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbjsgaSsrKSBsaW5lW2ldID0gZmllbGRbYmFzZSArIGkgKiBzdHJpZGVdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIGxldCBhY2MgPSAwO1xuICAgICAgZm9yIChsZXQgayA9IC1yYWRpdXM7IGsgPD0gcmFkaXVzOyBrKyspIHtcbiAgICAgICAgLy8gQ2xhbXBlZCBlZGdlczogemVyby1wYWRkaW5nIHdvdWxkIGRhcmtlbiB0aGUgc3BlY2ltZW4ncyBvd24gYm91bmRhcnksXG4gICAgICAgIC8vIGFuZCB0aGUgc3VwcG9ydCBjaGFubmVsIGFscmVhZHkgc2F5cyB3aGVyZSB0aGVyZSBpcyBubyBkYXRhIGF0IGFsbC5cbiAgICAgICAgY29uc3QgaiA9IE1hdGgubWluKGxlbiAtIDEsIE1hdGgubWF4KDAsIGkgKyBrKSk7XG4gICAgICAgIGFjYyArPSBsaW5lW2pdICoga2VybmVsW2sgKyByYWRpdXNdO1xuICAgICAgfVxuICAgICAgZmllbGRbYmFzZSArIGkgKiBzdHJpZGVdID0gYWNjO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEVzdGltYXRlIGEgZ2VuZSdzIGV4cHJlc3Npb24gZmllbGQgb3ZlciB0aGUgaW1hZ2UgdGhlIG9ic2VydmF0aW9ucyBzaXQgaW4uXG4gKlxuICogTnVsbCB3aGVuIG5vdGhpbmcgbGFuZHMgb24gdGhlIHJhc3RlciDigJQgdGhlIGNhbGxlciB0aGVuIGRyYXdzIG5vIGxheWVyLCByYXRoZXJcbiAqIHRoYW4gYW4gZW1wdHkgb25lIHRoZSByZWFkZXIgaGFzIHRvIGludGVycHJldC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV4cHJlc3Npb25GaWVsZChcbiAgb2JzOiBTcGF0aWFsT2JzZXJ2YXRpb25zLFxuICBvcHRzOiBFeHByZXNzaW9uRmllbGRPcHRpb25zLFxuKTogRXhwcmVzc2lvbkZpZWxkIHwgbnVsbCB7XG4gIGNvbnN0IHsgd2lkdGg6IHcsIGhlaWdodDogaCwgc3RlcCwgc2lnbWEsIHZhbHVlcywgaW5kaWNlcyB9ID0gb3B0cztcbiAgaWYgKHcgPD0gMCB8fCBoIDw9IDApIHJldHVybiBudWxsO1xuICBjb25zdCBbc3gsIHN5XSA9IG9wdHMucmVmPy5zY2FsZSA/PyBbMSwgMV07XG4gIGNvbnN0IFt0eCwgdHldID0gb3B0cy5yZWY/LnRyYW5zbGF0ZSA/PyBbMCwgMF07XG5cbiAgY29uc3QgbnVtID0gbmV3IEZsb2F0MzJBcnJheSh3ICogaCk7XG4gIGNvbnN0IGRlbiA9IG5ldyBGbG9hdDMyQXJyYXkodyAqIGgpO1xuICBjb25zdCBuID0gaW5kaWNlcyA/IGluZGljZXMubGVuZ3RoIDogb2JzLmNvdW50O1xuICBsZXQgcGxhY2VkID0gMDtcbiAgZm9yIChsZXQgayA9IDA7IGsgPCBuOyBrKyspIHtcbiAgICBjb25zdCBpID0gaW5kaWNlcyA/IGluZGljZXNba10gOiBrO1xuICAgIGNvbnN0IGUgPSB2YWx1ZXNbaV07XG4gICAgLy8gQSBOYU4gaXMgXCJub3QgbWVhc3VyZWQgZm9yIHRoaXMgY2VsbFwiLCB3aGljaCBtdXN0IG5vdCBiZWNvbWUgYSB6ZXJvOiBpdFxuICAgIC8vIHdvdWxkIHB1bGwgdGhlIGxvY2FsIG1lYW4gZG93biBhcyBpZiB0aGUgZ2VuZSB3ZXJlIGFic2VudCB0aGVyZS5cbiAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShlKSkgY29udGludWU7XG4gICAgY29uc3QgcHggPSBNYXRoLmZsb29yKChvYnMueFtpXSAqIHN4ICsgdHgpIC8gc3RlcCk7XG4gICAgY29uc3QgcHkgPSBNYXRoLmZsb29yKChvYnMueVtpXSAqIHN5ICsgdHkpIC8gc3RlcCk7XG4gICAgaWYgKHB4IDwgMCB8fCBweCA+PSB3IHx8IHB5IDwgMCB8fCBweSA+PSBoKSBjb250aW51ZTtcbiAgICBjb25zdCBhdCA9IHB5ICogdyArIHB4O1xuICAgIG51bVthdF0gKz0gZTtcbiAgICBkZW5bYXRdICs9IDE7XG4gICAgcGxhY2VkKys7XG4gIH1cbiAgaWYgKCFwbGFjZWQpIHJldHVybiBudWxsO1xuXG4gIGZvciAoY29uc3QgYXhpcyBvZiBbMCwgMV0gYXMgY29uc3QpIHtcbiAgICBibHVyQXhpcyhudW0sIHcsIGgsIGF4aXMsIHNpZ21hKTtcbiAgICBibHVyQXhpcyhkZW4sIHcsIGgsIGF4aXMsIHNpZ21hKTtcbiAgfVxuXG4gIGNvbnN0IG1lYW4gPSBuZXcgRmxvYXQzMkFycmF5KHcgKiBoKTtcbiAgbGV0IGxvID0gSW5maW5pdHk7XG4gIGxldCBoaSA9IC1JbmZpbml0eTtcbiAgY29uc3QgcG9zaXRpdmVzOiBudW1iZXJbXSA9IFtdO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG1lYW4ubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBkID0gZGVuW2ldO1xuICAgIGlmIChkIDw9IDApIGNvbnRpbnVlO1xuICAgIGNvbnN0IG0gPSBudW1baV0gLyBkO1xuICAgIG1lYW5baV0gPSBtO1xuICAgIHBvc2l0aXZlcy5wdXNoKGQpO1xuICAgIGlmIChtIDwgbG8pIGxvID0gbTtcbiAgICBpZiAobSA+IGhpKSBoaSA9IG07XG4gIH1cbiAgaWYgKCFOdW1iZXIuaXNGaW5pdGUobG8pKSByZXR1cm4gbnVsbDtcblxuICBwb3NpdGl2ZXMuc29ydCgoYSwgYikgPT4gYSAtIGIpO1xuICBjb25zdCBzdXBwb3J0U2NhbGUgPSBwb3NpdGl2ZXNbcG9zaXRpdmVzLmxlbmd0aCA+PiAxXSB8fCAwO1xuICByZXR1cm4ge1xuICAgIHdpZHRoOiB3LFxuICAgIGhlaWdodDogaCxcbiAgICBtZWFuLFxuICAgIHN1cHBvcnQ6IGRlbixcbiAgICBzdXBwb3J0U2NhbGUsXG4gICAgcmFuZ2U6IGhpID4gbG8gPyBbbG8sIGhpXSA6IFtsbywgbG8gKyAxXSxcbiAgfTtcbn1cblxuLyoqXG4gKiBDb2xvdXIgYSBmaWVsZCBpbnRvIFJHQkE4IGZvciBhIGBjaGFubmVsczogNGAgaW1hZ2Ugc291cmNlLlxuICpcbiAqIEFscGhhIGNvbWVzIGZyb20gdGhlIFNVUFBPUlQsIHJhbXBlZCB0byB0aGUgZmllbGQncyBvd24gbWVkaWFuIHN1cHBvcnQgcmF0aGVyXG4gKiB0aGFuIGEgY29uc3RhbnQ6IGEgcGl4ZWwgYmFja2VkIGJ5IG9uZSBkaXN0YW50IGNlbGwgaXMgZmFpbnQsIGEgcHJvcGVybHkgc2FtcGxlZFxuICogb25lIGlzIHNvbGlkLCBhbmQgdW5tZWFzdXJlZCB0aXNzdWUgaXMgZnVsbHkgdHJhbnNwYXJlbnQg4oCUIHNvIHRoZSBtYXAgbmV2ZXJcbiAqIGFzc2VydHMgYSBtZWFzdXJlbWVudCB3aGVyZSB0aGVyZSB3YXMgbm9uZS4gYG9wYWNpdHlgIHNjYWxlcyB0aGUgd2hvbGUgbGF5ZXIgb25cbiAqIHRvcCBvZiB0aGF0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29sb3JFeHByZXNzaW9uRmllbGQoXG4gIGZpZWxkOiBFeHByZXNzaW9uRmllbGQsXG4gIGx1dDogcmVhZG9ubHkgKHJlYWRvbmx5IFtudW1iZXIsIG51bWJlciwgbnVtYmVyXSlbXSxcbiAgd2luZG93OiBbbnVtYmVyLCBudW1iZXJdLFxuICBvcHRzOiB7IGxvZz86IGJvb2xlYW47IG9wYWNpdHk/OiBudW1iZXIgfSA9IHt9LFxuKTogVWludDhBcnJheSB7XG4gIGNvbnN0IHsgbWVhbiwgc3VwcG9ydCwgc3VwcG9ydFNjYWxlIH0gPSBmaWVsZDtcbiAgY29uc3QgcmdiYSA9IG5ldyBVaW50OEFycmF5KG1lYW4ubGVuZ3RoICogNCk7XG4gIGNvbnN0IGxvZyA9ICEhb3B0cy5sb2c7XG4gIGNvbnN0IG9wYWNpdHkgPSBvcHRzLm9wYWNpdHkgPz8gMTtcbiAgY29uc3Qgbm9ybSA9ICh2OiBudW1iZXIpOiBudW1iZXIgPT4gKGxvZyA/IE1hdGgubG9nMXAoTWF0aC5tYXgoMCwgdikpIDogdik7XG4gIGNvbnN0IGxvID0gbm9ybSh3aW5kb3dbMF0pO1xuICBjb25zdCBoaSA9IG5vcm0od2luZG93WzFdKTtcbiAgY29uc3Qgc3BhbiA9IGhpID4gbG8gPyBoaSAtIGxvIDogMTtcbiAgY29uc3QgbGFzdCA9IGx1dC5sZW5ndGggLSAxO1xuICBjb25zdCBzYXQgPSBzdXBwb3J0U2NhbGUgPiAwID8gc3VwcG9ydFNjYWxlIDogMTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBtZWFuLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgZCA9IHN1cHBvcnRbaV07XG4gICAgaWYgKGQgPD0gMCkgY29udGludWU7IC8vIHVubWVhc3VyZWQg4oCUIGxlYXZlIGl0IHRyYW5zcGFyZW50XG4gICAgY29uc3QgdCA9IE1hdGgubWluKDEsIE1hdGgubWF4KDAsIChub3JtKG1lYW5baV0pIC0gbG8pIC8gc3BhbikpO1xuICAgIGNvbnN0IGMgPSBsdXRbTWF0aC5yb3VuZCh0ICogbGFzdCldID8/IGx1dFtsYXN0XTtcbiAgICBjb25zdCBhID0gTWF0aC5taW4oMSwgZCAvIHNhdCkgKiBvcGFjaXR5O1xuICAgIGNvbnN0IG8gPSBpICogNDtcbiAgICAvLyBQcmVtdWx0aXBsaWVkLCBtYXRjaGluZyB0aGUgY2FudmFzIGFscGhhIG1vZGUgdGhlIHJlbmRlcmVyIGNvbmZpZ3VyZXMuXG4gICAgcmdiYVtvXSA9IE1hdGgucm91bmQoY1swXSAqIGEpO1xuICAgIHJnYmFbbyArIDFdID0gTWF0aC5yb3VuZChjWzFdICogYSk7XG4gICAgcmdiYVtvICsgMl0gPSBNYXRoLnJvdW5kKGNbMl0gKiBhKTtcbiAgICByZ2JhW28gKyAzXSA9IE1hdGgucm91bmQoYSAqIDI1NSk7XG4gIH1cbiAgcmV0dXJuIHJnYmE7XG59XG5cbi8qKlxuICogVGhlIHNhbWUgZXN0aW1hdG9yIGluIDNEOiBhIGdlbmUncyBleHByZXNzaW9uIG92ZXIgYSBzZXJpYWxseSBzZWN0aW9uZWRcbiAqIHNwZWNpbWVuLCBvbiBhIHtAbGluayBEZW5zaXR5R3JpZH0gbGF0dGljZS5cbiAqXG4gKiBUd28gbW9kZXMsIGFuZCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZW0gaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBhXG4gKiBtZWFzdXJlbWVudCBhbmQgYW4gZXN0aW1hdGU6XG4gKlxuICogIC0gKipzaGVldHMqKiAoYGludGVycG9sYXRlYCB1bnNldCkgYmx1cnMgaW4tcGxhbmUgb25seSwgc28gZXhhY3RseSB0aGUgeiBwbGFuZXNcbiAqICAgIHRoYXQgaG9sZCBjZWxscyBhcmUgZmlsbGVkIGFuZCB0aGUgZ2FwcyBiZXR3ZWVuIHNlY3Rpb25zIHN0YXkgZW1wdHkuIFRoaXMgaXNcbiAqICAgIHRoZSBtZWFzdXJlZCBzZWN0aW9ucywgc3RhY2tlZCDigJQgdGhlIDJEIGdlbmUgbWFwIG9mIGVhY2ggc2xpZGUsIGF0IGl0cyBvd24gei5cbiAqICAtICoqdm9sdW1lKiogKGBpbnRlcnBvbGF0ZWAgc2V0KSBhbHNvIHNtb290aHMgYWxvbmcgeiwgc28gdGhlIHBsYW5lcyBiZXR3ZWVuXG4gKiAgICB0aGUgc2VjdGlvbnMgY2FycnkgYW4gaW50ZXJwb2xhdGVkIHZhbHVlLiBTbW9vdGhpbmcgdGhlIG51bWVyYXRvciBhbmQgdGhlXG4gKiAgICBkZW5vbWluYXRvciB0b2dldGhlciBpcyB3aGF0IG1ha2VzIHRoYXQgaG9uZXN0OiBpdCBpcyBOYWRhcmF5YS1XYXRzb24sIHNvIGFuXG4gKiAgICB1bmltYWdlZCBwbGFuZSBpbmhlcml0cyBpdHMgbmVpZ2hib3VycycgTUVBTiByYXRoZXIgdGhhbiB0aGVpciBzdW0gdGhpbm5lZFxuICogICAgb3ZlciBhIGdhcCBub2JvZHkgc2FtcGxlZC4gT3V0c2lkZSB0aGUgc2FtcGxlZCByYW5nZSB0aGUgZmllbGQgaXMgemVyb2VkIOKAlFxuICogICAgXCJzbW9vdGhlZCBiZXR3ZWVuIHRoZSBpbWFnZWQgc2VjdGlvbnNcIiBtdXN0IG5vdCBwdXQgZXhwcmVzc2lvbiBpbiBmcm9udCBvZlxuICogICAgdGhlIGZpcnN0IHNlY3Rpb24gb3IgYmVoaW5kIHRoZSBsYXN0LlxuICpcbiAqIEluZGl2aWR1YWwgY2VsbHMgYXJlIHN0aWxsIG5ldmVyIGludGVycG9sYXRlZDogY29uc2VjdXRpdmUgc2VjdGlvbnMgc2FtcGxlXG4gKiBkaWZmZXJlbnQgY2VsbHMsIHNvIHRoZXJlIGlzIG5vdGhpbmcgdG8gaW50ZXJwb2xhdGUgYWxvbmcuIFdoYXQgaXMgaW50ZXJwb2xhdGVkXG4gKiBpcyBhIGZpZWxkLCB3aGljaCBpcyBsZWdpdGltYXRlbHkgZGVmaW5lZCBiZXR3ZWVuIHRoZSBwbGFuZXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRXhwcmVzc2lvblZvbHVtZU9wdGlvbnMge1xuICAvKiogS2VybmVsIM+DIHBlciBheGlzLCBpbiB0aGUgb2JzZXJ2YXRpb25zJyBvd24gdW5pdHMuIFRoZSB6IHRlcm0gaXMgdXNlZCBvbmx5XG4gICAqICB3aGVuIHtAbGluayBpbnRlcnBvbGF0ZX0gaXMgc2V0LiAqL1xuICBzaWdtYTogW251bWJlciwgbnVtYmVyLCBudW1iZXJdO1xuICAvKiogT25lIGV4cHJlc3Npb24gdmFsdWUgcGVyIG9ic2VydmF0aW9uLiAqL1xuICB2YWx1ZXM6IEZsb2F0MzJBcnJheTtcbiAgLyoqIE9ic2VydmF0aW9ucyB0byBpbmNsdWRlOyBldmVyeSBvbmUgd2hlbiBhYnNlbnQg4oCUIG9uZSBzZWN0aW9uLCBvciBhIHNlbGVjdGlvbi4gKi9cbiAgaW5kaWNlcz86IFVpbnQzMkFycmF5O1xuICAvKiogU21vb3RoIGFsb25nIHogaW50byBhIGNvbnRpbnVvdXMgZXN0aW1hdGUgcmF0aGVyIHRoYW4gbGVhdmluZyB0aGUgbWVhc3VyZWRcbiAgICogIHNoZWV0cyBpc29sYXRlZCBhdCB0aGVpciBvd24gcGxhbmVzLiAqL1xuICBpbnRlcnBvbGF0ZT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXhwcmVzc2lvblZvbHVtZUZpZWxkIHtcbiAgd2lkdGg6IG51bWJlcjtcbiAgaGVpZ2h0OiBudW1iZXI7XG4gIGRlcHRoOiBudW1iZXI7XG4gIC8qKiBLZXJuZWwtd2VpZ2h0ZWQgbWVhbiBleHByZXNzaW9uLCB2YWxpZCBvbmx5IHdoZXJlIGBzdXBwb3J0ID4gMGAuICovXG4gIG1lYW46IEZsb2F0MzJBcnJheTtcbiAgLyoqIEtlcm5lbC13ZWlnaHRlZCBjZWxsIGNvdW50IHBlciB2b3hlbCDigJQgMCB3aGVyZSBub3RoaW5nIHdhcyBtZWFzdXJlZC4gKi9cbiAgc3VwcG9ydDogRmxvYXQzMkFycmF5O1xuICAvKiogRmluaXRlIHJhbmdlIG9mIGBtZWFuYCBvdmVyIHRoZSBzdXBwb3J0ZWQgdm94ZWxzLCBmb3IgYSBjb250cmFzdCB3aW5kb3cuICovXG4gIHJhbmdlOiBbbnVtYmVyLCBudW1iZXJdO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZXhwcmVzc2lvblZvbHVtZShcbiAgb2JzOiBTcGF0aWFsT2JzZXJ2YXRpb25zLFxuICBncmlkOiBEZW5zaXR5R3JpZCxcbiAgb3B0czogRXhwcmVzc2lvblZvbHVtZU9wdGlvbnMsXG4pOiBFeHByZXNzaW9uVm9sdW1lRmllbGQgfCBudWxsIHtcbiAgY29uc3QgeyB3aWR0aDogdywgaGVpZ2h0OiBoLCBkZXB0aDogZCwgdm94ZWxTaXplIH0gPSBncmlkO1xuICBpZiAodyA8PSAwIHx8IGggPD0gMCB8fCBkIDw9IDApIHJldHVybiBudWxsO1xuICBjb25zdCBudW0gPSBuZXcgRmxvYXQzMkFycmF5KHcgKiBoICogZCk7XG4gIGNvbnN0IGRlbiA9IG5ldyBGbG9hdDMyQXJyYXkodyAqIGggKiBkKTtcbiAgY29uc3QgaWR4ID0gb3B0cy5pbmRpY2VzO1xuICBjb25zdCBuID0gaWR4ID8gaWR4Lmxlbmd0aCA6IG9icy5jb3VudDtcbiAgY29uc3QgeiA9IG9icy56O1xuICBsZXQgcGxhY2VkID0gMDtcbiAgLy8gVGhlIGltYWdlZCByYW5nZSwgdGFrZW4gZnJvbSB0aGUgb2JzZXJ2YXRpb25zIHRoYXQgd2VyZSBhY3R1YWxseSBpbmNsdWRlZDpcbiAgLy8gdGhlIGVzdGltYXRlIG1heSBub3QgcmVhY2ggcGFzdCB0aGUgb3V0ZXJtb3N0IHNlY3Rpb24gaXQgd2FzIGJ1aWx0IGZyb20uXG4gIGxldCBmaXJzdCA9IGQ7XG4gIGxldCBsYXN0ID0gLTE7XG5cbiAgZm9yIChsZXQgayA9IDA7IGsgPCBuOyBrKyspIHtcbiAgICBjb25zdCBpID0gaWR4ID8gaWR4W2tdIDogaztcbiAgICBjb25zdCBlID0gb3B0cy52YWx1ZXNbaV07XG4gICAgLy8gTm90IG1lYXN1cmVkIGZvciB0aGlzIGNlbGwg4oCUIG11c3Qgbm90IGJlIHJlYWQgYXMgXCJ0aGUgZ2VuZSBpcyBhYnNlbnQgaGVyZVwiLlxuICAgIGlmICghTnVtYmVyLmlzRmluaXRlKGUpKSBjb250aW51ZTtcbiAgICBjb25zdCB2eCA9IE1hdGguZmxvb3Iob2JzLnhbaV0gLyB2b3hlbFNpemVbMF0pO1xuICAgIGNvbnN0IHZ5ID0gTWF0aC5mbG9vcihvYnMueVtpXSAvIHZveGVsU2l6ZVsxXSk7XG4gICAgY29uc3QgdnogPSB6ID8gTWF0aC5mbG9vcih6W2ldIC8gdm94ZWxTaXplWzJdKSA6IDA7XG4gICAgaWYgKHZ4IDwgMCB8fCB2eCA+PSB3IHx8IHZ5IDwgMCB8fCB2eSA+PSBoIHx8IHZ6IDwgMCB8fCB2eiA+PSBkKSBjb250aW51ZTtcbiAgICBjb25zdCBhdCA9ICh2eiAqIGggKyB2eSkgKiB3ICsgdng7XG4gICAgbnVtW2F0XSArPSBlO1xuICAgIGRlblthdF0gKz0gMTtcbiAgICBwbGFjZWQrKztcbiAgICBpZiAodnogPCBmaXJzdCkgZmlyc3QgPSB2ejtcbiAgICBpZiAodnogPiBsYXN0KSBsYXN0ID0gdno7XG4gIH1cbiAgaWYgKCFwbGFjZWQpIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IHNpZ21hVm94OiBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0gPSBbXG4gICAgb3B0cy5zaWdtYVswXSAvIHZveGVsU2l6ZVswXSwgb3B0cy5zaWdtYVsxXSAvIHZveGVsU2l6ZVsxXSwgb3B0cy5zaWdtYVsyXSAvIHZveGVsU2l6ZVsyXSxcbiAgXTtcbiAgLy8gSW4tcGxhbmUgYWx3YXlzOiBhIHNlY3Rpb24ncyBvd24gZ2VuZSBtYXAgaXMgYSAyRCBmaWVsZCwgd2hpY2hldmVyIG1vZGUgdGhpcyBpcy5cbiAgZm9yIChjb25zdCBheGlzIG9mIFswLCAxXSBhcyBjb25zdCkge1xuICAgIGJsdXJWb2x1bWVBeGlzKG51bSwgdywgaCwgZCwgYXhpcywgc2lnbWFWb3hbYXhpc10pO1xuICAgIGJsdXJWb2x1bWVBeGlzKGRlbiwgdywgaCwgZCwgYXhpcywgc2lnbWFWb3hbYXhpc10pO1xuICB9XG4gIGlmIChvcHRzLmludGVycG9sYXRlKSB7XG4gICAgYmx1clZvbHVtZUF4aXMobnVtLCB3LCBoLCBkLCAyLCBzaWdtYVZveFsyXSk7XG4gICAgYmx1clZvbHVtZUF4aXMoZGVuLCB3LCBoLCBkLCAyLCBzaWdtYVZveFsyXSk7XG4gICAgY29uc3QgcGxhbmUgPSB3ICogaDtcbiAgICBmb3IgKGxldCBrID0gMDsgayA8IGQ7IGsrKykge1xuICAgICAgaWYgKGsgPj0gZmlyc3QgJiYgayA8PSBsYXN0KSBjb250aW51ZTtcbiAgICAgIC8vIFRoZSBibHVyIGxlYXZlcyBhIHRhaWwgcGFzdCB0aGUgb3V0ZXJtb3N0IHNlY3Rpb25zOyBrZWVwaW5nIGl0IHdvdWxkIGRyYXdcbiAgICAgIC8vIGV4cHJlc3Npb24gd2hlcmUgdGhlIHNwZWNpbWVuIHdhcyBuZXZlciBzZWN0aW9uZWQuXG4gICAgICBudW0uZmlsbCgwLCBrICogcGxhbmUsIChrICsgMSkgKiBwbGFuZSk7XG4gICAgICBkZW4uZmlsbCgwLCBrICogcGxhbmUsIChrICsgMSkgKiBwbGFuZSk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgbWVhbiA9IG5ldyBGbG9hdDMyQXJyYXkobnVtLmxlbmd0aCk7XG4gIGxldCBsbyA9IEluZmluaXR5O1xuICBsZXQgaGkgPSAtSW5maW5pdHk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbWVhbi5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IHN1cHBvcnQgPSBkZW5baV07XG4gICAgaWYgKHN1cHBvcnQgPD0gMCkgY29udGludWU7XG4gICAgY29uc3QgbSA9IG51bVtpXSAvIHN1cHBvcnQ7XG4gICAgbWVhbltpXSA9IG07XG4gICAgaWYgKG0gPCBsbykgbG8gPSBtO1xuICAgIGlmIChtID4gaGkpIGhpID0gbTtcbiAgfVxuICBpZiAoIU51bWJlci5pc0Zpbml0ZShsbykpIHJldHVybiBudWxsO1xuXG4gIHJldHVybiB7XG4gICAgd2lkdGg6IHcsXG4gICAgaGVpZ2h0OiBoLFxuICAgIGRlcHRoOiBkLFxuICAgIG1lYW4sXG4gICAgc3VwcG9ydDogZGVuLFxuICAgIHJhbmdlOiBoaSA+IGxvID8gW2xvLCBoaV0gOiBbbG8sIGxvICsgMV0sXG4gIH07XG59XG5cbi8qKlxuICogRW5jb2RlIGEgZmllbGQgaW50byB0aGUgdWludDggc2NhbGFyIGEgYFZvbHVtZUxheWVyYCByZW5kZXJzLCB3aW5kb3dlZCB0aGUgc2FtZVxuICogd2F5IHRoZSAyRCBtYXAgYW5kIHRoZSBtYXJrZXJzIGFyZSBzbyB0aGUgdGhyZWUgY2Fubm90IGRpc2FncmVlLlxuICpcbiAqIGBmbG9vcmAgbGlmdHMgZXZlcnkgTUVBU1VSRUQgdm94ZWwgdG8gYXQgbGVhc3QgdGhpcyBmcmFjdGlvbiBvZiBmdWxsIHNjYWxlLCBzb1xuICogdGhhdCBcInRoZSBnZW5lIGlzIG5vdCBoZXJlXCIgY2FuIGJlIHRvbGQgZnJvbSBcIm5vYm9keSBzZWN0aW9uZWQgaGVyZVwiIOKAlCB0aGVcbiAqIGRpc3RpbmN0aW9uIHRoZSAyRCBtYXAga2VlcHMgd2l0aCBpdHMgc2VwYXJhdGUgc3VwcG9ydCBjaGFubmVsLCB3aGljaCBhIHNjYWxhclxuICogdm9sdW1lIGNhbm5vdCBleHByZXNzIGJlY2F1c2UgaXRzIHJheW1hcmNoIHRha2VzIGFscGhhIGZyb20gdGhlIHNhbWUgbnVtYmVyIGl0XG4gKiB0YWtlcyBjb2xvdXIgZnJvbS5cbiAqXG4gKiBJdCBkZWZhdWx0cyB0byBPRkYsIGJlY2F1c2UgaW4gYSB2b2x1bWUgdGhhdCB0cmFkZSBkb2VzIG5vdCBwYXkuIEEgcmF5IGNyb3NzZXNcbiAqIHRlbnMgb2YgbWVhc3VyZWQgcGxhbmVzIGFuZCB0aGUgRFZSIGNvbXBvc2l0ZXMgZXZlcnkgb25lIG9mIHRoZW0sIHNvIGEgZmxvb3JcbiAqIGxhcmdlIGVub3VnaCB0byBzZWUgb24gYSBzaW5nbGUgcGxhbmUgc2F0dXJhdGVzIHRvIGFuIG9wYXF1ZSBzaGVsbCBvdmVyIHRoZVxuICogd2hvbGUgc3BlY2ltZW4gYW5kIGJ1cmllcyB0aGUgc2lnbmFsIGl0IHdhcyBtZWFudCB0byBjb250ZXh0dWFsaXNlLCB3aGlsZSBvbmVcbiAqIHNtYWxsIGVub3VnaCB0byBzdGF5IGZhaW50IGlzIGFscmVhZHkgaW52aXNpYmxlIHBlciBwbGFuZS4gVGhlIG1lYXN1cmVkIGVudmVsb3BlXG4gKiBpcyBiZXR0ZXIgcmVhZCBmcm9tIHRoZSBhbmF0b215IGxheWVyIGFuZCB0aGUgb2JzZXJ2YXRpb25zLCB3aGljaCBhcmUgZHJhd24gaW5cbiAqIHRoZSBzYW1lIHNjZW5lIOKAlCBhbmQgdGhlIHN1cnJvdW5kaW5nIGRlbnNpdHkgdm9sdW1lcyB0YWtlIHRoZSBzYW1lIG5vLWZsb29yXG4gKiBhcHByb2FjaCwgc28gdGhlIHNjZW5lIHN0YXlzIGludGVybmFsbHkgY29uc2lzdGVudC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVuY29kZUV4cHJlc3Npb25Wb2x1bWUoXG4gIGZpZWxkOiBFeHByZXNzaW9uVm9sdW1lRmllbGQsXG4gIHdpbmRvdzogW251bWJlciwgbnVtYmVyXSxcbiAgb3B0czogeyBsb2c/OiBib29sZWFuOyBmbG9vcj86IG51bWJlciB9ID0ge30sXG4pOiBVaW50OEFycmF5IHtcbiAgY29uc3QgeyBtZWFuLCBzdXBwb3J0IH0gPSBmaWVsZDtcbiAgY29uc3Qgb3V0ID0gbmV3IFVpbnQ4QXJyYXkobWVhbi5sZW5ndGgpO1xuICBjb25zdCBsb2cgPSAhIW9wdHMubG9nO1xuICBjb25zdCBmbG9vciA9IE1hdGgubWluKDEsIE1hdGgubWF4KDAsIG9wdHMuZmxvb3IgPz8gMCkpO1xuICBjb25zdCBub3JtID0gKHY6IG51bWJlcik6IG51bWJlciA9PiAobG9nID8gTWF0aC5sb2cxcChNYXRoLm1heCgwLCB2KSkgOiB2KTtcbiAgY29uc3QgbG8gPSBub3JtKHdpbmRvd1swXSk7XG4gIGNvbnN0IGhpID0gbm9ybSh3aW5kb3dbMV0pO1xuICBjb25zdCBzcGFuID0gaGkgPiBsbyA/IGhpIC0gbG8gOiAxO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG1lYW4ubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoc3VwcG9ydFtpXSA8PSAwKSBjb250aW51ZTsgLy8gdW5tZWFzdXJlZCDigJQgemVybywgc28gdGhlIHJheW1hcmNoIHNraXBzIGl0XG4gICAgY29uc3QgdCA9IE1hdGgubWluKDEsIE1hdGgubWF4KDAsIChub3JtKG1lYW5baV0pIC0gbG8pIC8gc3BhbikpO1xuICAgIG91dFtpXSA9IE1hdGgucm91bmQoKGZsb29yICsgKDEgLSBmbG9vcikgKiB0KSAqIDI1NSk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cbiJdfQ==