@jax-data-science/sci-image-visualizer 0.3.3 → 0.5.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 (98) hide show
  1. package/README.md +268 -4
  2. package/esm2022/index.mjs +21 -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-contribution.contract.mjs +66 -0
  6. package/esm2022/lib/contracts/plot-type.mjs +41 -1
  7. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +3 -0
  8. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +45 -0
  9. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  10. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +10 -19
  11. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +71 -7
  12. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +1 -1
  13. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +96 -0
  14. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +1934 -55
  15. package/esm2022/lib/implementations/napari-js/napari-zoom.mjs +18 -0
  16. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +73 -8
  17. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +8 -1
  18. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +3 -4
  19. package/esm2022/lib/implementations/osd/osd-zoom.mjs +20 -0
  20. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +555 -0
  21. package/esm2022/lib/implementations/plotly/plotly.service.mjs +13 -7
  22. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +304 -0
  23. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +179 -0
  24. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +329 -0
  25. package/esm2022/lib/routing-visualizer.service.mjs +228 -12
  26. package/esm2022/lib/spatial/embedding-compute.mjs +142 -0
  27. package/esm2022/lib/spatial/gene-search.mjs +77 -0
  28. package/esm2022/lib/spatial/spatial-density.mjs +224 -0
  29. package/esm2022/lib/spatial/spatial-encoding.mjs +232 -0
  30. package/esm2022/lib/spatial/spatial-expression.mjs +257 -0
  31. package/esm2022/lib/spatial/spatial-framing.mjs +60 -0
  32. package/esm2022/lib/spatial/spatial-heatmap.mjs +185 -0
  33. package/esm2022/lib/spatial/spatial-hover.mjs +79 -0
  34. package/esm2022/lib/spatial/spatial-sections.mjs +96 -0
  35. package/esm2022/lib/spatial/spatial-selection.mjs +264 -0
  36. package/esm2022/lib/spatial/spatial-volume-image.mjs +163 -0
  37. package/esm2022/lib/spatial/tsne-worker.mjs +10 -0
  38. package/esm2022/lib/spatial/world-grid.mjs +77 -0
  39. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +1278 -0
  40. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +621 -0
  41. package/esm2022/lib/store/spatial-selection.service.mjs +47 -0
  42. package/esm2022/lib/store/visualizer-store.service.mjs +23 -1
  43. package/esm2022/lib/toolbar/toolbar.component.mjs +61 -21
  44. package/esm2022/lib/visualization.module.mjs +23 -5
  45. package/esm2022/lib/visualizer.component.mjs +527 -44
  46. 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
  47. 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
  48. package/fesm2022/jax-data-science-sci-image-visualizer-tsne-worker-B_nXDGf0.mjs +12 -0
  49. package/fesm2022/jax-data-science-sci-image-visualizer-tsne-worker-B_nXDGf0.mjs.map +1 -0
  50. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +15971 -7808
  51. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  52. package/fesm2022/tsne.worker.js +19091 -0
  53. package/index.d.ts +16 -0
  54. package/lib/contracts/display-types.d.ts +131 -0
  55. package/lib/contracts/image.contract.d.ts +7 -0
  56. package/lib/contracts/plot-type-contribution.contract.d.ts +172 -0
  57. package/lib/contracts/plot-type.d.ts +52 -2
  58. package/lib/contracts/ports/spatial-data.port.d.ts +90 -0
  59. package/lib/contracts/spatial-dataset.contract.d.ts +281 -0
  60. package/lib/contracts/visualizer.contract.d.ts +104 -1
  61. package/lib/implementations/napari-js/napari-axes-labels.d.ts +9 -7
  62. package/lib/implementations/napari-js/napari-region-overlay.d.ts +38 -4
  63. package/lib/implementations/napari-js/napari-scale-bar.d.ts +7 -3
  64. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +32 -0
  65. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +497 -16
  66. package/lib/implementations/napari-js/napari-zoom.d.ts +15 -0
  67. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +21 -0
  68. package/lib/implementations/osd/osd-coordinate-transform.d.ts +6 -0
  69. package/lib/implementations/osd/osd-zoom.d.ts +19 -0
  70. package/lib/implementations/plotly/omics-trace-builders.d.ts +193 -0
  71. package/lib/implementations/plotly/plotly.service.d.ts +9 -0
  72. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +123 -0
  73. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +115 -0
  74. package/lib/plot-mode/plot-mode-controller.d.ts +130 -0
  75. package/lib/routing-visualizer.service.d.ts +49 -6
  76. package/lib/spatial/embedding-compute.d.ts +73 -0
  77. package/lib/spatial/gene-search.d.ts +48 -0
  78. package/lib/spatial/spatial-density.d.ts +73 -0
  79. package/lib/spatial/spatial-encoding.d.ts +155 -0
  80. package/lib/spatial/spatial-expression.d.ts +144 -0
  81. package/lib/spatial/spatial-framing.d.ts +37 -0
  82. package/lib/spatial/spatial-heatmap.d.ts +111 -0
  83. package/lib/spatial/spatial-hover.d.ts +49 -0
  84. package/lib/spatial/spatial-sections.d.ts +59 -0
  85. package/lib/spatial/spatial-selection.d.ts +113 -0
  86. package/lib/spatial/spatial-volume-image.d.ts +67 -0
  87. package/lib/spatial/tsne-worker.d.ts +7 -0
  88. package/lib/spatial/world-grid.d.ts +58 -0
  89. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +439 -0
  90. package/lib/spatial-controls/spatial-controls.component.d.ts +257 -0
  91. package/lib/store/spatial-selection.service.d.ts +27 -0
  92. package/lib/store/visualizer-store.service.d.ts +13 -0
  93. package/lib/toolbar/toolbar.component.d.ts +36 -8
  94. package/lib/visualization.module.d.ts +28 -24
  95. package/lib/visualizer.component.d.ts +139 -7
  96. package/package.json +6 -2
  97. package/src/lib/assets/spatial-omics-3d.svg +31 -0
  98. package/src/lib/assets/spatial-omics.svg +27 -0
@@ -0,0 +1,329 @@
1
+ import { PlotType, isBuiltinPlotType } from '../contracts/plot-type';
2
+ /** Base types a contributed mode can ride on in this version. */
3
+ export const SUPPORTED_CONTRIBUTION_BASE_TYPES = [PlotType.IMAGE];
4
+ /** How many animation frames to wait for the viewport before giving up. */
5
+ const MAX_READY_FRAMES = 180;
6
+ const TAG = '[visualizer] plot-type contribution';
7
+ /**
8
+ * Validate what arrived on `PLOT_TYPE_CONTRIBUTIONS`. A malformed or clashing
9
+ * contribution is dropped with a warning rather than breaking the selector:
10
+ * - a nested array (`useValue: [a, b], multi: true`) is flattened one level;
11
+ * - `type` must be a non-empty string that is not a built-in `PlotType` value;
12
+ * - the first contribution with a given `type` wins;
13
+ * - `baseType` must be one of {@link SUPPORTED_CONTRIBUTION_BASE_TYPES};
14
+ * - `activate` must be a function.
15
+ */
16
+ export function normalizeContributions(raw, log = console) {
17
+ const out = [];
18
+ const seen = new Set();
19
+ const flat = (raw ?? []).flatMap((c) => (Array.isArray(c) ? c : [c]));
20
+ for (const c of flat) {
21
+ const d = c?.descriptor;
22
+ const id = d?.type;
23
+ if (!d || typeof id !== 'string' || !id || typeof c.activate !== 'function') {
24
+ log.warn(`${TAG} ignored: it needs a descriptor with a string \`type\` and an \`activate\` function.`, c);
25
+ continue;
26
+ }
27
+ if (isBuiltinPlotType(id)) {
28
+ log.warn(`${TAG} '${id}' ignored: the id clashes with a built-in plot type.`);
29
+ continue;
30
+ }
31
+ if (seen.has(id)) {
32
+ log.warn(`${TAG} '${id}' ignored: another contribution already uses that id.`);
33
+ continue;
34
+ }
35
+ if (!SUPPORTED_CONTRIBUTION_BASE_TYPES.includes(d.baseType)) {
36
+ log.warn(`${TAG} '${id}' ignored: baseType '${String(d.baseType)}' is not supported `
37
+ + `(supported: ${SUPPORTED_CONTRIBUTION_BASE_TYPES.join(', ')}).`);
38
+ continue;
39
+ }
40
+ seen.add(id);
41
+ out.push(c);
42
+ }
43
+ return out;
44
+ }
45
+ export class PlotModeController {
46
+ constructor(raw, hooks, log = console) {
47
+ this.hooks = hooks;
48
+ this.log = log;
49
+ this.active = null;
50
+ this.teardown = null;
51
+ /** Bumped by every activate/deactivate, so a pending async activation can
52
+ * tell it has been superseded. */
53
+ this.generation = 0;
54
+ this.readyFrame = null;
55
+ /** Contributions whose last cleanup (panel teardown / `deactivate()`) threw or
56
+ * rejected. Their next automatic re-activation (base re-render, image switch)
57
+ * falls back to the base type instead; an explicit selection clears the mark. */
58
+ this.failedCleanup = new Map();
59
+ this.readyCb = null;
60
+ this.pendingId = null;
61
+ this.contributions = normalizeContributions(raw, log);
62
+ this.byId = new Map(this.contributions.map((c) => [c.descriptor.type, c]));
63
+ }
64
+ /** Descriptors of the usable contributions, in registration order. */
65
+ descriptors() {
66
+ return this.contributions.map((c) => c.descriptor);
67
+ }
68
+ /** The contribution for a selector id, if it is a contributed mode. */
69
+ find(id) {
70
+ return typeof id === 'string' ? this.byId.get(id) : undefined;
71
+ }
72
+ /**
73
+ * The built-in type that renders `id`: a built-in type is itself, a
74
+ * contributed id is its `baseType`, and an id that is neither (a stale
75
+ * contributed id whose provider is gone) resolves to `PlotType.IMAGE`, the
76
+ * default view.
77
+ */
78
+ baseTypeOf(id) {
79
+ if (isBuiltinPlotType(id))
80
+ return id;
81
+ return this.find(id)?.descriptor.baseType ?? PlotType.IMAGE;
82
+ }
83
+ /** The live session, if any. */
84
+ get current() {
85
+ return this.active;
86
+ }
87
+ /** Whether an activation is waiting on the contribution or the viewport. */
88
+ get pending() {
89
+ return this.pendingId !== null;
90
+ }
91
+ /**
92
+ * Start a session for `contribution`. Ends any live one first. Resolves when
93
+ * the attempt has finished (successfully or not); it never rejects.
94
+ */
95
+ activate(contribution, ctx) {
96
+ this.deactivate();
97
+ const id = contribution.descriptor.type;
98
+ if (this.failedCleanup.has(id)) {
99
+ // Its previous session did not end cleanly; do not stack a new one on top.
100
+ const err = this.failedCleanup.get(id);
101
+ this.failedCleanup.delete(id);
102
+ this.fail(contribution, err);
103
+ return Promise.resolve();
104
+ }
105
+ const gen = ++this.generation;
106
+ this.pendingId = id;
107
+ return new Promise((resolve) => {
108
+ this.whenReady(ctx, gen, (ready) => {
109
+ if (gen !== this.generation)
110
+ return resolve();
111
+ if (!ready) {
112
+ this.fail(contribution, new Error('the viewport never became ready'));
113
+ return resolve();
114
+ }
115
+ let result;
116
+ try {
117
+ result = contribution.activate(ctx);
118
+ }
119
+ catch (err) {
120
+ this.fail(contribution, err);
121
+ return resolve();
122
+ }
123
+ if (isThenable(result)) {
124
+ result.then((session) => { this.start(contribution, ctx, session, gen); resolve(); }, (err) => {
125
+ if (gen === this.generation)
126
+ this.fail(contribution, err);
127
+ resolve();
128
+ });
129
+ }
130
+ else {
131
+ this.start(contribution, ctx, result, gen);
132
+ resolve();
133
+ }
134
+ });
135
+ });
136
+ }
137
+ /**
138
+ * End the live session, if any: the component panel is dropped (via
139
+ * `onDeactivating`), a `mount` panel's teardown runs, then
140
+ * `session.deactivate()`, then the mount host is removed. Each step is
141
+ * isolated. A pending activation is cancelled; if it resolves later its
142
+ * session is deactivated on arrival. Idempotent.
143
+ */
144
+ deactivate() {
145
+ this.generation++;
146
+ this.pendingId = null;
147
+ this.cancelReadyWait();
148
+ const a = this.active;
149
+ if (!a)
150
+ return;
151
+ this.active = null;
152
+ const teardown = this.teardown;
153
+ this.teardown = null;
154
+ const id = a.contribution.descriptor.type;
155
+ this.guard(`'${id}' panel removal`, () => this.hooks.onDeactivating(a));
156
+ if (teardown)
157
+ this.cleanup(a.contribution, 'panel teardown', teardown);
158
+ this.cleanup(a.contribution, 'deactivate()', () => a.session.deactivate());
159
+ a.panelHost?.remove();
160
+ }
161
+ /**
162
+ * Forget recorded cleanup failures. The host calls this when the USER picks a
163
+ * plot type: an explicit choice gets a fresh attempt, only automatic
164
+ * re-activations fall back.
165
+ */
166
+ clearCleanupFailures() {
167
+ this.failedCleanup.clear();
168
+ }
169
+ // ── internals ──────────────────────────────────────────────────────────
170
+ start(contribution, ctx, session, gen) {
171
+ const id = contribution.descriptor.type;
172
+ if (!session || typeof session.deactivate !== 'function') {
173
+ if (gen === this.generation) {
174
+ this.fail(contribution, new Error('activate() did not return a PlotModeSession'));
175
+ }
176
+ return;
177
+ }
178
+ if (gen !== this.generation) {
179
+ // Superseded while activate() was in flight — the user already left. The
180
+ // session still gets its single deactivate(), just late.
181
+ this.guardLogged(`'${id}' deactivate() of a superseded session`, () => session.deactivate());
182
+ return;
183
+ }
184
+ this.pendingId = null;
185
+ const panel = contribution.panel;
186
+ let panelHost = null;
187
+ let teardown = null;
188
+ if (panel && 'mount' in panel && typeof panel.mount === 'function') {
189
+ panelHost = document.createElement('div');
190
+ panelHost.className = 'plot-mode-panel-host';
191
+ try {
192
+ const t = panel.mount(panelHost, ctx, session);
193
+ teardown = typeof t === 'function' ? t : null;
194
+ }
195
+ catch (err) {
196
+ panelHost.remove();
197
+ this.guardLogged(`'${id}' deactivate()`, () => session.deactivate());
198
+ this.fail(contribution, err);
199
+ return;
200
+ }
201
+ }
202
+ this.active = { contribution, ctx, session, panelHost };
203
+ this.teardown = teardown;
204
+ try {
205
+ this.hooks.onActivated(this.active);
206
+ }
207
+ catch (err) {
208
+ // The host could not show it (e.g. its panel failed to render): not a usable mode.
209
+ this.failActive(err);
210
+ }
211
+ }
212
+ /**
213
+ * The host could not make the live mode usable (its panel threw while being
214
+ * created or first rendered): end the session once, then fall back to its base.
215
+ * No-op when nothing is live.
216
+ */
217
+ failActive(err) {
218
+ const a = this.active;
219
+ if (!a)
220
+ return;
221
+ this.deactivate();
222
+ this.fail(a.contribution, err);
223
+ }
224
+ fail(contribution, err) {
225
+ this.pendingId = null;
226
+ this.log.error(`${TAG} '${contribution.descriptor.type}' failed to activate — `
227
+ + `falling back to '${contribution.descriptor.baseType}'.`, err);
228
+ try {
229
+ this.hooks.onFailed(contribution, err);
230
+ }
231
+ catch (hookErr) {
232
+ this.log.error(`${TAG} fallback failed.`, hookErr);
233
+ }
234
+ }
235
+ guard(what, fn) {
236
+ try {
237
+ fn();
238
+ }
239
+ catch (err) {
240
+ this.log.error(`${TAG} ${what} threw.`, err);
241
+ }
242
+ }
243
+ /** Like `guard`, for a contribution callback typed `void` that may still return a
244
+ * promise: a rejection is logged instead of escaping as an unhandled rejection. */
245
+ guardLogged(what, fn) {
246
+ try {
247
+ const r = fn();
248
+ if (isThenable(r))
249
+ r.then(undefined, (err) => this.log.error(`${TAG} ${what} rejected.`, err));
250
+ }
251
+ catch (err) {
252
+ this.log.error(`${TAG} ${what} threw.`, err);
253
+ }
254
+ }
255
+ /** Run a live session's cleanup; a throw OR a rejection goes to `cleanupFailed`. */
256
+ cleanup(contribution, what, fn) {
257
+ try {
258
+ const r = fn();
259
+ if (isThenable(r))
260
+ r.then(undefined, (err) => this.cleanupFailed(contribution, what, err));
261
+ }
262
+ catch (err) {
263
+ this.cleanupFailed(contribution, what, err);
264
+ }
265
+ }
266
+ /**
267
+ * A contribution's cleanup failed. If that same contribution is live or starting
268
+ * again (a base re-render / image switch re-activated it — or, for an async
269
+ * rejection, already has), end it and fall back to its base type. Otherwise the
270
+ * user has moved on: remember it, so the next automatic re-activation falls back.
271
+ */
272
+ cleanupFailed(contribution, what, err) {
273
+ const id = contribution.descriptor.type;
274
+ this.log.error(`${TAG} '${id}' ${what} failed.`, err);
275
+ const again = this.active?.contribution === contribution || this.pendingId === id;
276
+ if (again) {
277
+ this.deactivate();
278
+ this.fail(contribution, err);
279
+ }
280
+ else {
281
+ this.failedCleanup.set(id, err);
282
+ }
283
+ }
284
+ /** Call `cb(true)` once the viewport reports ready (now, or on a later
285
+ * animation frame), or `cb(false)` after {@link MAX_READY_FRAMES}. */
286
+ whenReady(ctx, gen, cb) {
287
+ const isReady = () => {
288
+ try {
289
+ return ctx.viewport.isReady();
290
+ }
291
+ catch {
292
+ return false;
293
+ }
294
+ };
295
+ if (isReady())
296
+ return cb(true);
297
+ let frames = 0;
298
+ const settle = (ready) => {
299
+ this.readyFrame = null;
300
+ this.readyCb = null;
301
+ cb(ready);
302
+ };
303
+ const tick = () => {
304
+ this.readyFrame = null;
305
+ if (gen !== this.generation)
306
+ return settle(false);
307
+ if (isReady())
308
+ return settle(true);
309
+ if (++frames >= MAX_READY_FRAMES)
310
+ return settle(false);
311
+ this.readyFrame = requestAnimationFrame(tick);
312
+ };
313
+ this.readyCb = settle;
314
+ this.readyFrame = requestAnimationFrame(tick);
315
+ }
316
+ /** Stop waiting for the viewport; the waiting activation resolves as superseded. */
317
+ cancelReadyWait() {
318
+ if (this.readyFrame !== null)
319
+ cancelAnimationFrame(this.readyFrame);
320
+ this.readyFrame = null;
321
+ const cb = this.readyCb;
322
+ this.readyCb = null;
323
+ cb?.(false);
324
+ }
325
+ }
326
+ function isThenable(v) {
327
+ return !!v && typeof v.then === 'function';
328
+ }
329
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxvdC1tb2RlLWNvbnRyb2xsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3Bsb3QtbW9kZS9wbG90LW1vZGUtY29udHJvbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFjLGlCQUFpQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFpRGpGLGlFQUFpRTtBQUNqRSxNQUFNLENBQUMsTUFBTSxpQ0FBaUMsR0FBd0IsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7QUFFdkYsMkVBQTJFO0FBQzNFLE1BQU0sZ0JBQWdCLEdBQUcsR0FBRyxDQUFDO0FBRTdCLE1BQU0sR0FBRyxHQUFHLHFDQUFxQyxDQUFDO0FBRWxEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxVQUFVLHNCQUFzQixDQUNwQyxHQUEwQyxFQUMxQyxNQUFzQixPQUFPO0lBRTdCLE1BQU0sR0FBRyxHQUEyQixFQUFFLENBQUM7SUFDdkMsTUFBTSxJQUFJLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUMvQixNQUFNLElBQUksR0FBRyxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RSxLQUFLLE1BQU0sQ0FBQyxJQUFJLElBQThCLEVBQUUsQ0FBQztRQUMvQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsVUFBdUQsQ0FBQztRQUNyRSxNQUFNLEVBQUUsR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDO1FBQ25CLElBQUksQ0FBQyxDQUFDLElBQUksT0FBTyxFQUFFLEtBQUssUUFBUSxJQUFJLENBQUMsRUFBRSxJQUFJLE9BQU8sQ0FBQyxDQUFDLFFB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UUFDeEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFDcEIsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDZCxDQUFDO0NBQ0Y7QUFFRCxTQUFTLFVBQVUsQ0FBSSxDQUEyQjtJQUNoRCxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBUSxDQUFnQixDQUFDLElBQUksS0FBSyxVQUFVLENBQUM7QUFDN0QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFBsb3RUeXBlLCBQbG90VHlwZUlkLCBpc0J1aWx0aW5QbG90VHlwZSB9IGZyb20gJy4uL2NvbnRyYWN0cy9wbG90LXR5cGUnO1xuaW1wb3J0IHtcbiAgQ29udHJpYnV0ZWRQbG90VHlwZURlc2NyaXB0b3IsXG4gIFBsb3RNb2RlQ29udGV4dCxcbiAgUGxvdE1vZGVTZXNzaW9uLFxuICBQbG90VHlwZUNvbnRyaWJ1dGlvbixcbn0gZnJvbSAnLi4vY29udHJhY3RzL3Bsb3QtdHlwZS1jb250cmlidXRpb24uY29udHJhY3QnO1xuXG4vKipcbiAqIExpZmVjeWNsZSBvZiB0aGUgY29udHJpYnV0ZWQgcGxvdCBtb2RlcyAoe0BsaW5rIFBsb3RUeXBlQ29udHJpYnV0aW9ufSkgZm9yIG9uZVxuICogdmlzdWFsaXplciBpbnN0YW5jZS4gUGFja2FnZS1pbnRlcm5hbDogdGhlIHZpc3VhbGl6ZXIgY29tcG9uZW50IG93bnMgb25lIGFuZFxuICogZHJpdmVzIGl0IGZyb20gaXRzIHJlbmRlciBwaXBlbGluZS5cbiAqXG4gKiBPd25zIHRocmVlIHRoaW5ncyB0aGUgY29tcG9uZW50IHNob3VsZCBub3QgaGF2ZSB0byByZWFzb24gYWJvdXQ6XG4gKiAgLSB3aGljaCBjb250cmlidXRpb25zIGFyZSB1c2FibGUgKHZhbGlkYXRlZCBhbmQgZGUtZHVwbGljYXRlZCBvbmNlKTtcbiAqICAtIHRoZSBzaW5nbGUgbGl2ZSBzZXNzaW9uLCBzbyBgZGVhY3RpdmF0ZSgpYCBydW5zIGV4YWN0bHkgb25jZSBwZXIgc2Vzc2lvblxuICogICAgaG93ZXZlciBtYW55IGV4aXRzIHJhY2UgZWFjaCBvdGhlciAodHlwZSBjaGFuZ2UsIGltYWdlIGNoYW5nZSwgZGVzdHJveSxcbiAqICAgIGEgc3VwZXJzZWRlZCBhc3luYyBhY3RpdmF0aW9uKTtcbiAqICAtIGlzb2xhdGlvbjogbm90aGluZyBhIGNvbnRyaWJ1dGlvbiB0aHJvd3Mgb3IgcmVqZWN0cyBlc2NhcGVzIHRoaXMgY2xhc3MuXG4gKiAgICBBIGZhaWx1cmUgaXMgbG9nZ2VkIGFuZCByZXBvcnRlZCB0aHJvdWdoIGBvbkZhaWxlZGAsIGFuZCB0aGUgY29tcG9uZW50XG4gKiAgICBmYWxscyBiYWNrIHRvIHRoZSBtb2RlJ3MgYmFzZSB0eXBlLlxuICovXG5cbi8qKiBUaGUgbGl2ZSBhY3RpdmF0aW9uIG9mIGEgY29udHJpYnV0ZWQgbW9kZSwgYXMgdGhlIGNvbXBvbmVudCByZW5kZXJzIGl0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBBY3RpdmVQbG90TW9kZSB7XG4gIHJlYWRvbmx5IGNvbnRyaWJ1dGlvbjogUGxvdFR5cGVDb250cmlidXRpb247XG4gIHJlYWRvbmx5IGN0eDogUGxvdE1vZGVDb250ZXh0O1xuICByZWFkb25seSBzZXNzaW9uOiBQbG90TW9kZVNlc3Npb247XG4gIC8qKiBIb3N0IGVsZW1lbnQgaGFuZGVkIHRvIGEgYG1vdW50YCBwYW5lbCwgb3IgbnVsbCBmb3IgYSBjb21wb25lbnQgLyBubyBwYW5lbC4gKi9cbiAgcmVhZG9ubHkgcGFuZWxIb3N0OiBIVE1MRWxlbWVudCB8IG51bGw7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGxvdE1vZGVDb250cm9sbGVySG9va3Mge1xuICAvKiogQSBzZXNzaW9uIGlzIGxpdmUgKGFuZCBhIGBtb3VudGAgcGFuZWwsIGlmIGFueSwgaGFzIGJlZW4gbW91bnRlZCkuICovXG4gIG9uQWN0aXZhdGVkKGFjdGl2ZTogQWN0aXZlUGxvdE1vZGUpOiB2b2lkO1xuICAvKiogVGhlIGxpdmUgc2Vzc2lvbiBpcyBhYm91dCB0byBlbmQuIENhbGxlZCBCRUZPUkUgYW55IHRlYXJkb3duLCBzbyBhXG4gICAqICBjb21wb25lbnQgcGFuZWwgY2FuIGJlIGRlc3Ryb3llZCB3aGlsZSBpdHMgc2Vzc2lvbiBpcyBzdGlsbCB2YWxpZC4gKi9cbiAgb25EZWFjdGl2YXRpbmcoYWN0aXZlOiBBY3RpdmVQbG90TW9kZSk6IHZvaWQ7XG4gIC8qKiBBY3RpdmF0aW9uIGZhaWxlZCAodGhyZXcsIHJlamVjdGVkLCBuZXZlciBnb3QgYSByZWFkeSB2aWV3cG9ydCwgb3IgaXRzXG4gICAqICBwYW5lbCBmYWlsZWQgdG8gbW91bnQpLiBUaGUgY29tcG9uZW50IGZhbGxzIGJhY2sgdG8gdGhlIGJhc2UgdHlwZS4gKi9cbiAgb25GYWlsZWQoY29udHJpYnV0aW9uOiBQbG90VHlwZUNvbnRyaWJ1dGlvbiwgZXJyb3I6IHVua25vd24pOiB2b2lkO1xufVxuXG4vKiogTWluaW1hbCBsb2dnZXIsIGluamVjdGFibGUgZm9yIHRlc3RzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBQbG90TW9kZUxvZ2dlciB7XG4gIHdhcm4oLi4uYXJnczogdW5rbm93bltdKTogdm9pZDtcbiAgZXJyb3IoLi4uYXJnczogdW5rbm93bltdKTogdm9pZDtcbn1cblxuLyoqIEJhc2UgdHlwZXMgYSBjb250cmlidXRlZCBtb2RlIGNhbiByaWRlIG9uIGluIHRoaXMgdmVyc2lvbi4gKi9cbmV4cG9ydCBjb25zdCBTVVBQT1JURURfQ09OVFJJQlVUSU9OX0JBU0VfVFlQRVM6IHJlYWRvbmx5IFBsb3RUeXBlW10gPSBbUGxvdFR5cGUuSU1BR0VdO1xuXG4vKiogSG93IG1hbnkgYW5pbWF0aW9uIGZyYW1lcyB0byB3YWl0IGZvciB0aGUgdmlld3BvcnQgYmVmb3JlIGdpdmluZyB1cC4gKi9cbmNvbnN0IE1BWF9SRUFEWV9GUkFNRVMgPSAxODA7XG5cbmNvbnN0IFRBRyA9ICdbdmlzdWFsaXplcl0gcGxvdC10eXBlIGNvbnRyaWJ1dGlvbic7XG5cbi8qKlxuICogVmFsaWRhdGUgd2hhdCBhcnJpdmVkIG9uIGBQTE9UX1RZUEVfQ09OVFJJQlVUSU9OU2AuIEEgbWFsZm9ybWVkIG9yIGNsYXNoaW5nXG4gKiBjb250cmlidXRpb24gaXMgZHJvcHBlZCB3aXRoIGEgd2FybmluZyByYXRoZXIgdGhhbiBicmVha2luZyB0aGUgc2VsZWN0b3I6XG4gKiAgLSBhIG5lc3RlZCBhcnJheSAoYHVzZVZhbHVlOiBbYSwgYl0sIG11bHRpOiB0cnVlYCkgaXMgZmxhdHRlbmVkIG9uZSBsZXZlbDtcbiAqICAtIGB0eXBlYCBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZyB0aGF0IGlzIG5vdCBhIGJ1aWx0LWluIGBQbG90VHlwZWAgdmFsdWU7XG4gKiAgLSB0aGUgZmlyc3QgY29udHJpYnV0aW9uIHdpdGggYSBnaXZlbiBgdHlwZWAgd2lucztcbiAqICAtIGBiYXNlVHlwZWAgbXVzdCBiZSBvbmUgb2Yge0BsaW5rIFNVUFBPUlRFRF9DT05UUklCVVRJT05fQkFTRV9UWVBFU307XG4gKiAgLSBgYWN0aXZhdGVgIG11c3QgYmUgYSBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZUNvbnRyaWJ1dGlvbnMoXG4gIHJhdzogcmVhZG9ubHkgdW5rbm93bltdIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgbG9nOiBQbG90TW9kZUxvZ2dlciA9IGNvbnNvbGUsXG4pOiBQbG90VHlwZUNvbnRyaWJ1dGlvbltdIHtcbiAgY29uc3Qgb3V0OiBQbG90VHlwZUNvbnRyaWJ1dGlvbltdID0gW107XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgY29uc3QgZmxhdCA9IChyYXcgPz8gW10pLmZsYXRNYXAoKGMpID0+IChBcnJheS5pc0FycmF5KGMpID8gYyA6IFtjXSkpO1xuICBmb3IgKGNvbnN0IGMgb2YgZmxhdCBhcyBQbG90VHlwZUNvbnRyaWJ1dGlvbltdKSB7XG4gICAgY29uc3QgZCA9IGM/LmRlc2NyaXB0b3IgYXMgQ29udHJpYnV0ZWRQbG90VHlwZURlc2NyaXB0b3IgfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgaWQgPSBkPy50eXBlO1xuICAgIGlmICghZCB8fCB0eXBlb2YgaWQgIT09ICdzdHJpbmcnIHx8ICFpZCB8fCB0eXBlb2YgYy5hY3RpdmF0ZSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgbG9nLndhcm4oYCR7VEFHfSBpZ25vcmVkOiBpdCBuZWVkcyBhIGRlc2NyaXB0b3Igd2l0aCBhIHN0cmluZyBcXGB0eXBlXFxgIGFuZCBhbiBcXGBhY3RpdmF0ZVxcYCBmdW5jdGlvbi5gLCBjKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZiAoaXNCdWlsdGluUGxvdFR5cGUoaWQpKSB7XG4gICAgICBsb2cud2FybihgJHtUQUd9ICcke2lkfScgaWdub3JlZDogdGhlIGlkIGNsYXNoZXMgd2l0aCBhIGJ1aWx0LWluIHBsb3QgdHlwZS5gKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZiAoc2Vlbi5oYXMoaWQpKSB7XG4gICAgICBsb2cud2FybihgJHtUQUd9ICcke2lkfScgaWdub3JlZDogYW5vdGhlciBjb250cmlidXRpb24gYWxyZWFkeSB1c2VzIHRoYXQgaWQuYCk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWYgKCFTVVBQT1JURURfQ09OVFJJQlVUSU9OX0JBU0VfVFlQRVMuaW5jbHVkZXMoZC5iYXNlVHlwZSkpIHtcbiAgICAgIGxvZy53YXJuKGAke1RBR30gJyR7aWR9JyBpZ25vcmVkOiBiYXNlVHlwZSAnJHtTdHJpbmcoZC5iYXNlVHlwZSl9JyBpcyBub3Qgc3VwcG9ydGVkIGBcbiAgICAgICAgKyBgKHN1cHBvcnRlZDogJHtTVVBQT1JURURfQ09OVFJJQlVUSU9OX0JBU0VfVFlQRVMuam9pbignLCAnKX0pLmApO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHNlZW4uYWRkKGlkKTtcbiAgICBvdXQucHVzaChjKTtcbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG5leHBvcnQgY2xhc3MgUGxvdE1vZGVDb250cm9sbGVyIHtcbiAgcmVhZG9ubHkgY29udHJpYnV0aW9uczogcmVhZG9ubHkgUGxvdFR5cGVDb250cmlidXRpb25bXTtcbiAgcHJpdmF0ZSByZWFkb25seSBieUlkOiBSZWFkb25seU1hcDxzdHJpbmcsIFBsb3RUeXBlQ29udHJpYnV0aW9uPjtcblxuICBwcml2YXRlIGFjdGl2ZTogQWN0aXZlUGxvdE1vZGUgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSB0ZWFyZG93bjogKCgpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBCdW1wZWQgYnkgZXZlcnkgYWN0aXZhdGUvZGVhY3RpdmF0ZSwgc28gYSBwZW5kaW5nIGFzeW5jIGFjdGl2YXRpb24gY2FuXG4gICAqICB0ZWxsIGl0IGhhcyBiZWVuIHN1cGVyc2VkZWQuICovXG4gIHByaXZhdGUgZ2VuZXJhdGlvbiA9IDA7XG4gIHByaXZhdGUgcmVhZHlGcmFtZTogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBDb250cmlidXRpb25zIHdob3NlIGxhc3QgY2xlYW51cCAocGFuZWwgdGVhcmRvd24gLyBgZGVhY3RpdmF0ZSgpYCkgdGhyZXcgb3JcbiAgICogIHJlamVjdGVkLiBUaGVpciBuZXh0IGF1dG9tYXRpYyByZS1hY3RpdmF0aW9uIChiYXNlIHJlLXJlbmRlciwgaW1hZ2Ugc3dpdGNoKVxuICAgKiAgZmFsbHMgYmFjayB0byB0aGUgYmFzZSB0eXBlIGluc3RlYWQ7IGFuIGV4cGxpY2l0IHNlbGVjdGlvbiBjbGVhcnMgdGhlIG1hcmsuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgZmFpbGVkQ2xlYW51cCA9IG5ldyBNYXA8c3RyaW5nLCB1bmtub3duPigpO1xuICBwcml2YXRlIHJlYWR5Q2I6ICgocmVhZHk6IGJvb2xlYW4pID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcmF3OiByZWFkb25seSB1bmtub3duW10gfCBudWxsIHwgdW5kZWZpbmVkLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgaG9va3M6IFBsb3RNb2RlQ29udHJvbGxlckhvb2tzLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbG9nOiBQbG90TW9kZUxvZ2dlciA9IGNvbnNvbGUsXG4gICkge1xuICAgIHRoaXMuY29udHJpYnV0aW9ucyA9IG5vcm1hbGl6ZUNvbnRyaWJ1dGlvbnMocmF3LCBsb2cpO1xuICAgIHRoaXMuYnlJZCA9IG5ldyBNYXAodGhpcy5jb250cmlidXRpb25zLm1hcCgoYykgPT4gW2MuZGVzY3JpcHRvci50eXBlLCBjXSkpO1xuICB9XG5cbiAgLyoqIERlc2NyaXB0b3JzIG9mIHRoZSB1c2FibGUgY29udHJpYnV0aW9ucywgaW4gcmVnaXN0cmF0aW9uIG9yZGVyLiAqL1xuICBkZXNjcmlwdG9ycygpOiBDb250cmlidXRlZFBsb3RUeXBlRGVzY3JpcHRvcltdIHtcbiAgICByZXR1cm4gdGhpcy5jb250cmlidXRpb25zLm1hcCgoYykgPT4gYy5kZXNjcmlwdG9yKTtcbiAgfVxuXG4gIC8qKiBUaGUgY29udHJpYnV0aW9uIGZvciBhIHNlbGVjdG9yIGlkLCBpZiBpdCBpcyBhIGNvbnRyaWJ1dGVkIG1vZGUuICovXG4gIGZpbmQoaWQ6IFBsb3RUeXBlSWQgfCBudWxsIHwgdW5kZWZpbmVkKTogUGxvdFR5cGVDb250cmlidXRpb24gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0eXBlb2YgaWQgPT09ICdzdHJpbmcnID8gdGhpcy5ieUlkLmdldChpZCkgOiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGJ1aWx0LWluIHR5cGUgdGhhdCByZW5kZXJzIGBpZGA6IGEgYnVpbHQtaW4gdHlwZSBpcyBpdHNlbGYsIGFcbiAgICogY29udHJpYnV0ZWQgaWQgaXMgaXRzIGBiYXNlVHlwZWAsIGFuZCBhbiBpZCB0aGF0IGlzIG5laXRoZXIgKGEgc3RhbGVcbiAgICogY29udHJpYnV0ZWQgaWQgd2hvc2UgcHJvdmlkZXIgaXMgZ29uZSkgcmVzb2x2ZXMgdG8gYFBsb3RUeXBlLklNQUdFYCwgdGhlXG4gICAqIGRlZmF1bHQgdmlldy5cbiAgICovXG4gIGJhc2VUeXBlT2YoaWQ6IFBsb3RUeXBlSWQgfCBudWxsIHwgdW5kZWZpbmVkKTogUGxvdFR5cGUge1xuICAgIGlmIChpc0J1aWx0aW5QbG90VHlwZShpZCkpIHJldHVybiBpZDtcbiAgICByZXR1cm4gdGhpcy5maW5kKGlkKT8uZGVzY3JpcHRvci5iYXNlVHlwZSA/PyBQbG90VHlwZS5JTUFHRTtcbiAgfVxuXG4gIC8qKiBUaGUgbGl2ZSBzZXNzaW9uLCBpZiBhbnkuICovXG4gIGdldCBjdXJyZW50KCk6IEFjdGl2ZVBsb3RNb2RlIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlO1xuICB9XG5cbiAgLyoqIFdoZXRoZXIgYW4gYWN0aXZhdGlvbiBpcyB3YWl0aW5nIG9uIHRoZSBjb250cmlidXRpb24gb3IgdGhlIHZpZXdwb3J0LiAqL1xuICBnZXQgcGVuZGluZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5wZW5kaW5nSWQgIT09IG51bGw7XG4gIH1cbiAgcHJpdmF0ZSBwZW5kaW5nSWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBTdGFydCBhIHNlc3Npb24gZm9yIGBjb250cmlidXRpb25gLiBFbmRzIGFueSBsaXZlIG9uZSBmaXJzdC4gUmVzb2x2ZXMgd2hlblxuICAgKiB0aGUgYXR0ZW1wdCBoYXMgZmluaXNoZWQgKHN1Y2Nlc3NmdWxseSBvciBub3QpOyBpdCBuZXZlciByZWplY3RzLlxuICAgKi9cbiAgYWN0aXZhdGUoY29udHJpYnV0aW9uOiBQbG90VHlwZUNvbnRyaWJ1dGlvbiwgY3R4OiBQbG90TW9kZUNvbnRleHQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmRlYWN0aXZhdGUoKTtcbiAgICBjb25zdCBpZCA9IGNvbnRyaWJ1dGlvbi5kZXNjcmlwdG9yLnR5cGU7XG4gICAgaWYgKHRoaXMuZmFpbGVkQ2xlYW51cC5oYXMoaWQpKSB7XG4gICAgICAvLyBJdHMgcHJldmlvdXMgc2Vzc2lvbiBkaWQgbm90IGVuZCBjbGVhbmx5OyBkbyBub3Qgc3RhY2sgYSBuZXcgb25lIG9uIHRvcC5cbiAgICAgIGNvbnN0IGVyciA9IHRoaXMuZmFpbGVkQ2xlYW51cC5nZXQoaWQpO1xuICAgICAgdGhpcy5mYWlsZWRDbGVhbnVwLmRlbGV0ZShpZCk7XG4gICAgICB0aGlzLmZhaWwoY29udHJpYnV0aW9uLCBlcnIpO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH1cbiAgICBjb25zdCBnZW4gPSArK3RoaXMuZ2VuZXJhdGlvbjtcbiAgICB0aGlzLnBlbmRpbmdJZCA9IGlkO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgdGhpcy53aGVuUmVhZHkoY3R4LCBnZW4sIChyZWFkeSkgPT4ge1xuICAgICAgICBpZiAoZ2VuICE9PSB0aGlzLmdlbmVyYXRpb24pIHJldHVybiByZXNvbHZlKCk7XG4gICAgICAgIGlmICghcmVhZHkpIHtcbiAgICAgICAgICB0aGlzLmZhaWwoY29udHJpYnV0aW9uLCBuZXcgRXJyb3IoJ3RoZSB2aWV3cG9ydCBuZXZlciBiZWNhbWUgcmVhZHknKSk7XG4gICAgICAgICAgcmV0dXJuIHJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcmVzdWx0OiBQbG90TW9kZVNlc3Npb24gfCBQcm9taXNlPFBsb3RNb2RlU2Vzc2lvbj47XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcmVzdWx0ID0gY29udHJpYnV0aW9uLmFjdGl2YXRlKGN0eCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIHRoaXMuZmFpbChjb250cmlidXRpb24sIGVycik7XG4gICAgICAgICAgcmV0dXJuIHJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNUaGVuYWJsZShyZXN1bHQpKSB7XG4gICAgICAgICAgcmVzdWx0LnRoZW4oXG4gICAgICAgICAgICAoc2Vzc2lvbikgPT4geyB0aGlzLnN0YXJ0KGNvbnRyaWJ1dGlvbiwgY3R4LCBzZXNzaW9uLCBnZW4pOyByZXNvbHZlKCk7IH0sXG4gICAgICAgICAgICAoZXJyKSA9PiB7XG4gICAgICAgICAgICAgIGlmIChnZW4gPT09IHRoaXMuZ2VuZXJhdGlvbikgdGhpcy5mYWlsKGNvbnRyaWJ1dGlvbiwgZXJyKTtcbiAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc3RhcnQoY29udHJpYnV0aW9uLCBjdHgsIHJlc3VsdCwgZ2VuKTtcbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuZCB0aGUgbGl2ZSBzZXNzaW9uLCBpZiBhbnk6IHRoZSBjb21wb25lbnQgcGFuZWwgaXMgZHJvcHBlZCAodmlhXG4gICAqIGBvbkRlYWN0aXZhdGluZ2ApLCBhIGBtb3VudGAgcGFuZWwncyB0ZWFyZG93biBydW5zLCB0aGVuXG4gICAqIGBzZXNzaW9uLmRlYWN0aXZhdGUoKWAsIHRoZW4gdGhlIG1vdW50IGhvc3QgaXMgcmVtb3ZlZC4gRWFjaCBzdGVwIGlzXG4gICAqIGlzb2xhdGVkLiBBIHBlbmRpbmcgYWN0aXZhdGlvbiBpcyBjYW5jZWxsZWQ7IGlmIGl0IHJlc29sdmVzIGxhdGVyIGl0c1xuICAgKiBzZXNzaW9uIGlzIGRlYWN0aXZhdGVkIG9uIGFycml2YWwuIElkZW1wb3RlbnQuXG4gICAqL1xuICBkZWFjdGl2YXRlKCk6IHZvaWQge1xuICAgIHRoaXMuZ2VuZXJhdGlvbisrO1xuICAgIHRoaXMucGVuZGluZ0lkID0gbnVsbDtcbiAgICB0aGlzLmNhbmNlbFJlYWR5V2FpdCgpO1xuICAgIGNvbnN0IGEgPSB0aGlzLmFjdGl2ZTtcbiAgICBpZiAoIWEpIHJldHVybjtcbiAgICB0aGlzLmFjdGl2ZSA9IG51bGw7XG4gICAgY29uc3QgdGVhcmRvd24gPSB0aGlzLnRlYXJkb3duO1xuICAgIHRoaXMudGVhcmRvd24gPSBudWxsO1xuICAgIGNvbnN0IGlkID0gYS5jb250cmlidXRpb24uZGVzY3JpcHRvci50eXBlO1xuICAgIHRoaXMuZ3VhcmQoYCcke2lkfScgcGFuZWwgcmVtb3ZhbGAsICgpID0+IHRoaXMuaG9va3Mub25EZWFjdGl2YXRpbmcoYSkpO1xuICAgIGlmICh0ZWFyZG93bikgdGhpcy5jbGVhbnVwKGEuY29udHJpYnV0aW9uLCAncGFuZWwgdGVhcmRvd24nLCB0ZWFyZG93bik7XG4gICAgdGhpcy5jbGVhbnVwKGEuY29udHJpYnV0aW9uLCAnZGVhY3RpdmF0ZSgpJywgKCkgPT4gYS5zZXNzaW9uLmRlYWN0aXZhdGUoKSk7XG4gICAgYS5wYW5lbEhvc3Q/LnJlbW92ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZvcmdldCByZWNvcmRlZCBjbGVhbnVwIGZhaWx1cmVzLiBUaGUgaG9zdCBjYWxscyB0aGlzIHdoZW4gdGhlIFVTRVIgcGlja3MgYVxuICAgKiBwbG90IHR5cGU6IGFuIGV4cGxpY2l0IGNob2ljZSBnZXRzIGEgZnJlc2ggYXR0ZW1wdCwgb25seSBhdXRvbWF0aWNcbiAgICogcmUtYWN0aXZhdGlvbnMgZmFsbCBiYWNrLlxuICAgKi9cbiAgY2xlYXJDbGVhbnVwRmFpbHVyZXMoKTogdm9pZCB7XG4gICAgdGhpcy5mYWlsZWRDbGVhbnVwLmNsZWFyKCk7XG4gIH1cblxuICAvLyDilIDilIAgaW50ZXJuYWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgc3RhcnQoY29udHJpYnV0aW9uOiBQbG90VHlwZUNvbnRyaWJ1dGlvbiwgY3R4OiBQbG90TW9kZUNvbnRleHQsXG4gICAgICAgICAgICAgICAgc2Vzc2lvbjogUGxvdE1vZGVTZXNzaW9uLCBnZW46IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IGlkID0gY29udHJpYnV0aW9uLmRlc2NyaXB0b3IudHlwZTtcbiAgICBpZiAoIXNlc3Npb24gfHwgdHlwZW9mIHNlc3Npb24uZGVhY3RpdmF0ZSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgaWYgKGdlbiA9PT0gdGhpcy5nZW5lcmF0aW9uKSB7XG4gICAgICAgIHRoaXMuZmFpbChjb250cmlidXRpb24sIG5ldyBFcnJvcignYWN0aXZhdGUoKSBkaWQgbm90IHJldHVybiBhIFBsb3RNb2RlU2Vzc2lvbicpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKGdlbiAhPT0gdGhpcy5nZW5lcmF0aW9uKSB7XG4gICAgICAvLyBTdXBlcnNlZGVkIHdoaWxlIGFjdGl2YXRlKCkgd2FzIGluIGZsaWdodCDigJQgdGhlIHVzZXIgYWxyZWFkeSBsZWZ0LiBUaGVcbiAgICAgIC8vIHNlc3Npb24gc3RpbGwgZ2V0cyBpdHMgc2luZ2xlIGRlYWN0aXZhdGUoKSwganVzdCBsYXRlLlxuICAgICAgdGhpcy5ndWFyZExvZ2dlZChgJyR7aWR9JyBkZWFjdGl2YXRlKCkgb2YgYSBzdXBlcnNlZGVkIHNlc3Npb25gLCAoKSA9PiBzZXNzaW9uLmRlYWN0aXZhdGUoKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMucGVuZGluZ0lkID0gbnVsbDtcbiAgICBjb25zdCBwYW5lbCA9IGNvbnRyaWJ1dGlvbi5wYW5lbDtcbiAgICBsZXQgcGFuZWxIb3N0OiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuICAgIGxldCB0ZWFyZG93bjogKCgpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG4gICAgaWYgKHBhbmVsICYmICdtb3VudCcgaW4gcGFuZWwgJiYgdHlwZW9mIHBhbmVsLm1vdW50ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBwYW5lbEhvc3QgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgIHBhbmVsSG9zdC5jbGFzc05hbWUgPSAncGxvdC1tb2RlLXBhbmVsLWhvc3QnO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgdCA9IHBhbmVsLm1vdW50KHBhbmVsSG9zdCwgY3R4LCBzZXNzaW9uKTtcbiAgICAgICAgdGVhcmRvd24gPSB0eXBlb2YgdCA9PT0gJ2Z1bmN0aW9uJyA/IHQgOiBudWxsO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHBhbmVsSG9zdC5yZW1vdmUoKTtcbiAgICAgICAgdGhpcy5ndWFyZExvZ2dlZChgJyR7aWR9JyBkZWFjdGl2YXRlKClgLCAoKSA9PiBzZXNzaW9uLmRlYWN0aXZhdGUoKSk7XG4gICAgICAgIHRoaXMuZmFpbChjb250cmlidXRpb24sIGVycik7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5hY3RpdmUgPSB7IGNvbnRyaWJ1dGlvbiwgY3R4LCBzZXNzaW9uLCBwYW5lbEhvc3QgfTtcbiAgICB0aGlzLnRlYXJkb3duID0gdGVhcmRvd247XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuaG9va3Mub25BY3RpdmF0ZWQodGhpcy5hY3RpdmUpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gVGhlIGhvc3QgY291bGQgbm90IHNob3cgaXQgKGUuZy4gaXRzIHBhbmVsIGZhaWxlZCB0byByZW5kZXIpOiBub3QgYSB1c2FibGUgbW9kZS5cbiAgICAgIHRoaXMuZmFpbEFjdGl2ZShlcnIpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgaG9zdCBjb3VsZCBub3QgbWFrZSB0aGUgbGl2ZSBtb2RlIHVzYWJsZSAoaXRzIHBhbmVsIHRocmV3IHdoaWxlIGJlaW5nXG4gICAqIGNyZWF0ZWQgb3IgZmlyc3QgcmVuZGVyZWQpOiBlbmQgdGhlIHNlc3Npb24gb25jZSwgdGhlbiBmYWxsIGJhY2sgdG8gaXRzIGJhc2UuXG4gICAqIE5vLW9wIHdoZW4gbm90aGluZyBpcyBsaXZlLlxuICAgKi9cbiAgZmFpbEFjdGl2ZShlcnI6IHVua25vd24pOiB2b2lkIHtcbiAgICBjb25zdCBhID0gdGhpcy5hY3RpdmU7XG4gICAgaWYgKCFhKSByZXR1cm47XG4gICAgdGhpcy5kZWFjdGl2YXRlKCk7XG4gICAgdGhpcy5mYWlsKGEuY29udHJpYnV0aW9uLCBlcnIpO1xuICB9XG5cbiAgcHJpdmF0ZSBmYWlsKGNvbnRyaWJ1dGlvbjogUGxvdFR5cGVDb250cmlidXRpb24sIGVycjogdW5rbm93bik6IHZvaWQge1xuICAgIHRoaXMucGVuZGluZ0lkID0gbnVsbDtcbiAgICB0aGlzLmxvZy5lcnJvcihgJHtUQUd9ICcke2NvbnRyaWJ1dGlvbi5kZXNjcmlwdG9yLnR5cGV9JyBmYWlsZWQgdG8gYWN0aXZhdGUg4oCUIGBcbiAgICAgICsgYGZhbGxpbmcgYmFjayB0byAnJHtjb250cmlidXRpb24uZGVzY3JpcHRvci5iYXNlVHlwZX0nLmAsIGVycik7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuaG9va3Mub25GYWlsZWQoY29udHJpYnV0aW9uLCBlcnIpO1xuICAgIH0gY2F0Y2ggKGhvb2tFcnIpIHtcbiAgICAgIHRoaXMubG9nLmVycm9yKGAke1RBR30gZmFsbGJhY2sgZmFpbGVkLmAsIGhvb2tFcnIpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ3VhcmQod2hhdDogc3RyaW5nLCBmbjogKCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICBmbigpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5sb2cuZXJyb3IoYCR7VEFHfSAke3doYXR9IHRocmV3LmAsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqIExpa2UgYGd1YXJkYCwgZm9yIGEgY29udHJpYnV0aW9uIGNhbGxiYWNrIHR5cGVkIGB2b2lkYCB0aGF0IG1heSBzdGlsbCByZXR1cm4gYVxuICAgKiAgcHJvbWlzZTogYSByZWplY3Rpb24gaXMgbG9nZ2VkIGluc3RlYWQgb2YgZXNjYXBpbmcgYXMgYW4gdW5oYW5kbGVkIHJlamVjdGlvbi4gKi9cbiAgcHJpdmF0ZSBndWFyZExvZ2dlZCh3aGF0OiBzdHJpbmcsIGZuOiAoKSA9PiB1bmtub3duKTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHIgPSBmbigpO1xuICAgICAgaWYgKGlzVGhlbmFibGUocikpIHIudGhlbih1bmRlZmluZWQsIChlcnIpID0+IHRoaXMubG9nLmVycm9yKGAke1RBR30gJHt3aGF0fSByZWplY3RlZC5gLCBlcnIpKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMubG9nLmVycm9yKGAke1RBR30gJHt3aGF0fSB0aHJldy5gLCBlcnIpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBSdW4gYSBsaXZlIHNlc3Npb24ncyBjbGVhbnVwOyBhIHRocm93IE9SIGEgcmVqZWN0aW9uIGdvZXMgdG8gYGNsZWFudXBGYWlsZWRgLiAqL1xuICBwcml2YXRlIGNsZWFudXAoY29udHJpYnV0aW9uOiBQbG90VHlwZUNvbnRyaWJ1dGlvbiwgd2hhdDogc3RyaW5nLCBmbjogKCkgPT4gdW5rbm93bik6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByID0gZm4oKTtcbiAgICAgIGlmIChpc1RoZW5hYmxlKHIpKSByLnRoZW4odW5kZWZpbmVkLCAoZXJyKSA9PiB0aGlzLmNsZWFudXBGYWlsZWQoY29udHJpYnV0aW9uLCB3aGF0LCBlcnIpKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuY2xlYW51cEZhaWxlZChjb250cmlidXRpb24sIHdoYXQsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEEgY29udHJpYnV0aW9uJ3MgY2xlYW51cCBmYWlsZWQuIElmIHRoYXQgc2FtZSBjb250cmlidXRpb24gaXMgbGl2ZSBvciBzdGFydGluZ1xuICAgKiBhZ2FpbiAoYSBiYXNlIHJlLXJlbmRlciAvIGltYWdlIHN3aXRjaCByZS1hY3RpdmF0ZWQgaXQg4oCUIG9yLCBmb3IgYW4gYXN5bmNcbiAgICogcmVqZWN0aW9uLCBhbHJlYWR5IGhhcyksIGVuZCBpdCBhbmQgZmFsbCBiYWNrIHRvIGl0cyBiYXNlIHR5cGUuIE90aGVyd2lzZSB0aGVcbiAgICogdXNlciBoYXMgbW92ZWQgb246IHJlbWVtYmVyIGl0LCBzbyB0aGUgbmV4dCBhdXRvbWF0aWMgcmUtYWN0aXZhdGlvbiBmYWxscyBiYWNrLlxuICAgKi9cbiAgcHJpdmF0ZSBjbGVhbnVwRmFpbGVkKGNvbnRyaWJ1dGlvbjogUGxvdFR5cGVDb250cmlidXRpb24sIHdoYXQ6IHN0cmluZywgZXJyOiB1bmtub3duKTogdm9pZCB7XG4gICAgY29uc3QgaWQgPSBjb250cmlidXRpb24uZGVzY3JpcHRvci50eXBlO1xuICAgIHRoaXMubG9nLmVycm9yKGAke1RBR30gJyR7aWR9JyAke3doYXR9IGZhaWxlZC5gLCBlcnIpO1xuICAgIGNvbnN0IGFnYWluID0gdGhpcy5hY3RpdmU/LmNvbnRyaWJ1dGlvbiA9PT0gY29udHJpYnV0aW9uIHx8IHRoaXMucGVuZGluZ0lkID09PSBpZDtcbiAgICBpZiAoYWdhaW4pIHtcbiAgICAgIHRoaXMuZGVhY3RpdmF0ZSgpO1xuICAgICAgdGhpcy5mYWlsKGNvbnRyaWJ1dGlvbiwgZXJyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5mYWlsZWRDbGVhbnVwLnNldChpZCwgZXJyKTtcbiAgICB9XG4gIH1cblxuICAvKiogQ2FsbCBgY2IodHJ1ZSlgIG9uY2UgdGhlIHZpZXdwb3J0IHJlcG9ydHMgcmVhZHkgKG5vdywgb3Igb24gYSBsYXRlclxuICAgKiAgYW5pbWF0aW9uIGZyYW1lKSwgb3IgYGNiKGZhbHNlKWAgYWZ0ZXIge0BsaW5rIE1BWF9SRUFEWV9GUkFNRVN9LiAqL1xuICBwcml2YXRlIHdoZW5SZWFkeShjdHg6IFBsb3RNb2RlQ29udGV4dCwgZ2VuOiBudW1iZXIsIGNiOiAocmVhZHk6IGJvb2xlYW4pID0+IHZvaWQpOiB2b2lkIHtcbiAgICBjb25zdCBpc1JlYWR5ID0gKCkgPT4ge1xuICAgICAgdHJ5IHsgcmV0dXJuIGN0eC52aWV3cG9ydC5pc1JlYWR5KCk7IH0gY2F0Y2ggeyByZXR1cm4gZmFsc2U7IH1cbiAgICB9O1xuICAgIGlmIChpc1JlYWR5KCkpIHJldHVybiBjYih0cnVlKTtcbiAgICBsZXQgZnJhbWVzID0gMDtcbiAgICBjb25zdCBzZXR0bGUgPSAocmVhZHk6IGJvb2xlYW4pID0+IHtcbiAgICAgIHRoaXMucmVhZHlGcmFtZSA9IG51bGw7XG4gICAgICB0aGlzLnJlYWR5Q2IgPSBudWxsO1xuICAgICAgY2IocmVhZHkpO1xuICAgIH07XG4gICAgY29uc3QgdGljayA9ICgpID0+IHtcbiAgICAgIHRoaXMucmVhZHlGcmFtZSA9IG51bGw7XG4gICAgICBpZiAoZ2VuICE9PSB0aGlzLmdlbmVyYXRpb24pIHJldHVybiBzZXR0bGUoZmFsc2UpO1xuICAgICAgaWYgKGlzUmVhZHkoKSkgcmV0dXJuIHNldHRsZSh0cnVlKTtcbiAgICAgIGlmICgrK2ZyYW1lcyA+PSBNQVhfUkVBRFlfRlJBTUVTKSByZXR1cm4gc2V0dGxlKGZhbHNlKTtcbiAgICAgIHRoaXMucmVhZHlGcmFtZSA9IHJlcXVlc3RBbmltYXRpb25GcmFtZSh0aWNrKTtcbiAgICB9O1xuICAgIHRoaXMucmVhZHlDYiA9IHNldHRsZTtcbiAgICB0aGlzLnJlYWR5RnJhbWUgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUodGljayk7XG4gIH1cblxuICAvKiogU3RvcCB3YWl0aW5nIGZvciB0aGUgdmlld3BvcnQ7IHRoZSB3YWl0aW5nIGFjdGl2YXRpb24gcmVzb2x2ZXMgYXMgc3VwZXJzZWRlZC4gKi9cbiAgcHJpdmF0ZSBjYW5jZWxSZWFkeVdhaXQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVhZHlGcmFtZSAhPT0gbnVsbCkgY2FuY2VsQW5pbWF0aW9uRnJhbWUodGhpcy5yZWFkeUZyYW1lKTtcbiAgICB0aGlzLnJlYWR5RnJhbWUgPSBudWxsO1xuICAgIGNvbnN0IGNiID0gdGhpcy5yZWFkeUNiO1xuICAgIHRoaXMucmVhZHlDYiA9IG51bGw7XG4gICAgY2I/LihmYWxzZSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gaXNUaGVuYWJsZTxUPih2OiBUIHwgUHJvbWlzZTxUPiB8IHVua25vd24pOiB2IGlzIFByb21pc2U8VD4ge1xuICByZXR1cm4gISF2ICYmIHR5cGVvZiAodiBhcyBQcm9taXNlPFQ+KS50aGVuID09PSAnZnVuY3Rpb24nO1xufVxuIl19