footprintjs 9.4.0 → 9.6.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 (55) hide show
  1. package/CLAUDE.md +2 -0
  2. package/README.md +14 -0
  3. package/dist/esm/index.js +1 -1
  4. package/dist/esm/lib/builder/FlowChartBuilder.js +15 -2
  5. package/dist/esm/lib/capture/envelope.js +187 -0
  6. package/dist/esm/lib/capture/index.js +2 -2
  7. package/dist/esm/lib/engine/handlers/ContinuationResolver.js +23 -4
  8. package/dist/esm/lib/engine/types.js +1 -1
  9. package/dist/esm/lib/observer-queue/deferredDispatcher.js +226 -0
  10. package/dist/esm/lib/observer-queue/flushDriver.js +163 -0
  11. package/dist/esm/lib/observer-queue/index.js +22 -0
  12. package/dist/esm/lib/observer-queue/mergedQueue.js +91 -0
  13. package/dist/esm/lib/observer-queue/ring.js +122 -0
  14. package/dist/esm/lib/recorder/CombinedRecorder.js +4 -4
  15. package/dist/esm/lib/recorder/invokeHook.js +38 -0
  16. package/dist/esm/lib/runner/DeferredObserverTier.js +366 -0
  17. package/dist/esm/lib/runner/ExecutionRuntime.js +1 -1
  18. package/dist/esm/lib/runner/FlowChartExecutor.js +152 -22
  19. package/dist/esm/lib/runner/index.js +1 -1
  20. package/dist/esm/lib/scope/ScopeFacade.js +11 -8
  21. package/dist/index.js +1 -1
  22. package/dist/lib/builder/FlowChartBuilder.js +15 -2
  23. package/dist/lib/capture/envelope.js +192 -0
  24. package/dist/lib/capture/index.js +3 -3
  25. package/dist/lib/engine/handlers/ContinuationResolver.js +23 -4
  26. package/dist/lib/engine/types.js +1 -1
  27. package/dist/lib/observer-queue/deferredDispatcher.js +230 -0
  28. package/dist/lib/observer-queue/flushDriver.js +167 -0
  29. package/dist/lib/observer-queue/index.js +36 -0
  30. package/dist/lib/observer-queue/mergedQueue.js +95 -0
  31. package/dist/lib/observer-queue/ring.js +126 -0
  32. package/dist/lib/recorder/CombinedRecorder.js +8 -8
  33. package/dist/lib/recorder/invokeHook.js +42 -0
  34. package/dist/lib/runner/DeferredObserverTier.js +370 -0
  35. package/dist/lib/runner/ExecutionRuntime.js +1 -1
  36. package/dist/lib/runner/FlowChartExecutor.js +152 -22
  37. package/dist/lib/runner/index.js +1 -1
  38. package/dist/lib/scope/ScopeFacade.js +11 -8
  39. package/dist/types/index.d.ts +24 -0
  40. package/dist/types/lib/capture/envelope.d.ts +169 -0
  41. package/dist/types/lib/capture/index.d.ts +1 -1
  42. package/dist/types/lib/engine/handlers/ContinuationResolver.d.ts +15 -2
  43. package/dist/types/lib/engine/types.d.ts +3 -0
  44. package/dist/types/lib/observer-queue/deferredDispatcher.d.ts +169 -0
  45. package/dist/types/lib/observer-queue/flushDriver.d.ts +124 -0
  46. package/dist/types/lib/observer-queue/index.d.ts +25 -0
  47. package/dist/types/lib/observer-queue/mergedQueue.d.ts +85 -0
  48. package/dist/types/lib/observer-queue/ring.d.ts +99 -0
  49. package/dist/types/lib/recorder/CombinedRecorder.d.ts +36 -0
  50. package/dist/types/lib/recorder/invokeHook.d.ts +32 -0
  51. package/dist/types/lib/runner/DeferredObserverTier.d.ts +204 -0
  52. package/dist/types/lib/runner/ExecutionRuntime.d.ts +8 -0
  53. package/dist/types/lib/runner/FlowChartExecutor.d.ts +49 -10
  54. package/dist/types/lib/runner/index.d.ts +1 -0
  55. package/package.json +2 -1
@@ -0,0 +1,226 @@
1
+ /**
2
+ * observer-queue/deferredDispatcher.ts — RFC-001 Block 5: deferred delivery façade.
3
+ *
4
+ * Pattern: capture → enqueue → (microtask) flush → invoke, with per-listener
5
+ * error isolation. Composes the whole pure pipeline: MergedQueue
6
+ * (Block 3, which captures via Block 1) + FlushDriver (Block 4) +
7
+ * a listener registry with timing/inflight accounting.
8
+ * Role: The object the engine wiring (Block 6) will hold. Producers call
9
+ * `capture()` (cheap, never throws, never blocks); listeners
10
+ * receive envelopes at the next checkpoint, "one beat behind".
11
+ * Pure module — zero engine imports.
12
+ *
13
+ * Delivery semantics (normative, RFC-001 §5 + amendments A2/A4):
14
+ * - Per-listener FIFO: every listener sees envelopes in seq order
15
+ * (invocation order; an async listener's COMPLETION order is its own
16
+ * concern) — EXCEPT under `'block'` overflow, where a refused enqueue
17
+ * is delivered inline and overtakes the queued backlog. `seq` always
18
+ * records true arrival order, so order-sensitive consumers re-sort;
19
+ * see the `'block'` caveat below.
20
+ * - Error isolation: a throwing listener (sync) or rejecting listener
21
+ * (async) never affects siblings or the producer. Both failure modes
22
+ * route to the injected `onError`; a throwing `onError` is itself
23
+ * swallowed.
24
+ * - The flush NEVER awaits a listener. Async continuations are tracked in
25
+ * an inflight set; `drain({ timeoutMs })` settles them
26
+ * (`Promise.allSettled` + deadline, shaped like `flushAllDetached`).
27
+ * - `'block'` overflow: a refused enqueue is delivered synchronously
28
+ * INLINE from `capture()` — re-introducing blocking delivery by the
29
+ * consumer's explicit choice. Ordering caveat (documented + tested): an
30
+ * inline event overtakes the queued backlog — `'block'` trades global
31
+ * ordering for zero loss and bounded memory. `seq` still tells the
32
+ * true arrival order.
33
+ * - Listener registry is idempotent by id (same id replaces, different
34
+ * ids coexist) — mirrors the repo-wide recorder ID contract. Stats
35
+ * accumulate per id across replacement; `removeListener` keeps the
36
+ * id's accumulated stats for post-run reports.
37
+ * - Events captured BEFORE any listener attaches stay queued — a listener
38
+ * attached before the next checkpoint still receives the backlog.
39
+ *
40
+ * Per-listener time accounting (amendment A2 — "name the hog"): cumulative
41
+ * `totalMs` and per-checkpoint `lastFlushMs` of SYNC time per listener id —
42
+ * the time that actually blocks the flush. An async listener's continuation
43
+ * time is intentionally not attributed (it does not block delivery).
44
+ */
45
+ import { FlushDriver } from './flushDriver.js';
46
+ import { MergedQueue } from './mergedQueue.js';
47
+ const defaultNow = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());
48
+ function isThenable(value) {
49
+ return typeof value === 'object' && value !== null && typeof value.then === 'function';
50
+ }
51
+ export class DeferredDispatcher {
52
+ queue;
53
+ driver;
54
+ listeners = new Map();
55
+ listenerStats = new Map();
56
+ /** Tracked async continuations — resolve `true` (ok) / `false` (failed). */
57
+ inflight = new Set();
58
+ onError;
59
+ now;
60
+ inlineDeliveries = 0;
61
+ constructor(opts) {
62
+ this.onError = opts?.onError;
63
+ this.now = opts?.now ?? defaultNow;
64
+ this.queue = new MergedQueue({
65
+ maxQueue: opts?.maxQueue,
66
+ overflow: opts?.overflow,
67
+ sampleEvery: opts?.sampleEvery,
68
+ capturePolicy: opts?.capturePolicy,
69
+ hooks: opts?.hooks,
70
+ });
71
+ this.driver = new FlushDriver({
72
+ depth: () => this.queue.depth,
73
+ processNext: () => this.deliverNext(),
74
+ flushBudgetMs: opts?.flushBudgetMs,
75
+ now: opts?.now,
76
+ schedule: opts?.schedule,
77
+ onFlushStart: () => {
78
+ for (const stats of this.listenerStats.values())
79
+ stats.lastFlushMs = 0;
80
+ },
81
+ });
82
+ }
83
+ /** Idempotent by id — same id replaces (stats continue), ids coexist. */
84
+ addListener(id, listener) {
85
+ this.listeners.set(id, listener);
86
+ if (!this.listenerStats.has(id)) {
87
+ this.listenerStats.set(id, { events: 0, totalMs: 0, lastFlushMs: 0 });
88
+ }
89
+ }
90
+ /** Stop delivering to `id`. Accumulated stats are kept for reports. */
91
+ removeListener(id) {
92
+ this.listeners.delete(id);
93
+ }
94
+ /**
95
+ * Producer entry point: capture the event (seq-stamped, payload per
96
+ * policy) and stage it for the next checkpoint. Cheap; NEVER throws;
97
+ * never blocks — except under `'block'` overflow, where a refused
98
+ * enqueue is delivered synchronously inline (explicit consumer choice).
99
+ */
100
+ capture(input, policy) {
101
+ const result = this.queue.enqueue(input, policy);
102
+ if (result.outcome === 'queued') {
103
+ this.driver.arm();
104
+ return;
105
+ }
106
+ if (result.outcome === 'inline') {
107
+ this.inlineDeliveries += 1;
108
+ this.deliver(result.envelope);
109
+ }
110
+ // 'dropped': counted by the queue; loss surfaces in stats + seq gaps.
111
+ }
112
+ /**
113
+ * Terminal flush — synchronously deliver everything queued (end of run /
114
+ * shutdown). Async listener continuations are NOT awaited; follow with
115
+ * `drain()` for that.
116
+ */
117
+ flushNow(opts) {
118
+ return this.driver.flushSync(opts);
119
+ }
120
+ /**
121
+ * Flush the backlog, then settle all inflight async continuations —
122
+ * `Promise.allSettled` under a deadline, shaped like `flushAllDetached`.
123
+ * Loops while continuations spawn new captures, until quiescent or the
124
+ * deadline expires.
125
+ */
126
+ async drain(opts) {
127
+ const timeoutMs = opts?.timeoutMs ?? 30_000;
128
+ const startedAt = Date.now();
129
+ let done = 0;
130
+ let failed = 0;
131
+ this.flushNow();
132
+ while (this.inflight.size > 0) {
133
+ const remainingMs = timeoutMs - (Date.now() - startedAt);
134
+ if (remainingMs <= 0)
135
+ return { done, failed, pending: this.inflight.size + this.queue.depth };
136
+ const batch = [...this.inflight];
137
+ let timerId;
138
+ const timeoutPromise = new Promise((resolve) => {
139
+ timerId = setTimeout(() => resolve('__drain_timeout__'), remainingMs);
140
+ });
141
+ const settled = await Promise.race([Promise.allSettled(batch), timeoutPromise]);
142
+ if (timerId !== undefined)
143
+ clearTimeout(timerId);
144
+ if (settled === '__drain_timeout__') {
145
+ return { done, failed, pending: this.inflight.size + this.queue.depth };
146
+ }
147
+ for (const r of settled) {
148
+ // Tracked promises never reject — they resolve true (ok) / false.
149
+ if (r.status === 'fulfilled' && r.value === false)
150
+ failed += 1;
151
+ else
152
+ done += 1;
153
+ }
154
+ // Continuations may have captured more events — flush and re-check.
155
+ this.flushNow();
156
+ }
157
+ return { done, failed, pending: this.queue.depth };
158
+ }
159
+ /** A4 — the stats object Block 9 consumes. Pure getter, fresh snapshot. */
160
+ getStats() {
161
+ const counters = this.queue.getCounters();
162
+ const driverStats = this.driver.getStats();
163
+ const perListener = {};
164
+ for (const [id, stats] of this.listenerStats) {
165
+ perListener[id] = { events: stats.events, totalMs: stats.totalMs, lastFlushMs: stats.lastFlushMs };
166
+ }
167
+ return {
168
+ depth: this.queue.depth,
169
+ drops: counters.drops,
170
+ flushes: driverStats.flushes,
171
+ budgetExhausted: driverStats.budgetExhausted,
172
+ p95FlushMs: driverStats.p95FlushMs,
173
+ inlineDeliveries: this.inlineDeliveries,
174
+ inflight: this.inflight.size,
175
+ perListener,
176
+ };
177
+ }
178
+ deliverNext() {
179
+ const envelope = this.queue.shift();
180
+ if (envelope === undefined)
181
+ return;
182
+ this.deliver(envelope);
183
+ }
184
+ /** Invoke every listener with full error isolation + time accounting. */
185
+ deliver(envelope) {
186
+ for (const [id, listener] of this.listeners) {
187
+ const stats = this.listenerStats.get(id);
188
+ const start = this.now();
189
+ try {
190
+ const result = listener(envelope);
191
+ if (isThenable(result))
192
+ this.track(result, id, envelope);
193
+ }
194
+ catch (error) {
195
+ this.safeOnError(error, { listenerId: id, envelope, phase: 'sync' });
196
+ }
197
+ finally {
198
+ const elapsed = this.now() - start;
199
+ stats.events += 1;
200
+ stats.totalMs += elapsed;
201
+ stats.lastFlushMs += elapsed;
202
+ }
203
+ }
204
+ }
205
+ /** Track an async continuation; route its rejection; never reject. */
206
+ track(promise, listenerId, envelope) {
207
+ const tracked = promise.then(() => true, (error) => {
208
+ this.safeOnError(error, { listenerId, envelope, phase: 'async' });
209
+ return false;
210
+ });
211
+ this.inflight.add(tracked);
212
+ // Self-cleanup — `tracked` never rejects, so this chain cannot float an
213
+ // unhandled rejection.
214
+ tracked.then(() => this.inflight.delete(tracked));
215
+ }
216
+ /** The error sink must never become an error source. */
217
+ safeOnError(error, context) {
218
+ try {
219
+ this.onError?.(error, context);
220
+ }
221
+ catch {
222
+ // Swallow — isolation is absolute.
223
+ }
224
+ }
225
+ }
226
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmZXJyZWREaXNwYXRjaGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9vYnNlcnZlci1xdWV1ZS9kZWZlcnJlZERpc3BhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyQ0c7QUFHSCxPQUFPLEVBQXdCLFdBQVcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3JFLE9BQU8sRUFBcUIsV0FBVyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUF3RmxFLE1BQU0sVUFBVSxHQUFHLEdBQVcsRUFBRSxDQUFDLENBQUMsT0FBTyxXQUFXLEtBQUssV0FBVyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0FBRXZHLFNBQVMsVUFBVSxDQUFDLEtBQTJCO0lBQzdDLE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksT0FBUSxLQUF1QixDQUFDLElBQUksS0FBSyxVQUFVLENBQUM7QUFDNUcsQ0FBQztBQUVELE1BQU0sT0FBTyxrQkFBa0I7SUFDWixLQUFLLENBQWM7SUFDbkIsTUFBTSxDQUFjO0lBQ3BCLFNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBNEIsQ0FBQztJQUNoRCxhQUFhLEdBQUcsSUFBSSxHQUFHLEVBQWdDLENBQUM7SUFDekUsNEVBQTRFO0lBQzNELFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBb0IsQ0FBQztJQUN2QyxPQUFPLENBQXdCO0lBQy9CLEdBQUcsQ0FBZTtJQUMzQixnQkFBZ0IsR0FBRyxDQUFDLENBQUM7SUFFN0IsWUFBWSxJQUFnQztRQUMxQyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksRUFBRSxPQUFPLENBQUM7UUFDN0IsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLEVB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QUFDLE9BQXNCLEVBQUUsVUFBa0IsRUFBRSxRQUF5QjtRQUNqRixNQUFNLE9BQU8sR0FBcUIsT0FBTyxDQUFDLElBQUksQ0FDNUMsR0FBRyxFQUFFLENBQUMsSUFBSSxFQUNWLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDUixJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDbEUsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDLENBQ0YsQ0FBQztRQUNGLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzNCLHdFQUF3RTtRQUN4RSx1QkFBdUI7UUFDdkIsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRCx3REFBd0Q7SUFDaEQsV0FBVyxDQUFDLEtBQWMsRUFBRSxPQUE2QjtRQUMvRCxJQUFJLENBQUM7WUFDSCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ2pDLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCxtQ0FBbUM7UUFDckMsQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogb2JzZXJ2ZXItcXVldWUvZGVmZXJyZWREaXNwYXRjaGVyLnRzIOKAlCBSRkMtMDAxIEJsb2NrIDU6IGRlZmVycmVkIGRlbGl2ZXJ5IGZhw6dhZGUuXG4gKlxuICogUGF0dGVybjogIGNhcHR1cmUg4oaSIGVucXVldWUg4oaSIChtaWNyb3Rhc2spIGZsdXNoIOKGkiBpbnZva2UsIHdpdGggcGVyLWxpc3RlbmVyXG4gKiAgICAgICAgICAgZXJyb3IgaXNvbGF0aW9uLiBDb21wb3NlcyB0aGUgd2hvbGUgcHVyZSBwaXBlbGluZTogTWVyZ2VkUXVldWVcbiAqICAgICAgICAgICAoQmxvY2sgMywgd2hpY2ggY2FwdHVyZXMgdmlhIEJsb2NrIDEpICsgRmx1c2hEcml2ZXIgKEJsb2NrIDQpICtcbiAqICAgICAgICAgICBhIGxpc3RlbmVyIHJlZ2lzdHJ5IHdpdGggdGltaW5nL2luZmxpZ2h0IGFjY291bnRpbmcuXG4gKiBSb2xlOiAgICAgVGhlIG9iamVjdCB0aGUgZW5naW5lIHdpcmluZyAoQmxvY2sgNikgd2lsbCBob2xkLiBQcm9kdWNlcnMgY2FsbFxuICogICAgICAgICAgIGBjYXB0dXJlKClgIChjaGVhcCwgbmV2ZXIgdGhyb3dzLCBuZXZlciBibG9ja3MpOyBsaXN0ZW5lcnNcbiAqICAgICAgICAgICByZWNlaXZlIGVudmVsb3BlcyBhdCB0aGUgbmV4dCBjaGVja3BvaW50LCBcIm9uZSBiZWF0IGJlaGluZFwiLlxuICogICAgICAgICAgIFB1cmUgbW9kdWxlIOKAlCB6ZXJvIGVuZ2luZSBpbXBvcnRzLlxuICpcbiAqIERlbGl2ZXJ5IHNlbWFudGljcyAobm9ybWF0aXZlLCBSRkMtMDAxIMKnNSArIGFtZW5kbWVudHMgQTIvQTQpOlxuICogICAtIFBlci1saXN0ZW5lciBGSUZPOiBldmVyeSBsaXN0ZW5lciBzZWVzIGVudmVsb3BlcyBpbiBzZXEgb3JkZXJcbiAqICAgICAoaW52b2NhdGlvbiBvcmRlcjsgYW4gYXN5bmMgbGlzdGVuZXIncyBDT01QTEVUSU9OIG9yZGVyIGlzIGl0cyBvd25cbiAqICAgICBjb25jZXJuKSDigJQgRVhDRVBUIHVuZGVyIGAnYmxvY2snYCBvdmVyZmxvdywgd2hlcmUgYSByZWZ1c2VkIGVucXVldWVcbiAqICAgICBpcyBkZWxpdmVyZWQgaW5saW5lIGFuZCBvdmVydGFrZXMgdGhlIHF1ZXVlZCBiYWNrbG9nLiBgc2VxYCBhbHdheXNcbiAqICAgICByZWNvcmRzIHRydWUgYXJyaXZhbCBvcmRlciwgc28gb3JkZXItc2Vuc2l0aXZlIGNvbnN1bWVycyByZS1zb3J0O1xuICogICAgIHNlZSB0aGUgYCdibG9jaydgIGNhdmVhdCBiZWxvdy5cbiAqICAgLSBFcnJvciBpc29sYXRpb246IGEgdGhyb3dpbmcgbGlzdGVuZXIgKHN5bmMpIG9yIHJlamVjdGluZyBsaXN0ZW5lclxuICogICAgIChhc3luYykgbmV2ZXIgYWZmZWN0cyBzaWJsaW5ncyBvciB0aGUgcHJvZHVjZXIuIEJvdGggZmFpbHVyZSBtb2Rlc1xuICogICAgIHJvdXRlIHRvIHRoZSBpbmplY3RlZCBgb25FcnJvcmA7IGEgdGhyb3dpbmcgYG9uRXJyb3JgIGlzIGl0c2VsZlxuICogICAgIHN3YWxsb3dlZC5cbiAqICAgLSBUaGUgZmx1c2ggTkVWRVIgYXdhaXRzIGEgbGlzdGVuZXIuIEFzeW5jIGNvbnRpbnVhdGlvbnMgYXJlIHRyYWNrZWQgaW5cbiAqICAgICBhbiBpbmZsaWdodCBzZXQ7IGBkcmFpbih7IHRpbWVvdXRNcyB9KWAgc2V0dGxlcyB0aGVtXG4gKiAgICAgKGBQcm9taXNlLmFsbFNldHRsZWRgICsgZGVhZGxpbmUsIHNoYXBlZCBsaWtlIGBmbHVzaEFsbERldGFjaGVkYCkuXG4gKiAgIC0gYCdibG9jaydgIG92ZXJmbG93OiBhIHJlZnVzZWQgZW5xdWV1ZSBpcyBkZWxpdmVyZWQgc3luY2hyb25vdXNseVxuICogICAgIElOTElORSBmcm9tIGBjYXB0dXJlKClgIOKAlCByZS1pbnRyb2R1Y2luZyBibG9ja2luZyBkZWxpdmVyeSBieSB0aGVcbiAqICAgICBjb25zdW1lcidzIGV4cGxpY2l0IGNob2ljZS4gT3JkZXJpbmcgY2F2ZWF0IChkb2N1bWVudGVkICsgdGVzdGVkKTogYW5cbiAqICAgICBpbmxpbmUgZXZlbnQgb3ZlcnRha2VzIHRoZSBxdWV1ZWQgYmFja2xvZyDigJQgYCdibG9jaydgIHRyYWRlcyBnbG9iYWxcbiAqICAgICBvcmRlcmluZyBmb3IgemVybyBsb3NzIGFuZCBib3VuZGVkIG1lbW9yeS4gYHNlcWAgc3RpbGwgdGVsbHMgdGhlXG4gKiAgICAgdHJ1ZSBhcnJpdmFsIG9yZGVyLlxuICogICAtIExpc3RlbmVyIHJlZ2lzdHJ5IGlzIGlkZW1wb3RlbnQgYnkgaWQgKHNhbWUgaWQgcmVwbGFjZXMsIGRpZmZlcmVudFxuICogICAgIGlkcyBjb2V4aXN0KSDigJQgbWlycm9ycyB0aGUgcmVwby13aWRlIHJlY29yZGVyIElEIGNvbnRyYWN0LiBTdGF0c1xuICogICAgIGFjY3VtdWxhdGUgcGVyIGlkIGFjcm9zcyByZXBsYWNlbWVudDsgYHJlbW92ZUxpc3RlbmVyYCBrZWVwcyB0aGVcbiAqICAgICBpZCdzIGFjY3VtdWxhdGVkIHN0YXRzIGZvciBwb3N0LXJ1biByZXBvcnRzLlxuICogICAtIEV2ZW50cyBjYXB0dXJlZCBCRUZPUkUgYW55IGxpc3RlbmVyIGF0dGFjaGVzIHN0YXkgcXVldWVkIOKAlCBhIGxpc3RlbmVyXG4gKiAgICAgYXR0YWNoZWQgYmVmb3JlIHRoZSBuZXh0IGNoZWNrcG9pbnQgc3RpbGwgcmVjZWl2ZXMgdGhlIGJhY2tsb2cuXG4gKlxuICogUGVyLWxpc3RlbmVyIHRpbWUgYWNjb3VudGluZyAoYW1lbmRtZW50IEEyIOKAlCBcIm5hbWUgdGhlIGhvZ1wiKTogY3VtdWxhdGl2ZVxuICogYHRvdGFsTXNgIGFuZCBwZXItY2hlY2twb2ludCBgbGFzdEZsdXNoTXNgIG9mIFNZTkMgdGltZSBwZXIgbGlzdGVuZXIgaWQg4oCUXG4gKiB0aGUgdGltZSB0aGF0IGFjdHVhbGx5IGJsb2NrcyB0aGUgZmx1c2guIEFuIGFzeW5jIGxpc3RlbmVyJ3MgY29udGludWF0aW9uXG4gKiB0aW1lIGlzIGludGVudGlvbmFsbHkgbm90IGF0dHJpYnV0ZWQgKGl0IGRvZXMgbm90IGJsb2NrIGRlbGl2ZXJ5KS5cbiAqL1xuXG5pbXBvcnQgeyB0eXBlIENhcHR1cmVFbnZlbG9wZSwgdHlwZSBDYXB0dXJlSG9va3MsIHR5cGUgQ2FwdHVyZVBvbGljeSB9IGZyb20gJy4uL2NhcHR1cmUvZW52ZWxvcGUuanMnO1xuaW1wb3J0IHsgdHlwZSBGbHVzaFN5bmNSZXN1bHQsIEZsdXNoRHJpdmVyIH0gZnJvbSAnLi9mbHVzaERyaXZlci5qcyc7XG5pbXBvcnQgeyB0eXBlIEVucXVldWVJbnB1dCwgTWVyZ2VkUXVldWUgfSBmcm9tICcuL21lcmdlZFF1ZXVlLmpzJztcbmltcG9ydCB7IHR5cGUgT3ZlcmZsb3dQb2xpY3kgfSBmcm9tICcuL3JpbmcuanMnO1xuXG4vKipcbiAqIE9uZSBkZWZlcnJlZCBvYnNlcnZlci4gTWF5IHJldHVybiBhIFByb21pc2Ug4oCUIHRoZSBkaXNwYXRjaGVyIHRyYWNrcyBpdCBpblxuICogdGhlIGluZmxpZ2h0IHNldCBidXQgTkVWRVIgYXdhaXRzIGl0IGR1cmluZyBhIGZsdXNoLlxuICovXG5leHBvcnQgdHlwZSBEZWZlcnJlZExpc3RlbmVyID0gKGVudmVsb3BlOiBDYXB0dXJlRW52ZWxvcGUpID0+IHZvaWQgfCBQcm9taXNlPHZvaWQ+O1xuXG5leHBvcnQgaW50ZXJmYWNlIERpc3BhdGNoRXJyb3JDb250ZXh0IHtcbiAgcmVhZG9ubHkgbGlzdGVuZXJJZDogc3RyaW5nO1xuICByZWFkb25seSBlbnZlbG9wZTogQ2FwdHVyZUVudmVsb3BlO1xuICAvKiogYCdzeW5jJ2AgPSBsaXN0ZW5lciB0aHJldzsgYCdhc3luYydgID0gcmV0dXJuZWQgcHJvbWlzZSByZWplY3RlZC4gKi9cbiAgcmVhZG9ubHkgcGhhc2U6ICdzeW5jJyB8ICdhc3luYyc7XG59XG5cbi8qKiBJbmplY3RlZCBlcnJvciBzaW5rIOKAlCB0aGUgd2lyaW5nIGxheWVyIHJvdXRlcyB0aGVzZSAoQmxvY2sgNikuICovXG5leHBvcnQgdHlwZSBEaXNwYXRjaEVycm9ySGFuZGxlciA9IChlcnJvcjogdW5rbm93biwgY29udGV4dDogRGlzcGF0Y2hFcnJvckNvbnRleHQpID0+IHZvaWQ7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGVmZXJyZWREaXNwYXRjaGVyT3B0aW9ucyB7XG4gIC8qKiBRdWV1ZSBib3VuZCDigJQgZGVmYXVsdCAxMCAwMDAgKHNlZSBgTWVyZ2VkUXVldWVgKS4gKi9cbiAgcmVhZG9ubHkgbWF4UXVldWU/OiBudW1iZXI7XG4gIC8qKiBPdmVyZmxvdyBwb2xpY3kg4oCUIGRlZmF1bHQgYCdkcm9wLW9sZGVzdCdgLiAqL1xuICByZWFkb25seSBvdmVyZmxvdz86IE92ZXJmbG93UG9saWN5O1xuICAvKiogYCdzYW1wbGUnYCBvdmVyZmxvdyBvbmx5IOKAlCBhZG1pdCAxIGluIHRoaXMgbWFueSBzYXR1cmF0ZWQgYXJyaXZhbHMuICovXG4gIHJlYWRvbmx5IHNhbXBsZUV2ZXJ5PzogbnVtYmVyO1xuICAvKiogRGVmYXVsdCBjYXB0dXJlIHBvbGljeSDigJQgZGVmYXVsdCBgJ3N1bW1hcnknYC4gKi9cbiAgcmVhZG9ubHkgY2FwdHVyZVBvbGljeT86IENhcHR1cmVQb2xpY3k7XG4gIC8qKiBQZXItZmx1c2ggdGltZSBidWRnZXQsIG1zIChBMSkg4oCUIGRlZmF1bHQgMjsgYEluZmluaXR5YCA9IGZ1bGwgZHJhaW4uICovXG4gIHJlYWRvbmx5IGZsdXNoQnVkZ2V0TXM/OiBudW1iZXI7XG4gIC8qKiBMaXN0ZW5lci1mYWlsdXJlIHNpbmsuIE5vIGRlZmF1bHQg4oCUIHdpdGhvdXQgaXQsIGZhaWx1cmVzIGFyZSBzaWxlbnQuICovXG4gIHJlYWRvbmx5IG9uRXJyb3I/OiBEaXNwYXRjaEVycm9ySGFuZGxlcjtcbiAgLyoqIENhcHR1cmUgc2VhbXMgKGRldi13YXJuLCBjYXB0dXJlZEF0IGNsb2NrKSDigJQgc2VlIGBDYXB0dXJlSG9va3NgLiAqL1xuICByZWFkb25seSBob29rcz86IENhcHR1cmVIb29rcztcbiAgLyoqIFRpbWluZyBjbG9jayBmb3IgYnVkZ2V0ICsgcGVyLWxpc3RlbmVyIGFjY291bnRpbmcuIEluamVjdGFibGUuICovXG4gIHJlYWRvbmx5IG5vdz86ICgpID0+IG51bWJlcjtcbiAgLyoqIENoZWNrcG9pbnQgcHJpbWl0aXZlIOKAlCBkZWZhdWx0IGBxdWV1ZU1pY3JvdGFza2AuIEluamVjdGFibGUuICovXG4gIHJlYWRvbmx5IHNjaGVkdWxlPzogKGNiOiAoKSA9PiB2b2lkKSA9PiB2b2lkO1xufVxuXG4vKiogUGVyLWxpc3RlbmVyIGFjY291bnRpbmcgKEEyL0E0KS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGlzdGVuZXJTdGF0cyB7XG4gIC8qKiBFbnZlbG9wZXMgZGVsaXZlcmVkIChpbnZvY2F0aW9ucywgaW5jbHVkaW5nIG9uZXMgdGhhdCB0aHJldykuICovXG4gIHJlYWRvbmx5IGV2ZW50czogbnVtYmVyO1xuICAvKiogQ3VtdWxhdGl2ZSBzeW5jIGRlbGl2ZXJ5IHRpbWUsIG1zLiAqL1xuICByZWFkb25seSB0b3RhbE1zOiBudW1iZXI7XG4gIC8qKiBTeW5jIGRlbGl2ZXJ5IHRpbWUgc2luY2UgdGhlIGxhc3QgZmx1c2ggc3RhcnRlZCwgbXMuICovXG4gIHJlYWRvbmx5IGxhc3RGbHVzaE1zOiBudW1iZXI7XG59XG5cbi8qKiBUaGUgQmxvY2sgOSBvYnNlcnZhYmlsaXR5IHN1cmZhY2UgKGFtZW5kbWVudCBBNCkg4oCUIHB1cmUgZ2V0dGVyLiAqL1xuZXhwb3J0IGludGVyZmFjZSBEaXNwYXRjaGVyU3RhdHMge1xuICAvKiogQ3VycmVudCBiYWNrbG9nLiAqL1xuICByZWFkb25seSBkZXB0aDogbnVtYmVyO1xuICAvKiogRXZlbnRzIExPU1QgKG92ZXJmbG93KSDigJQgbmV2ZXIgc2lsZW50OyBhbHNvIHZpc2libGUgYXMgc2VxIGdhcHMuICovXG4gIHJlYWRvbmx5IGRyb3BzOiBudW1iZXI7XG4gIC8qKiBDb21wbGV0ZWQgY2hlY2twb2ludCBmbHVzaGVzLiAqL1xuICByZWFkb25seSBmbHVzaGVzOiBudW1iZXI7XG4gIC8qKiBGbHVzaGVzIGN1dCBzaG9ydCBieSBgZmx1c2hCdWRnZXRNc2AgKEExKS4gKi9cbiAgcmVhZG9ubHkgYnVkZ2V0RXhoYXVzdGVkOiBudW1iZXI7XG4gIC8qKiBwOTUgZmx1c2ggZHVyYXRpb24sIG1zIChyb2xsaW5nIHdpbmRvdykuICovXG4gIHJlYWRvbmx5IHA5NUZsdXNoTXM6IG51bWJlcjtcbiAgLyoqIGAnYmxvY2snYC1wb2xpY3kgcmVmdXNhbHMgZGVsaXZlcmVkIHN5bmNocm9ub3VzbHkgaW5saW5lLiAqL1xuICByZWFkb25seSBpbmxpbmVEZWxpdmVyaWVzOiBudW1iZXI7XG4gIC8qKiBBc3luYyBsaXN0ZW5lciBjb250aW51YXRpb25zIG5vdCB5ZXQgc2V0dGxlZC4gKi9cbiAgcmVhZG9ubHkgaW5mbGlnaHQ6IG51bWJlcjtcbiAgLyoqIFBlci1saXN0ZW5lciB0aW1lIGFjY291bnRpbmcg4oCUIFwibmFtZSB0aGUgaG9nXCIgKEEyKS4gKi9cbiAgcmVhZG9ubHkgcGVyTGlzdGVuZXI6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIExpc3RlbmVyU3RhdHM+Pjtcbn1cblxuLyoqIFJlc3VsdCBvZiB7QGxpbmsgRGVmZXJyZWREaXNwYXRjaGVyLmRyYWlufSDigJQgYGZsdXNoQWxsRGV0YWNoZWRgIHNoYXBlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBEcmFpblJlc3VsdCB7XG4gIC8qKiBBc3luYyBjb250aW51YXRpb25zIHNlZW4gc2V0dGxpbmcgZnVsZmlsbGVkLiBCZXN0LWVmZm9ydCBjb3VudCDigJQgYVxuICAgKiAgY29udGludWF0aW9uIHRoYXQgc2V0dGxlcyBiZXR3ZWVuIGNoZWNrcyBpcyBkcmFpbmVkIGJ1dCBtYXkgbm90IGJlXG4gICAqICBjb3VudGVkIChzYW1lIHNlbWFudGljcyBhcyBgZmx1c2hBbGxEZXRhY2hlZGApLiAqL1xuICByZWFkb25seSBkb25lOiBudW1iZXI7XG4gIC8qKiBDb250aW51YXRpb25zIHdob3NlIGxpc3RlbmVyIHByb21pc2UgcmVqZWN0ZWQgKHJvdXRlZCB0byBvbkVycm9yKS4gKi9cbiAgcmVhZG9ubHkgZmFpbGVkOiBudW1iZXI7XG4gIC8qKiBTdGlsbCBpbiBmbGlnaHQgKG9yIHF1ZXVlZCkgd2hlbiB0aGUgZGVhZGxpbmUgZXhwaXJlZC4gYDBgID0gZHJhaW5lZC4gKi9cbiAgcmVhZG9ubHkgcGVuZGluZzogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgTXV0YWJsZUxpc3RlbmVyU3RhdHMge1xuICBldmVudHM6IG51bWJlcjtcbiAgdG90YWxNczogbnVtYmVyO1xuICBsYXN0Rmx1c2hNczogbnVtYmVyO1xufVxuXG5jb25zdCBkZWZhdWx0Tm93ID0gKCk6IG51bWJlciA9PiAodHlwZW9mIHBlcmZvcm1hbmNlICE9PSAndW5kZWZpbmVkJyA/IHBlcmZvcm1hbmNlLm5vdygpIDogRGF0ZS5ub3coKSk7XG5cbmZ1bmN0aW9uIGlzVGhlbmFibGUodmFsdWU6IHZvaWQgfCBQcm9taXNlPHZvaWQ+KTogdmFsdWUgaXMgUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsICYmIHR5cGVvZiAodmFsdWUgYXMgUHJvbWlzZTx2b2lkPikudGhlbiA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuZXhwb3J0IGNsYXNzIERlZmVycmVkRGlzcGF0Y2hlciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgcXVldWU6IE1lcmdlZFF1ZXVlO1xuICBwcml2YXRlIHJlYWRvbmx5IGRyaXZlcjogRmx1c2hEcml2ZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgbGlzdGVuZXJzID0gbmV3IE1hcDxzdHJpbmcsIERlZmVycmVkTGlzdGVuZXI+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgbGlzdGVuZXJTdGF0cyA9IG5ldyBNYXA8c3RyaW5nLCBNdXRhYmxlTGlzdGVuZXJTdGF0cz4oKTtcbiAgLyoqIFRyYWNrZWQgYXN5bmMgY29udGludWF0aW9ucyDigJQgcmVzb2x2ZSBgdHJ1ZWAgKG9rKSAvIGBmYWxzZWAgKGZhaWxlZCkuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaW5mbGlnaHQgPSBuZXcgU2V0PFByb21pc2U8Ym9vbGVhbj4+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgb25FcnJvcj86IERpc3BhdGNoRXJyb3JIYW5kbGVyO1xuICBwcml2YXRlIHJlYWRvbmx5IG5vdzogKCkgPT4gbnVtYmVyO1xuICBwcml2YXRlIGlubGluZURlbGl2ZXJpZXMgPSAwO1xuXG4gIGNvbnN0cnVjdG9yKG9wdHM/OiBEZWZlcnJlZERpc3BhdGNoZXJPcHRpb25zKSB7XG4gICAgdGhpcy5vbkVycm9yID0gb3B0cz8ub25FcnJvcjtcbiAgICB0aGlzLm5vdyA9IG9wdHM/Lm5vdyA/PyBkZWZhdWx0Tm93O1xuICAgIHRoaXMucXVldWUgPSBuZXcgTWVyZ2VkUXVldWUoe1xuICAgICAgbWF4UXVldWU6IG9wdHM/Lm1heFF1ZXVlLFxuICAgICAgb3ZlcmZsb3c6IG9wdHM/Lm92ZXJmbG93LFxuICAgICAgc2FtcGxlRXZlcnk6IG9wdHM/LnNhbXBsZUV2ZXJ5LFxuICAgICAgY2FwdHVyZVBvbGljeTogb3B0cz8uY2FwdHVyZVBvbGljeSxcbiAgICAgIGhvb2tzOiBvcHRzPy5ob29rcyxcbiAgICB9KTtcbiAgICB0aGlzLmRyaXZlciA9IG5ldyBGbHVzaERyaXZlcih7XG4gICAgICBkZXB0aDogKCkgPT4gdGhpcy5xdWV1ZS5kZXB0aCxcbiAgICAgIHByb2Nlc3NOZXh0OiAoKSA9PiB0aGlzLmRlbGl2ZXJOZXh0KCksXG4gICAgICBmbHVzaEJ1ZGdldE1zOiBvcHRzPy5mbHVzaEJ1ZGdldE1zLFxuICAgICAgbm93OiBvcHRzPy5ub3csXG4gICAgICBzY2hlZHVsZTogb3B0cz8uc2NoZWR1bGUsXG4gICAgICBvbkZsdXNoU3RhcnQ6ICgpID0+IHtcbiAgICAgICAgZm9yIChjb25zdCBzdGF0cyBvZiB0aGlzLmxpc3RlbmVyU3RhdHMudmFsdWVzKCkpIHN0YXRzLmxhc3RGbHVzaE1zID0gMDtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICAvKiogSWRlbXBvdGVudCBieSBpZCDigJQgc2FtZSBpZCByZXBsYWNlcyAoc3RhdHMgY29udGludWUpLCBpZHMgY29leGlzdC4gKi9cbiAgYWRkTGlzdGVuZXIoaWQ6IHN0cmluZywgbGlzdGVuZXI6IERlZmVycmVkTGlzdGVuZXIpOiB2b2lkIHtcbiAgICB0aGlzLmxpc3RlbmVycy5zZXQoaWQsIGxpc3RlbmVyKTtcbiAgICBpZiAoIXRoaXMubGlzdGVuZXJTdGF0cy5oYXMoaWQpKSB7XG4gICAgICB0aGlzLmxpc3RlbmVyU3RhdHMuc2V0KGlkLCB7IGV2ZW50czogMCwgdG90YWxNczogMCwgbGFzdEZsdXNoTXM6IDAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFN0b3AgZGVsaXZlcmluZyB0byBgaWRgLiBBY2N1bXVsYXRlZCBzdGF0cyBhcmUga2VwdCBmb3IgcmVwb3J0cy4gKi9cbiAgcmVtb3ZlTGlzdGVuZXIoaWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMubGlzdGVuZXJzLmRlbGV0ZShpZCk7XG4gIH1cblxuICAvKipcbiAgICogUHJvZHVjZXIgZW50cnkgcG9pbnQ6IGNhcHR1cmUgdGhlIGV2ZW50IChzZXEtc3RhbXBlZCwgcGF5bG9hZCBwZXJcbiAgICogcG9saWN5KSBhbmQgc3RhZ2UgaXQgZm9yIHRoZSBuZXh0IGNoZWNrcG9pbnQuIENoZWFwOyBORVZFUiB0aHJvd3M7XG4gICAqIG5ldmVyIGJsb2NrcyDigJQgZXhjZXB0IHVuZGVyIGAnYmxvY2snYCBvdmVyZmxvdywgd2hlcmUgYSByZWZ1c2VkXG4gICAqIGVucXVldWUgaXMgZGVsaXZlcmVkIHN5bmNocm9ub3VzbHkgaW5saW5lIChleHBsaWNpdCBjb25zdW1lciBjaG9pY2UpLlxuICAgKi9cbiAgY2FwdHVyZShpbnB1dDogRW5xdWV1ZUlucHV0LCBwb2xpY3k/OiBDYXB0dXJlUG9saWN5KTogdm9pZCB7XG4gICAgY29uc3QgcmVzdWx0ID0gdGhpcy5xdWV1ZS5lbnF1ZXVlKGlucHV0LCBwb2xpY3kpO1xuICAgIGlmIChyZXN1bHQub3V0Y29tZSA9PT0gJ3F1ZXVlZCcpIHtcbiAgICAgIHRoaXMuZHJpdmVyLmFybSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAocmVzdWx0Lm91dGNvbWUgPT09ICdpbmxpbmUnKSB7XG4gICAgICB0aGlzLmlubGluZURlbGl2ZXJpZXMgKz0gMTtcbiAgICAgIHRoaXMuZGVsaXZlcihyZXN1bHQuZW52ZWxvcGUpO1xuICAgIH1cbiAgICAvLyAnZHJvcHBlZCc6IGNvdW50ZWQgYnkgdGhlIHF1ZXVlOyBsb3NzIHN1cmZhY2VzIGluIHN0YXRzICsgc2VxIGdhcHMuXG4gIH1cblxuICAvKipcbiAgICogVGVybWluYWwgZmx1c2gg4oCUIHN5bmNocm9ub3VzbHkgZGVsaXZlciBldmVyeXRoaW5nIHF1ZXVlZCAoZW5kIG9mIHJ1biAvXG4gICAqIHNodXRkb3duKS4gQXN5bmMgbGlzdGVuZXIgY29udGludWF0aW9ucyBhcmUgTk9UIGF3YWl0ZWQ7IGZvbGxvdyB3aXRoXG4gICAqIGBkcmFpbigpYCBmb3IgdGhhdC5cbiAgICovXG4gIGZsdXNoTm93KG9wdHM/OiB7IG1heFJvdW5kcz86IG51bWJlciB9KTogRmx1c2hTeW5jUmVzdWx0IHtcbiAgICByZXR1cm4gdGhpcy5kcml2ZXIuZmx1c2hTeW5jKG9wdHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsdXNoIHRoZSBiYWNrbG9nLCB0aGVuIHNldHRsZSBhbGwgaW5mbGlnaHQgYXN5bmMgY29udGludWF0aW9ucyDigJRcbiAgICogYFByb21pc2UuYWxsU2V0dGxlZGAgdW5kZXIgYSBkZWFkbGluZSwgc2hhcGVkIGxpa2UgYGZsdXNoQWxsRGV0YWNoZWRgLlxuICAgKiBMb29wcyB3aGlsZSBjb250aW51YXRpb25zIHNwYXduIG5ldyBjYXB0dXJlcywgdW50aWwgcXVpZXNjZW50IG9yIHRoZVxuICAgKiBkZWFkbGluZSBleHBpcmVzLlxuICAgKi9cbiAgYXN5bmMgZHJhaW4ob3B0cz86IHsgdGltZW91dE1zPzogbnVtYmVyIH0pOiBQcm9taXNlPERyYWluUmVzdWx0PiB7XG4gICAgY29uc3QgdGltZW91dE1zID0gb3B0cz8udGltZW91dE1zID8/IDMwXzAwMDtcbiAgICBjb25zdCBzdGFydGVkQXQgPSBEYXRlLm5vdygpO1xuICAgIGxldCBkb25lID0gMDtcbiAgICBsZXQgZmFpbGVkID0gMDtcblxuICAgIHRoaXMuZmx1c2hOb3coKTtcbiAgICB3aGlsZSAodGhpcy5pbmZsaWdodC5zaXplID4gMCkge1xuICAgICAgY29uc3QgcmVtYWluaW5nTXMgPSB0aW1lb3V0TXMgLSAoRGF0ZS5ub3coKSAtIHN0YXJ0ZWRBdCk7XG4gICAgICBpZiAocmVtYWluaW5nTXMgPD0gMCkgcmV0dXJuIHsgZG9uZSwgZmFpbGVkLCBwZW5kaW5nOiB0aGlzLmluZmxpZ2h0LnNpemUgKyB0aGlzLnF1ZXVlLmRlcHRoIH07XG5cbiAgICAgIGNvbnN0IGJhdGNoID0gWy4uLnRoaXMuaW5mbGlnaHRdO1xuICAgICAgbGV0IHRpbWVySWQ6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkO1xuICAgICAgY29uc3QgdGltZW91dFByb21pc2UgPSBuZXcgUHJvbWlzZTwnX19kcmFpbl90aW1lb3V0X18nPigocmVzb2x2ZSkgPT4ge1xuICAgICAgICB0aW1lcklkID0gc2V0VGltZW91dCgoKSA9PiByZXNvbHZlKCdfX2RyYWluX3RpbWVvdXRfXycpLCByZW1haW5pbmdNcyk7XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHNldHRsZWQgPSBhd2FpdCBQcm9taXNlLnJhY2UoW1Byb21pc2UuYWxsU2V0dGxlZChiYXRjaCksIHRpbWVvdXRQcm9taXNlXSk7XG4gICAgICBpZiAodGltZXJJZCAhPT0gdW5kZWZpbmVkKSBjbGVhclRpbWVvdXQodGltZXJJZCk7XG4gICAgICBpZiAoc2V0dGxlZCA9PT0gJ19fZHJhaW5fdGltZW91dF9fJykge1xuICAgICAgICByZXR1cm4geyBkb25lLCBmYWlsZWQsIHBlbmRpbmc6IHRoaXMuaW5mbGlnaHQuc2l6ZSArIHRoaXMucXVldWUuZGVwdGggfTtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgciBvZiBzZXR0bGVkKSB7XG4gICAgICAgIC8vIFRyYWNrZWQgcHJvbWlzZXMgbmV2ZXIgcmVqZWN0IOKAlCB0aGV5IHJlc29sdmUgdHJ1ZSAob2spIC8gZmFsc2UuXG4gICAgICAgIGlmIChyLnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcgJiYgci52YWx1ZSA9PT0gZmFsc2UpIGZhaWxlZCArPSAxO1xuICAgICAgICBlbHNlIGRvbmUgKz0gMTtcbiAgICAgIH1cbiAgICAgIC8vIENvbnRpbnVhdGlvbnMgbWF5IGhhdmUgY2FwdHVyZWQgbW9yZSBldmVudHMg4oCUIGZsdXNoIGFuZCByZS1jaGVjay5cbiAgICAgIHRoaXMuZmx1c2hOb3coKTtcbiAgICB9XG4gICAgcmV0dXJuIHsgZG9uZSwgZmFpbGVkLCBwZW5kaW5nOiB0aGlzLnF1ZXVlLmRlcHRoIH07XG4gIH1cblxuICAvKiogQTQg4oCUIHRoZSBzdGF0cyBvYmplY3QgQmxvY2sgOSBjb25zdW1lcy4gUHVyZSBnZXR0ZXIsIGZyZXNoIHNuYXBzaG90LiAqL1xuICBnZXRTdGF0cygpOiBEaXNwYXRjaGVyU3RhdHMge1xuICAgIGNvbnN0IGNvdW50ZXJzID0gdGhpcy5xdWV1ZS5nZXRDb3VudGVycygpO1xuICAgIGNvbnN0IGRyaXZlclN0YXRzID0gdGhpcy5kcml2ZXIuZ2V0U3RhdHMoKTtcbiAgICBjb25zdCBwZXJMaXN0ZW5lcjogUmVjb3JkPHN0cmluZywgTGlzdGVuZXJTdGF0cz4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IFtpZCwgc3RhdHNdIG9mIHRoaXMubGlzdGVuZXJTdGF0cykge1xuICAgICAgcGVyTGlzdGVuZXJbaWRdID0geyBldmVudHM6IHN0YXRzLmV2ZW50cywgdG90YWxNczogc3RhdHMudG90YWxNcywgbGFzdEZsdXNoTXM6IHN0YXRzLmxhc3RGbHVzaE1zIH07XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICBkZXB0aDogdGhpcy5xdWV1ZS5kZXB0aCxcbiAgICAgIGRyb3BzOiBjb3VudGVycy5kcm9wcyxcbiAgICAgIGZsdXNoZXM6IGRyaXZlclN0YXRzLmZsdXNoZXMsXG4gICAgICBidWRnZXRFeGhhdXN0ZWQ6IGRyaXZlclN0YXRzLmJ1ZGdldEV4aGF1c3RlZCxcbiAgICAgIHA5NUZsdXNoTXM6IGRyaXZlclN0YXRzLnA5NUZsdXNoTXMsXG4gICAgICBpbmxpbmVEZWxpdmVyaWVzOiB0aGlzLmlubGluZURlbGl2ZXJpZXMsXG4gICAgICBpbmZsaWdodDogdGhpcy5pbmZsaWdodC5zaXplLFxuICAgICAgcGVyTGlzdGVuZXIsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgZGVsaXZlck5leHQoKTogdm9pZCB7XG4gICAgY29uc3QgZW52ZWxvcGUgPSB0aGlzLnF1ZXVlLnNoaWZ0KCk7XG4gICAgaWYgKGVudmVsb3BlID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0aGlzLmRlbGl2ZXIoZW52ZWxvcGUpO1xuICB9XG5cbiAgLyoqIEludm9rZSBldmVyeSBsaXN0ZW5lciB3aXRoIGZ1bGwgZXJyb3IgaXNvbGF0aW9uICsgdGltZSBhY2NvdW50aW5nLiAqL1xuICBwcml2YXRlIGRlbGl2ZXIoZW52ZWxvcGU6IENhcHR1cmVFbnZlbG9wZSk6IHZvaWQge1xuICAgIGZvciAoY29uc3QgW2lkLCBsaXN0ZW5lcl0gb2YgdGhpcy5saXN0ZW5lcnMpIHtcbiAgICAgIGNvbnN0IHN0YXRzID0gdGhpcy5saXN0ZW5lclN0YXRzLmdldChpZCkgYXMgTXV0YWJsZUxpc3RlbmVyU3RhdHM7XG4gICAgICBjb25zdCBzdGFydCA9IHRoaXMubm93KCk7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBsaXN0ZW5lcihlbnZlbG9wZSk7XG4gICAgICAgIGlmIChpc1RoZW5hYmxlKHJlc3VsdCkpIHRoaXMudHJhY2socmVzdWx0LCBpZCwgZW52ZWxvcGUpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zYWZlT25FcnJvcihlcnJvciwgeyBsaXN0ZW5lcklkOiBpZCwgZW52ZWxvcGUsIHBoYXNlOiAnc3luYycgfSk7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBjb25zdCBlbGFwc2VkID0gdGhpcy5ub3coKSAtIHN0YXJ0O1xuICAgICAgICBzdGF0cy5ldmVudHMgKz0gMTtcbiAgICAgICAgc3RhdHMudG90YWxNcyArPSBlbGFwc2VkO1xuICAgICAgICBzdGF0cy5sYXN0Rmx1c2hNcyArPSBlbGFwc2VkO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBUcmFjayBhbiBhc3luYyBjb250aW51YXRpb247IHJvdXRlIGl0cyByZWplY3Rpb247IG5ldmVyIHJlamVjdC4gKi9cbiAgcHJpdmF0ZSB0cmFjayhwcm9taXNlOiBQcm9taXNlPHZvaWQ+LCBsaXN0ZW5lcklkOiBzdHJpbmcsIGVudmVsb3BlOiBDYXB0dXJlRW52ZWxvcGUpOiB2b2lkIHtcbiAgICBjb25zdCB0cmFja2VkOiBQcm9taXNlPGJvb2xlYW4+ID0gcHJvbWlzZS50aGVuKFxuICAgICAgKCkgPT4gdHJ1ZSxcbiAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICB0aGlzLnNhZmVPbkVycm9yKGVycm9yLCB7IGxpc3RlbmVySWQsIGVudmVsb3BlLCBwaGFzZTogJ2FzeW5jJyB9KTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSxcbiAgICApO1xuICAgIHRoaXMuaW5mbGlnaHQuYWRkKHRyYWNrZWQpO1xuICAgIC8vIFNlbGYtY2xlYW51cCDigJQgYHRyYWNrZWRgIG5ldmVyIHJlamVjdHMsIHNvIHRoaXMgY2hhaW4gY2Fubm90IGZsb2F0IGFuXG4gICAgLy8gdW5oYW5kbGVkIHJlamVjdGlvbi5cbiAgICB0cmFja2VkLnRoZW4oKCkgPT4gdGhpcy5pbmZsaWdodC5kZWxldGUodHJhY2tlZCkpO1xuICB9XG5cbiAgLyoqIFRoZSBlcnJvciBzaW5rIG11c3QgbmV2ZXIgYmVjb21lIGFuIGVycm9yIHNvdXJjZS4gKi9cbiAgcHJpdmF0ZSBzYWZlT25FcnJvcihlcnJvcjogdW5rbm93biwgY29udGV4dDogRGlzcGF0Y2hFcnJvckNvbnRleHQpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgdGhpcy5vbkVycm9yPy4oZXJyb3IsIGNvbnRleHQpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gU3dhbGxvdyDigJQgaXNvbGF0aW9uIGlzIGFic29sdXRlLlxuICAgIH1cbiAgfVxufVxuIl19
@@ -0,0 +1,163 @@
1
+ /**
2
+ * observer-queue/flushDriver.ts — RFC-001 Block 4: armed-once microtask batcher.
3
+ *
4
+ * Pattern: Kernel-style bottom-half. Producers only set a flag ("work
5
+ * pending") and return; the actual work runs at the next
6
+ * scheduling checkpoint (a microtask), drains under a time
7
+ * budget, and re-arms itself if backlog remains. Same shape as
8
+ * the detach module's `microtaskBatchDriver` — accumulate during
9
+ * the current sync slice, drain at the boundary.
10
+ * Role: The scheduler of the deferred-observer pipeline. Owns WHEN
11
+ * delivery happens; knows nothing about envelopes or listeners
12
+ * (the dispatcher, Block 5, injects `depth`/`processNext`).
13
+ * Pure module — zero imports, zero engine knowledge.
14
+ *
15
+ * Scheduling semantics (normative, RFC-001 §5 + amendment A1):
16
+ * - `arm()` is idempotent: at most ONE pending flush exists (armed flag).
17
+ * N captures between checkpoints ⇒ exactly 1 flush.
18
+ * - A flush drains a SNAPSHOT: at most `depth()`-at-flush-start items.
19
+ * Events enqueued BY listeners during the flush exceed the snapshot and
20
+ * land at the NEXT checkpoint — listener-driven cascades cannot starve
21
+ * the event loop.
22
+ * - `flushBudgetMs` (default 2; `Infinity` = full snapshot drain): the
23
+ * flush stops once the budget is exhausted, counts `budgetExhausted`,
24
+ * and re-arms. At least ONE item is processed per flush regardless of
25
+ * budget — guaranteed progress under any clock.
26
+ * - If backlog remains after the flush (budget cut OR listener enqueues),
27
+ * the driver re-arms for the next checkpoint.
28
+ *
29
+ * Why stage boundaries make this safe: the engine `await`s every stage, so
30
+ * the microtask queue runs at EVERY stage boundary — flushes are at most
31
+ * "one beat behind" the producing stage. See
32
+ * `docs/guides/execution-model.md` ("Stage boundaries are scheduling
33
+ * points") and the FAQ in `docs/design/rfc-001-deferred-observers.md`.
34
+ *
35
+ * Testability: `now` (clock) and `schedule` (checkpoint primitive) are
36
+ * injectable — tests pump flushes deterministically with a fake clock and
37
+ * a captured-callback scheduler; production uses `performance.now` and
38
+ * `queueMicrotask`.
39
+ */
40
+ /** Rolling sample window for the p95 flush-duration stat (A4). */
41
+ export const FLUSH_SAMPLE_WINDOW = 128;
42
+ /** Default cascade cap for {@link FlushDriver.flushSync}. */
43
+ const DEFAULT_MAX_SYNC_ROUNDS = 1_000;
44
+ const defaultNow = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());
45
+ export class FlushDriver {
46
+ depth;
47
+ processNext;
48
+ flushBudgetMs;
49
+ now;
50
+ schedule;
51
+ onFlushStart;
52
+ onFlushEnd;
53
+ armed = false;
54
+ flushes = 0;
55
+ budgetExhaustedCount = 0;
56
+ lastFlushMs = 0;
57
+ samples = [];
58
+ sampleWriteIdx = 0;
59
+ constructor(opts) {
60
+ const budget = opts.flushBudgetMs ?? 2;
61
+ if (Number.isNaN(budget) || budget <= 0) {
62
+ throw new RangeError(`flushBudgetMs must be > 0 (got ${budget}); use Infinity for full drains`);
63
+ }
64
+ this.depth = opts.depth;
65
+ this.processNext = opts.processNext;
66
+ this.flushBudgetMs = budget;
67
+ this.now = opts.now ?? defaultNow;
68
+ this.schedule = opts.schedule ?? ((cb) => queueMicrotask(cb));
69
+ this.onFlushStart = opts.onFlushStart;
70
+ this.onFlushEnd = opts.onFlushEnd;
71
+ }
72
+ /**
73
+ * Request a flush at the next checkpoint. Idempotent — while one flush
74
+ * is pending, further arms are free no-ops (the armed-once invariant).
75
+ */
76
+ arm() {
77
+ if (this.armed)
78
+ return;
79
+ this.armed = true;
80
+ this.schedule(() => this.flush());
81
+ }
82
+ /**
83
+ * Synchronous full drain — the terminal-flush primitive (end of run /
84
+ * shutdown). Repeats snapshot rounds until the queue is empty so
85
+ * listener-enqueued cascades drain too, capped at `maxRounds` so a
86
+ * listener that enqueues forever cannot hang the process (`remaining`
87
+ * reports what the cap left behind).
88
+ */
89
+ flushSync(opts) {
90
+ const maxRounds = opts?.maxRounds ?? DEFAULT_MAX_SYNC_ROUNDS;
91
+ if (this.depth() === 0)
92
+ return { drained: 0, remaining: 0 };
93
+ this.onFlushStart?.();
94
+ const start = this.now();
95
+ let drained = 0;
96
+ for (let round = 0; round < maxRounds && this.depth() > 0; round++) {
97
+ const snapshot = this.depth();
98
+ for (let i = 0; i < snapshot && this.depth() > 0; i++) {
99
+ this.processNext();
100
+ drained += 1;
101
+ }
102
+ }
103
+ this.recordFlush(this.now() - start, false);
104
+ const remaining = this.depth();
105
+ this.onFlushEnd?.({ processed: drained, budgetExhausted: false, rearmed: false });
106
+ return { drained, remaining };
107
+ }
108
+ getStats() {
109
+ return {
110
+ flushes: this.flushes,
111
+ budgetExhausted: this.budgetExhaustedCount,
112
+ lastFlushMs: this.lastFlushMs,
113
+ p95FlushMs: this.p95FlushMs(),
114
+ armed: this.armed,
115
+ };
116
+ }
117
+ /** The microtask body — see the module-header semantics. */
118
+ flush() {
119
+ this.armed = false;
120
+ const snapshot = this.depth();
121
+ if (snapshot === 0)
122
+ return; // raced with flushSync — zero-work wakeup
123
+ this.onFlushStart?.();
124
+ const start = this.now();
125
+ let processed = 0;
126
+ let exhausted = false;
127
+ while (processed < snapshot && this.depth() > 0) {
128
+ // Budget check AFTER the first item — guaranteed progress per flush.
129
+ if (processed > 0 && this.now() - start >= this.flushBudgetMs) {
130
+ exhausted = true;
131
+ break;
132
+ }
133
+ this.processNext();
134
+ processed += 1;
135
+ }
136
+ this.recordFlush(this.now() - start, exhausted);
137
+ // Backlog left (budget cut, or listeners enqueued past the snapshot):
138
+ // hand it to the NEXT checkpoint — never starve, never spin.
139
+ const rearmed = this.depth() > 0;
140
+ if (rearmed)
141
+ this.arm();
142
+ this.onFlushEnd?.({ processed, budgetExhausted: exhausted, rearmed });
143
+ }
144
+ recordFlush(elapsedMs, exhausted) {
145
+ this.flushes += 1;
146
+ this.lastFlushMs = elapsedMs;
147
+ if (exhausted)
148
+ this.budgetExhaustedCount += 1;
149
+ if (this.samples.length < FLUSH_SAMPLE_WINDOW)
150
+ this.samples.push(elapsedMs);
151
+ else {
152
+ this.samples[this.sampleWriteIdx] = elapsedMs;
153
+ this.sampleWriteIdx = (this.sampleWriteIdx + 1) % FLUSH_SAMPLE_WINDOW;
154
+ }
155
+ }
156
+ p95FlushMs() {
157
+ if (this.samples.length === 0)
158
+ return 0;
159
+ const sorted = [...this.samples].sort((a, b) => a - b);
160
+ return sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95))];
161
+ }
162
+ }
163
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmx1c2hEcml2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL29ic2VydmVyLXF1ZXVlL2ZsdXNoRHJpdmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNDRztBQXFESCxrRUFBa0U7QUFDbEUsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsR0FBRyxDQUFDO0FBRXZDLDZEQUE2RDtBQUM3RCxNQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQztBQUV0QyxNQUFNLFVBQVUsR0FBRyxHQUFXLEVBQUUsQ0FBQyxDQUFDLE9BQU8sV0FBVyxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUV2RyxNQUFNLE9BQU8sV0FBVztJQUNMLEtBQUssQ0FBZTtJQUNwQixXQUFXLENBQWE7SUFDeEIsYUFBYSxDQUFTO0lBQ3RCLEdBQUcsQ0FBZTtJQUNsQixRQUFRLENBQTJCO0lBQ25DLFlBQVksQ0FBYztJQUMxQixVQUFVLENBQW1DO0lBRXRELEtBQUssR0FBRyxLQUFLLENBQUM7SUFDZCxPQUFPLEdBQUcsQ0FBQyxDQUFDO0lBQ1osb0JBQW9CLEdBQUcsQ0FBQyxDQUFDO0lBQ3pCLFdBQVcsR0FBRyxDQUFDLENBQUM7SUFDUCxPQUFPLEdBQWEsRUFBRSxDQUFDO0lBQ2hDLGNBQWMsR0FBRyxDQUFDLENBQUM7SUFFM0IsWUFBWSxJQUF3QjtRQUNsQyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsYUFBYSxJQUFJLENBQUMsQ0FBQztRQUN2QyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3hDLE1BQU0sSUFBSSxVQUFVLENBQUMsa0NBQWtDLE1BQU0saUNB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QUFHLFNBQVMsQ0FBQztRQUM3QixJQUFJLFNBQVM7WUFBRSxJQUFJLENBQUMsb0JBQW9CLElBQUksQ0FBQyxDQUFDO1FBQzlDLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsbUJBQW1CO1lBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7YUFDdkUsQ0FBQztZQUNKLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLFNBQVMsQ0FBQztZQUM5QyxJQUFJLENBQUMsY0FBYyxHQUFHLENBQUMsSUFBSSxDQUFDLGNBQWMsR0FBRyxDQUFDLENBQUMsR0FBRyxtQkFBbUIsQ0FBQztRQUN4RSxDQUFDO0lBQ0gsQ0FBQztJQUVPLFVBQVU7UUFDaEIsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsT0FBTyxDQUFDLENBQUM7UUFDeEMsTUFBTSxNQUFNLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDdkQsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQy9FLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogb2JzZXJ2ZXItcXVldWUvZmx1c2hEcml2ZXIudHMg4oCUIFJGQy0wMDEgQmxvY2sgNDogYXJtZWQtb25jZSBtaWNyb3Rhc2sgYmF0Y2hlci5cbiAqXG4gKiBQYXR0ZXJuOiAgS2VybmVsLXN0eWxlIGJvdHRvbS1oYWxmLiBQcm9kdWNlcnMgb25seSBzZXQgYSBmbGFnIChcIndvcmtcbiAqICAgICAgICAgICBwZW5kaW5nXCIpIGFuZCByZXR1cm47IHRoZSBhY3R1YWwgd29yayBydW5zIGF0IHRoZSBuZXh0XG4gKiAgICAgICAgICAgc2NoZWR1bGluZyBjaGVja3BvaW50IChhIG1pY3JvdGFzayksIGRyYWlucyB1bmRlciBhIHRpbWVcbiAqICAgICAgICAgICBidWRnZXQsIGFuZCByZS1hcm1zIGl0c2VsZiBpZiBiYWNrbG9nIHJlbWFpbnMuIFNhbWUgc2hhcGUgYXNcbiAqICAgICAgICAgICB0aGUgZGV0YWNoIG1vZHVsZSdzIGBtaWNyb3Rhc2tCYXRjaERyaXZlcmAg4oCUIGFjY3VtdWxhdGUgZHVyaW5nXG4gKiAgICAgICAgICAgdGhlIGN1cnJlbnQgc3luYyBzbGljZSwgZHJhaW4gYXQgdGhlIGJvdW5kYXJ5LlxuICogUm9sZTogICAgIFRoZSBzY2hlZHVsZXIgb2YgdGhlIGRlZmVycmVkLW9ic2VydmVyIHBpcGVsaW5lLiBPd25zIFdIRU5cbiAqICAgICAgICAgICBkZWxpdmVyeSBoYXBwZW5zOyBrbm93cyBub3RoaW5nIGFib3V0IGVudmVsb3BlcyBvciBsaXN0ZW5lcnNcbiAqICAgICAgICAgICAodGhlIGRpc3BhdGNoZXIsIEJsb2NrIDUsIGluamVjdHMgYGRlcHRoYC9gcHJvY2Vzc05leHRgKS5cbiAqICAgICAgICAgICBQdXJlIG1vZHVsZSDigJQgemVybyBpbXBvcnRzLCB6ZXJvIGVuZ2luZSBrbm93bGVkZ2UuXG4gKlxuICogU2NoZWR1bGluZyBzZW1hbnRpY3MgKG5vcm1hdGl2ZSwgUkZDLTAwMSDCpzUgKyBhbWVuZG1lbnQgQTEpOlxuICogICAtIGBhcm0oKWAgaXMgaWRlbXBvdGVudDogYXQgbW9zdCBPTkUgcGVuZGluZyBmbHVzaCBleGlzdHMgKGFybWVkIGZsYWcpLlxuICogICAgIE4gY2FwdHVyZXMgYmV0d2VlbiBjaGVja3BvaW50cyDih5IgZXhhY3RseSAxIGZsdXNoLlxuICogICAtIEEgZmx1c2ggZHJhaW5zIGEgU05BUFNIT1Q6IGF0IG1vc3QgYGRlcHRoKClgLWF0LWZsdXNoLXN0YXJ0IGl0ZW1zLlxuICogICAgIEV2ZW50cyBlbnF1ZXVlZCBCWSBsaXN0ZW5lcnMgZHVyaW5nIHRoZSBmbHVzaCBleGNlZWQgdGhlIHNuYXBzaG90IGFuZFxuICogICAgIGxhbmQgYXQgdGhlIE5FWFQgY2hlY2twb2ludCDigJQgbGlzdGVuZXItZHJpdmVuIGNhc2NhZGVzIGNhbm5vdCBzdGFydmVcbiAqICAgICB0aGUgZXZlbnQgbG9vcC5cbiAqICAgLSBgZmx1c2hCdWRnZXRNc2AgKGRlZmF1bHQgMjsgYEluZmluaXR5YCA9IGZ1bGwgc25hcHNob3QgZHJhaW4pOiB0aGVcbiAqICAgICBmbHVzaCBzdG9wcyBvbmNlIHRoZSBidWRnZXQgaXMgZXhoYXVzdGVkLCBjb3VudHMgYGJ1ZGdldEV4aGF1c3RlZGAsXG4gKiAgICAgYW5kIHJlLWFybXMuIEF0IGxlYXN0IE9ORSBpdGVtIGlzIHByb2Nlc3NlZCBwZXIgZmx1c2ggcmVnYXJkbGVzcyBvZlxuICogICAgIGJ1ZGdldCDigJQgZ3VhcmFudGVlZCBwcm9ncmVzcyB1bmRlciBhbnkgY2xvY2suXG4gKiAgIC0gSWYgYmFja2xvZyByZW1haW5zIGFmdGVyIHRoZSBmbHVzaCAoYnVkZ2V0IGN1dCBPUiBsaXN0ZW5lciBlbnF1ZXVlcyksXG4gKiAgICAgdGhlIGRyaXZlciByZS1hcm1zIGZvciB0aGUgbmV4dCBjaGVja3BvaW50LlxuICpcbiAqIFdoeSBzdGFnZSBib3VuZGFyaWVzIG1ha2UgdGhpcyBzYWZlOiB0aGUgZW5naW5lIGBhd2FpdGBzIGV2ZXJ5IHN0YWdlLCBzb1xuICogdGhlIG1pY3JvdGFzayBxdWV1ZSBydW5zIGF0IEVWRVJZIHN0YWdlIGJvdW5kYXJ5IOKAlCBmbHVzaGVzIGFyZSBhdCBtb3N0XG4gKiBcIm9uZSBiZWF0IGJlaGluZFwiIHRoZSBwcm9kdWNpbmcgc3RhZ2UuIFNlZVxuICogYGRvY3MvZ3VpZGVzL2V4ZWN1dGlvbi1tb2RlbC5tZGAgKFwiU3RhZ2UgYm91bmRhcmllcyBhcmUgc2NoZWR1bGluZ1xuICogcG9pbnRzXCIpIGFuZCB0aGUgRkFRIGluIGBkb2NzL2Rlc2lnbi9yZmMtMDAxLWRlZmVycmVkLW9ic2VydmVycy5tZGAuXG4gKlxuICogVGVzdGFiaWxpdHk6IGBub3dgIChjbG9jaykgYW5kIGBzY2hlZHVsZWAgKGNoZWNrcG9pbnQgcHJpbWl0aXZlKSBhcmVcbiAqIGluamVjdGFibGUg4oCUIHRlc3RzIHB1bXAgZmx1c2hlcyBkZXRlcm1pbmlzdGljYWxseSB3aXRoIGEgZmFrZSBjbG9jayBhbmRcbiAqIGEgY2FwdHVyZWQtY2FsbGJhY2sgc2NoZWR1bGVyOyBwcm9kdWN0aW9uIHVzZXMgYHBlcmZvcm1hbmNlLm5vd2AgYW5kXG4gKiBgcXVldWVNaWNyb3Rhc2tgLlxuICovXG5cbi8qKiBSZXN1bHQgb2Ygb25lIGZsdXNoIChhbHNvIGRlbGl2ZXJlZCB0byBgb25GbHVzaEVuZGApLiAqL1xuZXhwb3J0IGludGVyZmFjZSBGbHVzaE91dGNvbWUge1xuICAvKiogSXRlbXMgcHJvY2Vzc2VkIGluIHRoaXMgZmx1c2guICovXG4gIHJlYWRvbmx5IHByb2Nlc3NlZDogbnVtYmVyO1xuICAvKiogVHJ1ZSB3aGVuIHRoZSB0aW1lIGJ1ZGdldCBjdXQgdGhlIGZsdXNoIGJlZm9yZSB0aGUgc25hcHNob3QgZHJhaW5lZC4gKi9cbiAgcmVhZG9ubHkgYnVkZ2V0RXhoYXVzdGVkOiBib29sZWFuO1xuICAvKiogVHJ1ZSB3aGVuIGJhY2tsb2cgcmVtYWluZWQgYW5kIHRoZSBkcml2ZXIgcmUtYXJtZWQgaXRzZWxmLiAqL1xuICByZWFkb25seSByZWFybWVkOiBib29sZWFuO1xufVxuXG4vKiogUmVzdWx0IG9mIGEgc3luY2hyb25vdXMge0BsaW5rIEZsdXNoRHJpdmVyLmZsdXNoU3luY30gZHJhaW4uICovXG5leHBvcnQgaW50ZXJmYWNlIEZsdXNoU3luY1Jlc3VsdCB7XG4gIC8qKiBJdGVtcyBwcm9jZXNzZWQgYWNyb3NzIGFsbCByb3VuZHMuICovXG4gIHJlYWRvbmx5IGRyYWluZWQ6IG51bWJlcjtcbiAgLyoqIEl0ZW1zIHN0aWxsIHF1ZXVlZCB3aGVuIGBtYXhSb3VuZHNgIHN0b3BwZWQgYSBydW5hd2F5IGNhc2NhZGUuICovXG4gIHJlYWRvbmx5IHJlbWFpbmluZzogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEZsdXNoRHJpdmVyT3B0aW9ucyB7XG4gIC8qKiBDdXJyZW50IGJhY2tsb2cgb2YgdGhlIHF1ZXVlIHRoaXMgZHJpdmVyIGRyYWlucy4gKi9cbiAgcmVhZG9ubHkgZGVwdGg6ICgpID0+IG51bWJlcjtcbiAgLyoqIFByb2Nlc3MgZXhhY3RseSBPTkUgcXVldWVkIGl0ZW0uIFByZWNvbmRpdGlvbjogYGRlcHRoKCkgPiAwYC4gKi9cbiAgcmVhZG9ubHkgcHJvY2Vzc05leHQ6ICgpID0+IHZvaWQ7XG4gIC8qKlxuICAgKiBQZXItZmx1c2ggdGltZSBidWRnZXQgaW4gbXMuIERlZmF1bHQgMi4gYEluZmluaXR5YCBkcmFpbnMgdGhlIGZ1bGxcbiAgICogc25hcHNob3QgZXZlcnkgY2hlY2twb2ludC4gTXVzdCBiZSA+IDAuXG4gICAqL1xuICByZWFkb25seSBmbHVzaEJ1ZGdldE1zPzogbnVtYmVyO1xuICAvKiogQ2xvY2sg4oCUIGRlZmF1bHQgYHBlcmZvcm1hbmNlLm5vd2AgKGZhbGxzIGJhY2sgdG8gYERhdGUubm93YCkuICovXG4gIHJlYWRvbmx5IG5vdz86ICgpID0+IG51bWJlcjtcbiAgLyoqIENoZWNrcG9pbnQgcHJpbWl0aXZlIOKAlCBkZWZhdWx0IGBxdWV1ZU1pY3JvdGFza2AuICovXG4gIHJlYWRvbmx5IHNjaGVkdWxlPzogKGNiOiAoKSA9PiB2b2lkKSA9PiB2b2lkO1xuICAvKiogRmlyZXMgYmVmb3JlIHRoZSBmaXJzdCBpdGVtIG9mIGV2ZXJ5IGZsdXNoIChpbmNsLiBgZmx1c2hTeW5jYCkuICovXG4gIHJlYWRvbmx5IG9uRmx1c2hTdGFydD86ICgpID0+IHZvaWQ7XG4gIC8qKiBGaXJlcyBhZnRlciBldmVyeSBmbHVzaCB3aXRoIGl0cyBvdXRjb21lIChpbmNsLiBgZmx1c2hTeW5jYCkuICovXG4gIHJlYWRvbmx5IG9uRmx1c2hFbmQ/OiAob3V0Y29tZTogRmx1c2hPdXRjb21lKSA9PiB2b2lkO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEZsdXNoRHJpdmVyU3RhdHMge1xuICAvKiogQ29tcGxldGVkIGZsdXNoZXMgKHplcm8td29yayB3YWtldXBzIGFyZSBub3QgY291bnRlZCkuICovXG4gIHJlYWRvbmx5IGZsdXNoZXM6IG51bWJlcjtcbiAgLyoqIEZsdXNoZXMgY3V0IHNob3J0IGJ5IGBmbHVzaEJ1ZGdldE1zYCAoQTEg4oCUIGJhY2tsb2cgdmlzaWJpbGl0eSkuICovXG4gIHJlYWRvbmx5IGJ1ZGdldEV4aGF1c3RlZDogbnVtYmVyO1xuICAvKiogRHVyYXRpb24gb2YgdGhlIG1vc3QgcmVjZW50IGZsdXNoLCBtcy4gKi9cbiAgcmVhZG9ubHkgbGFzdEZsdXNoTXM6IG51bWJlcjtcbiAgLyoqIHA5NSBvdmVyIHRoZSBsYXN0IHtAbGluayBGTFVTSF9TQU1QTEVfV0lORE9XfSBmbHVzaCBkdXJhdGlvbnMsIG1zLiAqL1xuICByZWFkb25seSBwOTVGbHVzaE1zOiBudW1iZXI7XG4gIC8qKiBUcnVlIHdoaWxlIGEgZmx1c2ggaXMgc2NoZWR1bGVkIGJ1dCBub3QgeWV0IHJ1bi4gKi9cbiAgcmVhZG9ubHkgYXJtZWQ6IGJvb2xlYW47XG59XG5cbi8qKiBSb2xsaW5nIHNhbXBsZSB3aW5kb3cgZm9yIHRoZSBwOTUgZmx1c2gtZHVyYXRpb24gc3RhdCAoQTQpLiAqL1xuZXhwb3J0IGNvbnN0IEZMVVNIX1NBTVBMRV9XSU5ET1cgPSAxMjg7XG5cbi8qKiBEZWZhdWx0IGNhc2NhZGUgY2FwIGZvciB7QGxpbmsgRmx1c2hEcml2ZXIuZmx1c2hTeW5jfS4gKi9cbmNvbnN0IERFRkFVTFRfTUFYX1NZTkNfUk9VTkRTID0gMV8wMDA7XG5cbmNvbnN0IGRlZmF1bHROb3cgPSAoKTogbnVtYmVyID0+ICh0eXBlb2YgcGVyZm9ybWFuY2UgIT09ICd1bmRlZmluZWQnID8gcGVyZm9ybWFuY2Uubm93KCkgOiBEYXRlLm5vdygpKTtcblxuZXhwb3J0IGNsYXNzIEZsdXNoRHJpdmVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBkZXB0aDogKCkgPT4gbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IHByb2Nlc3NOZXh0OiAoKSA9PiB2b2lkO1xuICBwcml2YXRlIHJlYWRvbmx5IGZsdXNoQnVkZ2V0TXM6IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBub3c6ICgpID0+IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBzY2hlZHVsZTogKGNiOiAoKSA9PiB2b2lkKSA9PiB2b2lkO1xuICBwcml2YXRlIHJlYWRvbmx5IG9uRmx1c2hTdGFydD86ICgpID0+IHZvaWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgb25GbHVzaEVuZD86IChvdXRjb21lOiBGbHVzaE91dGNvbWUpID0+IHZvaWQ7XG5cbiAgcHJpdmF0ZSBhcm1lZCA9IGZhbHNlO1xuICBwcml2YXRlIGZsdXNoZXMgPSAwO1xuICBwcml2YXRlIGJ1ZGdldEV4aGF1c3RlZENvdW50ID0gMDtcbiAgcHJpdmF0ZSBsYXN0Rmx1c2hNcyA9IDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2FtcGxlczogbnVtYmVyW10gPSBbXTtcbiAgcHJpdmF0ZSBzYW1wbGVXcml0ZUlkeCA9IDA7XG5cbiAgY29uc3RydWN0b3Iob3B0czogRmx1c2hEcml2ZXJPcHRpb25zKSB7XG4gICAgY29uc3QgYnVkZ2V0ID0gb3B0cy5mbHVzaEJ1ZGdldE1zID8/IDI7XG4gICAgaWYgKE51bWJlci5pc05hTihidWRnZXQpIHx8IGJ1ZGdldCA8PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihgZmx1c2hCdWRnZXRNcyBtdXN0IGJlID4gMCAoZ290ICR7YnVkZ2V0fSk7IHVzZSBJbmZpbml0eSBmb3IgZnVsbCBkcmFpbnNgKTtcbiAgICB9XG4gICAgdGhpcy5kZXB0aCA9IG9wdHMuZGVwdGg7XG4gICAgdGhpcy5wcm9jZXNzTmV4dCA9IG9wdHMucHJvY2Vzc05leHQ7XG4gICAgdGhpcy5mbHVzaEJ1ZGdldE1zID0gYnVkZ2V0O1xuICAgIHRoaXMubm93ID0gb3B0cy5ub3cgPz8gZGVmYXVsdE5vdztcbiAgICB0aGlzLnNjaGVkdWxlID0gb3B0cy5zY2hlZHVsZSA/PyAoKGNiKSA9PiBxdWV1ZU1pY3JvdGFzayhjYikpO1xuICAgIHRoaXMub25GbHVzaFN0YXJ0ID0gb3B0cy5vbkZsdXNoU3RhcnQ7XG4gICAgdGhpcy5vbkZsdXNoRW5kID0gb3B0cy5vbkZsdXNoRW5kO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlcXVlc3QgYSBmbHVzaCBhdCB0aGUgbmV4dCBjaGVja3BvaW50LiBJZGVtcG90ZW50IOKAlCB3aGlsZSBvbmUgZmx1c2hcbiAgICogaXMgcGVuZGluZywgZnVydGhlciBhcm1zIGFyZSBmcmVlIG5vLW9wcyAodGhlIGFybWVkLW9uY2UgaW52YXJpYW50KS5cbiAgICovXG4gIGFybSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hcm1lZCkgcmV0dXJuO1xuICAgIHRoaXMuYXJtZWQgPSB0cnVlO1xuICAgIHRoaXMuc2NoZWR1bGUoKCkgPT4gdGhpcy5mbHVzaCgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTeW5jaHJvbm91cyBmdWxsIGRyYWluIOKAlCB0aGUgdGVybWluYWwtZmx1c2ggcHJpbWl0aXZlIChlbmQgb2YgcnVuIC9cbiAgICogc2h1dGRvd24pLiBSZXBlYXRzIHNuYXBzaG90IHJvdW5kcyB1bnRpbCB0aGUgcXVldWUgaXMgZW1wdHkgc29cbiAgICogbGlzdGVuZXItZW5xdWV1ZWQgY2FzY2FkZXMgZHJhaW4gdG9vLCBjYXBwZWQgYXQgYG1heFJvdW5kc2Agc28gYVxuICAgKiBsaXN0ZW5lciB0aGF0IGVucXVldWVzIGZvcmV2ZXIgY2Fubm90IGhhbmcgdGhlIHByb2Nlc3MgKGByZW1haW5pbmdgXG4gICAqIHJlcG9ydHMgd2hhdCB0aGUgY2FwIGxlZnQgYmVoaW5kKS5cbiAgICovXG4gIGZsdXNoU3luYyhvcHRzPzogeyBtYXhSb3VuZHM/OiBudW1iZXIgfSk6IEZsdXNoU3luY1Jlc3VsdCB7XG4gICAgY29uc3QgbWF4Um91bmRzID0gb3B0cz8ubWF4Um91bmRzID8/IERFRkFVTFRfTUFYX1NZTkNfUk9VTkRTO1xuICAgIGlmICh0aGlzLmRlcHRoKCkgPT09IDApIHJldHVybiB7IGRyYWluZWQ6IDAsIHJlbWFpbmluZzogMCB9O1xuXG4gICAgdGhpcy5vbkZsdXNoU3RhcnQ/LigpO1xuICAgIGNvbnN0IHN0YXJ0ID0gdGhpcy5ub3coKTtcbiAgICBsZXQgZHJhaW5lZCA9IDA7XG4gICAgZm9yIChsZXQgcm91bmQgPSAwOyByb3VuZCA8IG1heFJvdW5kcyAmJiB0aGlzLmRlcHRoKCkgPiAwOyByb3VuZCsrKSB7XG4gICAgICBjb25zdCBzbmFwc2hvdCA9IHRoaXMuZGVwdGgoKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc25hcHNob3QgJiYgdGhpcy5kZXB0aCgpID4gMDsgaSsrKSB7XG4gICAgICAgIHRoaXMucHJvY2Vzc05leHQoKTtcbiAgICAgICAgZHJhaW5lZCArPSAxO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnJlY29yZEZsdXNoKHRoaXMubm93KCkgLSBzdGFydCwgZmFsc2UpO1xuICAgIGNvbnN0IHJlbWFpbmluZyA9IHRoaXMuZGVwdGgoKTtcbiAgICB0aGlzLm9uRmx1c2hFbmQ/Lih7IHByb2Nlc3NlZDogZHJhaW5lZCwgYnVkZ2V0RXhoYXVzdGVkOiBmYWxzZSwgcmVhcm1lZDogZmFsc2UgfSk7XG4gICAgcmV0dXJuIHsgZHJhaW5lZCwgcmVtYWluaW5nIH07XG4gIH1cblxuICBnZXRTdGF0cygpOiBGbHVzaERyaXZlclN0YXRzIHtcbiAgICByZXR1cm4ge1xuICAgICAgZmx1c2hlczogdGhpcy5mbHVzaGVzLFxuICAgICAgYnVkZ2V0RXhoYXVzdGVkOiB0aGlzLmJ1ZGdldEV4aGF1c3RlZENvdW50LFxuICAgICAgbGFzdEZsdXNoTXM6IHRoaXMubGFzdEZsdXNoTXMsXG4gICAgICBwOTVGbHVzaE1zOiB0aGlzLnA5NUZsdXNoTXMoKSxcbiAgICAgIGFybWVkOiB0aGlzLmFybWVkLFxuICAgIH07XG4gIH1cblxuICAvKiogVGhlIG1pY3JvdGFzayBib2R5IOKAlCBzZWUgdGhlIG1vZHVsZS1oZWFkZXIgc2VtYW50aWNzLiAqL1xuICBwcml2YXRlIGZsdXNoKCk6IHZvaWQge1xuICAgIHRoaXMuYXJtZWQgPSBmYWxzZTtcbiAgICBjb25zdCBzbmFwc2hvdCA9IHRoaXMuZGVwdGgoKTtcbiAgICBpZiAoc25hcHNob3QgPT09IDApIHJldHVybjsgLy8gcmFjZWQgd2l0aCBmbHVzaFN5bmMg4oCUIHplcm8td29yayB3YWtldXBcblxuICAgIHRoaXMub25GbHVzaFN0YXJ0Py4oKTtcbiAgICBjb25zdCBzdGFydCA9IHRoaXMubm93KCk7XG4gICAgbGV0IHByb2Nlc3NlZCA9IDA7XG4gICAgbGV0IGV4aGF1c3RlZCA9IGZhbHNlO1xuICAgIHdoaWxlIChwcm9jZXNzZWQgPCBzbmFwc2hvdCAmJiB0aGlzLmRlcHRoKCkgPiAwKSB7XG4gICAgICAvLyBCdWRnZXQgY2hlY2sgQUZURVIgdGhlIGZpcnN0IGl0ZW0g4oCUIGd1YXJhbnRlZWQgcHJvZ3Jlc3MgcGVyIGZsdXNoLlxuICAgICAgaWYgKHByb2Nlc3NlZCA+IDAgJiYgdGhpcy5ub3coKSAtIHN0YXJ0ID49IHRoaXMuZmx1c2hCdWRnZXRNcykge1xuICAgICAgICBleGhhdXN0ZWQgPSB0cnVlO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIHRoaXMucHJvY2Vzc05leHQoKTtcbiAgICAgIHByb2Nlc3NlZCArPSAxO1xuICAgIH1cbiAgICB0aGlzLnJlY29yZEZsdXNoKHRoaXMubm93KCkgLSBzdGFydCwgZXhoYXVzdGVkKTtcblxuICAgIC8vIEJhY2tsb2cgbGVmdCAoYnVkZ2V0IGN1dCwgb3IgbGlzdGVuZXJzIGVucXVldWVkIHBhc3QgdGhlIHNuYXBzaG90KTpcbiAgICAvLyBoYW5kIGl0IHRvIHRoZSBORVhUIGNoZWNrcG9pbnQg4oCUIG5ldmVyIHN0YXJ2ZSwgbmV2ZXIgc3Bpbi5cbiAgICBjb25zdCByZWFybWVkID0gdGhpcy5kZXB0aCgpID4gMDtcbiAgICBpZiAocmVhcm1lZCkgdGhpcy5hcm0oKTtcbiAgICB0aGlzLm9uRmx1c2hFbmQ/Lih7IHByb2Nlc3NlZCwgYnVkZ2V0RXhoYXVzdGVkOiBleGhhdXN0ZWQsIHJlYXJtZWQgfSk7XG4gIH1cblxuICBwcml2YXRlIHJlY29yZEZsdXNoKGVsYXBzZWRNczogbnVtYmVyLCBleGhhdXN0ZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmZsdXNoZXMgKz0gMTtcbiAgICB0aGlzLmxhc3RGbHVzaE1zID0gZWxhcHNlZE1zO1xuICAgIGlmIChleGhhdXN0ZWQpIHRoaXMuYnVkZ2V0RXhoYXVzdGVkQ291bnQgKz0gMTtcbiAgICBpZiAodGhpcy5zYW1wbGVzLmxlbmd0aCA8IEZMVVNIX1NBTVBMRV9XSU5ET1cpIHRoaXMuc2FtcGxlcy5wdXNoKGVsYXBzZWRNcyk7XG4gICAgZWxzZSB7XG4gICAgICB0aGlzLnNhbXBsZXNbdGhpcy5zYW1wbGVXcml0ZUlkeF0gPSBlbGFwc2VkTXM7XG4gICAgICB0aGlzLnNhbXBsZVdyaXRlSWR4ID0gKHRoaXMuc2FtcGxlV3JpdGVJZHggKyAxKSAlIEZMVVNIX1NBTVBMRV9XSU5ET1c7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBwOTVGbHVzaE1zKCk6IG51bWJlciB7XG4gICAgaWYgKHRoaXMuc2FtcGxlcy5sZW5ndGggPT09IDApIHJldHVybiAwO1xuICAgIGNvbnN0IHNvcnRlZCA9IFsuLi50aGlzLnNhbXBsZXNdLnNvcnQoKGEsIGIpID0+IGEgLSBiKTtcbiAgICByZXR1cm4gc29ydGVkW01hdGgubWluKHNvcnRlZC5sZW5ndGggLSAxLCBNYXRoLmZsb29yKHNvcnRlZC5sZW5ndGggKiAwLjk1KSldO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,22 @@
1
+ /* istanbul ignore file */
2
+ /**
3
+ * observer-queue/ — RFC-001 deferred observer delivery, Blocks 2–5.
4
+ *
5
+ * The pure "one beat behind" pipeline:
6
+ *
7
+ * producer ─► capture (Block 1, `capture/envelope`) ─► MergedQueue
8
+ * (Block 3, seq-stamped over a BoundedRing, Block 2) ─► FlushDriver
9
+ * (Block 4, armed-once microtask checkpoints, flushBudgetMs) ─►
10
+ * DeferredDispatcher (Block 5, isolated listeners + inflight + stats)
11
+ *
12
+ * INTERNAL MODULE — deliberately NOT exported from the public footprintjs
13
+ * barrels yet. The engine wiring + public surface land with Blocks 6–10
14
+ * (see docs/design/rfc-001-deferred-observers.md). Zero engine imports:
15
+ * this directory may import only `../capture/` and its own files.
16
+ */
17
+ export { capture, PAYLOAD_SUMMARY_MAX_DEPTH, PAYLOAD_SUMMARY_MAX_ENTRIES, PAYLOAD_SUMMARY_MAX_NODES, summarizePayload, } from '../capture/envelope.js';
18
+ export { DeferredDispatcher } from './deferredDispatcher.js';
19
+ export { FLUSH_SAMPLE_WINDOW, FlushDriver } from './flushDriver.js';
20
+ export { DEFAULT_MAX_QUEUE, MergedQueue } from './mergedQueue.js';
21
+ export { BoundedRing } from './ring.js';
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL29ic2VydmVyLXF1ZXVlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDBCQUEwQjtBQUMxQjs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQVlILE9BQU8sRUFDTCxPQUFPLEVBQ1AseUJBQXlCLEVBQ3pCLDJCQUEyQixFQUMzQix5QkFBeUIsRUFDekIsZ0JBQWdCLEdBQ2pCLE1BQU0sd0JBQXdCLENBQUM7QUFVaEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFN0QsT0FBTyxFQUFFLG1CQUFtQixFQUFFLFdBQVcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRXBFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVsRSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sV0FBVyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogaXN0YW5idWwgaWdub3JlIGZpbGUgKi9cbi8qKlxuICogb2JzZXJ2ZXItcXVldWUvIOKAlCBSRkMtMDAxIGRlZmVycmVkIG9ic2VydmVyIGRlbGl2ZXJ5LCBCbG9ja3MgMuKAkzUuXG4gKlxuICogVGhlIHB1cmUgXCJvbmUgYmVhdCBiZWhpbmRcIiBwaXBlbGluZTpcbiAqXG4gKiAgIHByb2R1Y2VyIOKUgOKWuiBjYXB0dXJlIChCbG9jayAxLCBgY2FwdHVyZS9lbnZlbG9wZWApIOKUgOKWuiBNZXJnZWRRdWV1ZVxuICogICAoQmxvY2sgMywgc2VxLXN0YW1wZWQgb3ZlciBhIEJvdW5kZWRSaW5nLCBCbG9jayAyKSDilIDilrogRmx1c2hEcml2ZXJcbiAqICAgKEJsb2NrIDQsIGFybWVkLW9uY2UgbWljcm90YXNrIGNoZWNrcG9pbnRzLCBmbHVzaEJ1ZGdldE1zKSDilIDilrpcbiAqICAgRGVmZXJyZWREaXNwYXRjaGVyIChCbG9jayA1LCBpc29sYXRlZCBsaXN0ZW5lcnMgKyBpbmZsaWdodCArIHN0YXRzKVxuICpcbiAqIElOVEVSTkFMIE1PRFVMRSDigJQgZGVsaWJlcmF0ZWx5IE5PVCBleHBvcnRlZCBmcm9tIHRoZSBwdWJsaWMgZm9vdHByaW50anNcbiAqIGJhcnJlbHMgeWV0LiBUaGUgZW5naW5lIHdpcmluZyArIHB1YmxpYyBzdXJmYWNlIGxhbmQgd2l0aCBCbG9ja3MgNuKAkzEwXG4gKiAoc2VlIGRvY3MvZGVzaWduL3JmYy0wMDEtZGVmZXJyZWQtb2JzZXJ2ZXJzLm1kKS4gWmVybyBlbmdpbmUgaW1wb3J0czpcbiAqIHRoaXMgZGlyZWN0b3J5IG1heSBpbXBvcnQgb25seSBgLi4vY2FwdHVyZS9gIGFuZCBpdHMgb3duIGZpbGVzLlxuICovXG5cbmV4cG9ydCB0eXBlIHtcbiAgQ2FwdHVyZUNoYW5uZWwsXG4gIENhcHR1cmVFbnZlbG9wZSxcbiAgQ2FwdHVyZUhvb2tzLFxuICBDYXB0dXJlUG9saWN5LFxuICBDYXB0dXJlUmVxdWVzdCxcbiAgUGF5bG9hZFN1bW1hcnksXG4gIFBheWxvYWRTdW1tYXJ5Tm9kZSxcbiAgUGF5bG9hZFN1bW1hcnlUeXBlLFxufSBmcm9tICcuLi9jYXB0dXJlL2VudmVsb3BlLmpzJztcbmV4cG9ydCB7XG4gIGNhcHR1cmUsXG4gIFBBWUxPQURfU1VNTUFSWV9NQVhfREVQVEgsXG4gIFBBWUxPQURfU1VNTUFSWV9NQVhfRU5UUklFUyxcbiAgUEFZTE9BRF9TVU1NQVJZX01BWF9OT0RFUyxcbiAgc3VtbWFyaXplUGF5bG9hZCxcbn0gZnJvbSAnLi4vY2FwdHVyZS9lbnZlbG9wZS5qcyc7XG5leHBvcnQgdHlwZSB7XG4gIERlZmVycmVkRGlzcGF0Y2hlck9wdGlvbnMsXG4gIERlZmVycmVkTGlzdGVuZXIsXG4gIERpc3BhdGNoRXJyb3JDb250ZXh0LFxuICBEaXNwYXRjaEVycm9ySGFuZGxlcixcbiAgRGlzcGF0Y2hlclN0YXRzLFxuICBEcmFpblJlc3VsdCxcbiAgTGlzdGVuZXJTdGF0cyxcbn0gZnJvbSAnLi9kZWZlcnJlZERpc3BhdGNoZXIuanMnO1xuZXhwb3J0IHsgRGVmZXJyZWREaXNwYXRjaGVyIH0gZnJvbSAnLi9kZWZlcnJlZERpc3BhdGNoZXIuanMnO1xuZXhwb3J0IHR5cGUgeyBGbHVzaERyaXZlck9wdGlvbnMsIEZsdXNoRHJpdmVyU3RhdHMsIEZsdXNoT3V0Y29tZSwgRmx1c2hTeW5jUmVzdWx0IH0gZnJvbSAnLi9mbHVzaERyaXZlci5qcyc7XG5leHBvcnQgeyBGTFVTSF9TQU1QTEVfV0lORE9XLCBGbHVzaERyaXZlciB9IGZyb20gJy4vZmx1c2hEcml2ZXIuanMnO1xuZXhwb3J0IHR5cGUgeyBFbnF1ZXVlSW5wdXQsIEVucXVldWVPdXRjb21lLCBFbnF1ZXVlUmVzdWx0LCBNZXJnZWRRdWV1ZU9wdGlvbnMgfSBmcm9tICcuL21lcmdlZFF1ZXVlLmpzJztcbmV4cG9ydCB7IERFRkFVTFRfTUFYX1FVRVVFLCBNZXJnZWRRdWV1ZSB9IGZyb20gJy4vbWVyZ2VkUXVldWUuanMnO1xuZXhwb3J0IHR5cGUgeyBPdmVyZmxvd1BvbGljeSwgUmluZ0NvdW50ZXJzLCBSaW5nT3B0aW9ucywgUmluZ1B1c2hSZXN1bHQgfSBmcm9tICcuL3JpbmcuanMnO1xuZXhwb3J0IHsgQm91bmRlZFJpbmcgfSBmcm9tICcuL3JpbmcuanMnO1xuIl19
@@ -0,0 +1,91 @@
1
+ /**
2
+ * observer-queue/mergedQueue.ts — RFC-001 Block 3: seq stamping + multi-channel merge.
3
+ *
4
+ * Pattern: Single totally-ordered staging queue. All three observer
5
+ * channels (`scope` / `flow` / `emit`) funnel through ONE queue;
6
+ * the `seq` counter is assigned at capture under the single JS
7
+ * thread, so drain order == arrival order ACROSS channels with no
8
+ * cross-queue merge logic ever needed.
9
+ * Role: Glue between the capture tier (Block 1) and the flush driver
10
+ * (Block 4). Pure module — imports only `capture/envelope` and
11
+ * the ring (Block 2); zero engine knowledge.
12
+ *
13
+ * Seq semantics (normative, RFC-001 §5):
14
+ * - Stamped BEFORE admission — an event that is then dropped (overflow)
15
+ * or refused (`'block'`) still consumed its seq. Drops therefore leave
16
+ * VISIBLE gaps in the delivered stream (honest loss accounting), and
17
+ * `'block'`-refused events delivered inline keep their true arrival
18
+ * stamp even though they overtake the queued backlog.
19
+ * - Monotonic, starts at 0, never reused for the lifetime of the queue.
20
+ *
21
+ * Enqueue outcomes:
22
+ * - `'queued'` — staged for the next flush (drop-oldest may have evicted
23
+ * an older event to make room; that loss is counted, never silent).
24
+ * - `'dropped'` — the event was sampled out at saturation. Lost; counted.
25
+ * - `'inline'` — `'block'` policy refused the enqueue. NOT lost: the
26
+ * caller (the dispatcher, Block 5) must deliver the returned envelope
27
+ * synchronously inline — blocking delivery by explicit consumer choice.
28
+ */
29
+ import { capture, } from '../capture/envelope.js';
30
+ import { BoundedRing } from './ring.js';
31
+ /** RFC-001 §5 default queue bound. */
32
+ export const DEFAULT_MAX_QUEUE = 10_000;
33
+ export class MergedQueue {
34
+ ring;
35
+ overflow;
36
+ defaultPolicy;
37
+ hooks;
38
+ /** Arrival stamp — monotonic across ALL channels (see module header). */
39
+ seq = 0;
40
+ constructor(opts) {
41
+ this.overflow = opts?.overflow ?? 'drop-oldest';
42
+ this.ring = new BoundedRing({
43
+ capacity: opts?.maxQueue ?? DEFAULT_MAX_QUEUE,
44
+ policy: this.overflow,
45
+ sampleEvery: opts?.sampleEvery,
46
+ });
47
+ this.defaultPolicy = opts?.capturePolicy ?? 'summary';
48
+ this.hooks = opts?.hooks;
49
+ }
50
+ /**
51
+ * Capture one event (seq-stamped at arrival) and stage it for deferred
52
+ * delivery. `policy` overrides the queue default per call — e.g. `'ref'`
53
+ * for payloads the caller proved immutable. Never throws.
54
+ */
55
+ enqueue(input, policy) {
56
+ const envelope = capture({
57
+ seq: this.seq,
58
+ channel: input.channel,
59
+ method: input.method,
60
+ runtimeStageId: input.runtimeStageId,
61
+ runId: input.runId,
62
+ payload: input.payload,
63
+ }, policy ?? this.defaultPolicy, this.hooks);
64
+ this.seq += 1;
65
+ const pushed = this.ring.push(envelope);
66
+ if (pushed.accepted)
67
+ return { envelope, outcome: 'queued' };
68
+ return { envelope, outcome: this.overflow === 'block' ? 'inline' : 'dropped' };
69
+ }
70
+ /** Pop the oldest staged envelope (total arrival order across channels). */
71
+ shift() {
72
+ return this.ring.shift();
73
+ }
74
+ /** Current backlog. */
75
+ get depth() {
76
+ return this.ring.size;
77
+ }
78
+ /** Ring capacity (the `maxQueue` bound). */
79
+ get capacity() {
80
+ return this.ring.capacity;
81
+ }
82
+ /** The next seq to be assigned == total events captured so far. */
83
+ get nextSeq() {
84
+ return this.seq;
85
+ }
86
+ /** Lifetime loss/delivery accounting — delegated to the ring. */
87
+ getCounters() {
88
+ return this.ring.getCounters();
89
+ }
90
+ }
91
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVyZ2VkUXVldWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL29ic2VydmVyLXF1ZXVlL21lcmdlZFF1ZXVlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyQkc7QUFFSCxPQUFPLEVBS0wsT0FBTyxHQUNSLE1BQU0sd0JBQXdCLENBQUM7QUFDaEMsT0FBTyxFQUEwQyxXQUFXLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFaEYsc0NBQXNDO0FBQ3RDLE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLE1BQU0sQ0FBQztBQWtDeEMsTUFBTSxPQUFPLFdBQVc7SUFDTCxJQUFJLENBQStCO0lBQ25DLFFBQVEsQ0FBaUI7SUFDekIsYUFBYSxDQUFnQjtJQUM3QixLQUFLLENBQWdCO0lBQ3RDLHlFQUF5RTtJQUNqRSxHQUFHLEdBQUcsQ0FBQyxDQUFDO0lBRWhCLFlBQVksSUFBeUI7UUFDbkMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLEVBQUUsUUFBUSxJQUFJLGFBQWEsQ0FBQztRQUNoRCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksV0FBVyxDQUFrQjtZQUMzQyxRQUFRLEVBQUUsSUFBSSxFQUFFLFFBQVEsSUFBSSxpQkFBaUI7WUFDN0MsTUFBTSxFQUFFLElBQUksQ0FBQyxRQUFRO1lBQ3JCLFdBQVcsRUFBRSxJQUFJLEVBQUUsV0FBVztTQUMvQixDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksRUFBRSxhQUFhLElBQUksU0FBUyxDQUFDO1FBQ3RELElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxFQUFFLEtBQUssQ0FBQztJQUMzQixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE9BQU8sQ0FBQyxLQUFtQixFQUFFLE1BQXNCO1FBQ2pELE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FDdEI7WUFDRSxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUc7WUFDYixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87WUFDdEIsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO1lBQ3BCLGNBQWMsRUFBRSxLQUFLLENBQUMsY0FBYztZQUNwQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUs7WUFDbEIsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO1NBQ3ZCLEVBQ0QsTUFBTSxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQzVCLElBQUksQ0FBQyxLQUFLLENBQ1gsQ0FBQztRQUNGLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO1FBRWQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDeEMsSUFBSSxNQUFNLENBQUMsUUFBUTtZQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxDQUFDO1FBQzVELE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxRQUFRLEtBQUssT0FBTyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDO0lBQ2pGLENBQUM7SUFFRCw0RUFBNEU7SUFDNUUsS0FBSztRQUNILE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQsdUJBQXVCO0lBQ3ZCLElBQUksS0FBSztRQUNQLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDeEIsQ0FBQztJQUVELDRDQUE0QztJQUM1QyxJQUFJLFFBQVE7UUFDVixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQzVCLENBQUM7SUFFRCxtRUFBbUU7SUFDbkUsSUFBSSxPQUFPO1FBQ1QsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ2xCLENBQUM7SUFFRCxpRUFBaUU7SUFDakUsV0FBVztRQUNULE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIG9ic2VydmVyLXF1ZXVlL21lcmdlZFF1ZXVlLnRzIOKAlCBSRkMtMDAxIEJsb2NrIDM6IHNlcSBzdGFtcGluZyArIG11bHRpLWNoYW5uZWwgbWVyZ2UuXG4gKlxuICogUGF0dGVybjogIFNpbmdsZSB0b3RhbGx5LW9yZGVyZWQgc3RhZ2luZyBxdWV1ZS4gQWxsIHRocmVlIG9ic2VydmVyXG4gKiAgICAgICAgICAgY2hhbm5lbHMgKGBzY29wZWAgLyBgZmxvd2AgLyBgZW1pdGApIGZ1bm5lbCB0aHJvdWdoIE9ORSBxdWV1ZTtcbiAqICAgICAgICAgICB0aGUgYHNlcWAgY291bnRlciBpcyBhc3NpZ25lZCBhdCBjYXB0dXJlIHVuZGVyIHRoZSBzaW5nbGUgSlNcbiAqICAgICAgICAgICB0aHJlYWQsIHNvIGRyYWluIG9yZGVyID09IGFycml2YWwgb3JkZXIgQUNST1NTIGNoYW5uZWxzIHdpdGggbm9cbiAqICAgICAgICAgICBjcm9zcy1xdWV1ZSBtZXJnZSBsb2dpYyBldmVyIG5lZWRlZC5cbiAqIFJvbGU6ICAgICBHbHVlIGJldHdlZW4gdGhlIGNhcHR1cmUgdGllciAoQmxvY2sgMSkgYW5kIHRoZSBmbHVzaCBkcml2ZXJcbiAqICAgICAgICAgICAoQmxvY2sgNCkuIFB1cmUgbW9kdWxlIOKAlCBpbXBvcnRzIG9ubHkgYGNhcHR1cmUvZW52ZWxvcGVgIGFuZFxuICogICAgICAgICAgIHRoZSByaW5nIChCbG9jayAyKTsgemVybyBlbmdpbmUga25vd2xlZGdlLlxuICpcbiAqIFNlcSBzZW1hbnRpY3MgKG5vcm1hdGl2ZSwgUkZDLTAwMSDCpzUpOlxuICogICAtIFN0YW1wZWQgQkVGT1JFIGFkbWlzc2lvbiDigJQgYW4gZXZlbnQgdGhhdCBpcyB0aGVuIGRyb3BwZWQgKG92ZXJmbG93KVxuICogICAgIG9yIHJlZnVzZWQgKGAnYmxvY2snYCkgc3RpbGwgY29uc3VtZWQgaXRzIHNlcS4gRHJvcHMgdGhlcmVmb3JlIGxlYXZlXG4gKiAgICAgVklTSUJMRSBnYXBzIGluIHRoZSBkZWxpdmVyZWQgc3RyZWFtIChob25lc3QgbG9zcyBhY2NvdW50aW5nKSwgYW5kXG4gKiAgICAgYCdibG9jaydgLXJlZnVzZWQgZXZlbnRzIGRlbGl2ZXJlZCBpbmxpbmUga2VlcCB0aGVpciB0cnVlIGFycml2YWxcbiAqICAgICBzdGFtcCBldmVuIHRob3VnaCB0aGV5IG92ZXJ0YWtlIHRoZSBxdWV1ZWQgYmFja2xvZy5cbiAqICAgLSBNb25vdG9uaWMsIHN0YXJ0cyBhdCAwLCBuZXZlciByZXVzZWQgZm9yIHRoZSBsaWZldGltZSBvZiB0aGUgcXVldWUuXG4gKlxuICogRW5xdWV1ZSBvdXRjb21lczpcbiAqICAgLSBgJ3F1ZXVlZCdgICDigJQgc3RhZ2VkIGZvciB0aGUgbmV4dCBmbHVzaCAoZHJvcC1vbGRlc3QgbWF5IGhhdmUgZXZpY3RlZFxuICogICAgIGFuIG9sZGVyIGV2ZW50IHRvIG1ha2Ugcm9vbTsgdGhhdCBsb3NzIGlzIGNvdW50ZWQsIG5ldmVyIHNpbGVudCkuXG4gKiAgIC0gYCdkcm9wcGVkJ2Ag4oCUIHRoZSBldmVudCB3YXMgc2FtcGxlZCBvdXQgYXQgc2F0dXJhdGlvbi4gTG9zdDsgY291bnRlZC5cbiAqICAgLSBgJ2lubGluZSdgICDigJQgYCdibG9jaydgIHBvbGljeSByZWZ1c2VkIHRoZSBlbnF1ZXVlLiBOT1QgbG9zdDogdGhlXG4gKiAgICAgY2FsbGVyICh0aGUgZGlzcGF0Y2hlciwgQmxvY2sgNSkgbXVzdCBkZWxpdmVyIHRoZSByZXR1cm5lZCBlbnZlbG9wZVxuICogICAgIHN5bmNocm9ub3VzbHkgaW5saW5lIOKAlCBibG9ja2luZyBkZWxpdmVyeSBieSBleHBsaWNpdCBjb25zdW1lciBjaG9pY2UuXG4gKi9cblxuaW1wb3J0IHtcbiAgdHlwZSBDYXB0dXJlQ2hhbm5lbCxcbiAgdHlwZSBDYXB0dXJlRW52ZWxvcGUsXG4gIHR5cGUgQ2FwdHVyZUhvb2tzLFxuICB0eXBlIENhcHR1cmVQb2xpY3ksXG4gIGNhcHR1cmUsXG59IGZyb20gJy4uL2NhcHR1cmUvZW52ZWxvcGUuanMnO1xuaW1wb3J0IHsgdHlwZSBPdmVyZmxvd1BvbGljeSwgdHlwZSBSaW5nQ291bnRlcnMsIEJvdW5kZWRSaW5nIH0gZnJvbSAnLi9yaW5nLmpzJztcblxuLyoqIFJGQy0wMDEgwqc1IGRlZmF1bHQgcXVldWUgYm91bmQuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9NQVhfUVVFVUUgPSAxMF8wMDA7XG5cbi8qKiBPbmUgb2JzZXJ2ZXIgZXZlbnQgdG8gbWVyZ2Ug4oCUIHtAbGluayBjYXB0dXJlfSdzIHJlcXVlc3QgbWludXMgYHNlcWAuICovXG5leHBvcnQgaW50ZXJmYWNlIEVucXVldWVJbnB1dCB7XG4gIHJlYWRvbmx5IGNoYW5uZWw6IENhcHR1cmVDaGFubmVsO1xuICByZWFkb25seSBtZXRob2Q6IHN0cmluZztcbiAgcmVhZG9ubHkgcnVudGltZVN0YWdlSWQ6IHN0cmluZztcbiAgcmVhZG9ubHkgcnVuSWQ6IHN0cmluZztcbiAgLyoqIExJVkUgcGF5bG9hZCDigJQgbWF0ZXJpYWxpemVkIHBlciBjYXB0dXJlIHBvbGljeSBhdCBlbnF1ZXVlIHRpbWUuICovXG4gIHJlYWRvbmx5IHBheWxvYWQ6IHVua25vd247XG59XG5cbi8qKiBGYXRlIG9mIG9uZSBlbnF1ZXVlZCBldmVudCDigJQgc2VlIHRoZSBtb2R1bGUgaGVhZGVyLiAqL1xuZXhwb3J0IHR5cGUgRW5xdWV1ZU91dGNvbWUgPSAncXVldWVkJyB8ICdkcm9wcGVkJyB8ICdpbmxpbmUnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEVucXVldWVSZXN1bHQge1xuICAvKiogVGhlIGNhcHR1cmVkLCBzZXEtc3RhbXBlZCBlbnZlbG9wZSAoYnVpbHQgZXZlbiB3aGVuIG5vdCBxdWV1ZWQpLiAqL1xuICByZWFkb25seSBlbnZlbG9wZTogQ2FwdHVyZUVudmVsb3BlO1xuICByZWFkb25seSBvdXRjb21lOiBFbnF1ZXVlT3V0Y29tZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNZXJnZWRRdWV1ZU9wdGlvbnMge1xuICAvKiogUmluZyBjYXBhY2l0eS4gRGVmYXVsdCB7QGxpbmsgREVGQVVMVF9NQVhfUVVFVUV9ICgxMCAwMDApLiAqL1xuICByZWFkb25seSBtYXhRdWV1ZT86IG51bWJlcjtcbiAgLyoqIE92ZXJmbG93IHBvbGljeSBhdCBjYXBhY2l0eS4gRGVmYXVsdCBgJ2Ryb3Atb2xkZXN0J2AuICovXG4gIHJlYWRvbmx5IG92ZXJmbG93PzogT3ZlcmZsb3dQb2xpY3k7XG4gIC8qKiBgJ3NhbXBsZSdgIG9ubHkg4oCUIGFkbWl0IDEgaW4gdGhpcyBtYW55IHNhdHVyYXRlZCBhcnJpdmFscy4gKi9cbiAgcmVhZG9ubHkgc2FtcGxlRXZlcnk/OiBudW1iZXI7XG4gIC8qKiBEZWZhdWx0IGNhcHR1cmUgcG9saWN5IHdoZW4gYGVucXVldWVgIGdldHMgbm9uZS4gRGVmYXVsdCBgJ3N1bW1hcnknYC4gKi9cbiAgcmVhZG9ubHkgY2FwdHVyZVBvbGljeT86IENhcHR1cmVQb2xpY3k7XG4gIC8qKiBFbmdpbmUtZnJlZSBzZWFtcyAoZGV2LXdhcm4sIGNsb2NrKSBwYXNzZWQgdGhyb3VnaCB0byB7QGxpbmsgY2FwdHVyZX0uICovXG4gIHJlYWRvbmx5IGhvb2tzPzogQ2FwdHVyZUhvb2tzO1xufVxuXG5leHBvcnQgY2xhc3MgTWVyZ2VkUXVldWUge1xuICBwcml2YXRlIHJlYWRvbmx5IHJpbmc6IEJvdW5kZWRSaW5nPENhcHR1cmVFbnZlbG9wZT47XG4gIHByaXZhdGUgcmVhZG9ubHkgb3ZlcmZsb3c6IE92ZXJmbG93UG9saWN5O1xuICBwcml2YXRlIHJlYWRvbmx5IGRlZmF1bHRQb2xpY3k6IENhcHR1cmVQb2xpY3k7XG4gIHByaXZhdGUgcmVhZG9ubHkgaG9va3M/OiBDYXB0dXJlSG9va3M7XG4gIC8qKiBBcnJpdmFsIHN0YW1wIOKAlCBtb25vdG9uaWMgYWNyb3NzIEFMTCBjaGFubmVscyAoc2VlIG1vZHVsZSBoZWFkZXIpLiAqL1xuICBwcml2YXRlIHNlcSA9IDA7XG5cbiAgY29uc3RydWN0b3Iob3B0cz86IE1lcmdlZFF1ZXVlT3B0aW9ucykge1xuICAgIHRoaXMub3ZlcmZsb3cgPSBvcHRzPy5vdmVyZmxvdyA/PyAnZHJvcC1vbGRlc3QnO1xuICAgIHRoaXMucmluZyA9IG5ldyBCb3VuZGVkUmluZzxDYXB0dXJlRW52ZWxvcGU+KHtcbiAgICAgIGNhcGFjaXR5OiBvcHRzPy5tYXhRdWV1ZSA/PyBERUZBVUxUX01BWF9RVUVVRSxcbiAgICAgIHBvbGljeTogdGhpcy5vdmVyZmxvdyxcbiAgICAgIHNhbXBsZUV2ZXJ5OiBvcHRzPy5zYW1wbGVFdmVyeSxcbiAgICB9KTtcbiAgICB0aGlzLmRlZmF1bHRQb2xpY3kgPSBvcHRzPy5jYXB0dXJlUG9saWN5ID8/ICdzdW1tYXJ5JztcbiAgICB0aGlzLmhvb2tzID0gb3B0cz8uaG9va3M7XG4gIH1cblxuICAvKipcbiAgICogQ2FwdHVyZSBvbmUgZXZlbnQgKHNlcS1zdGFtcGVkIGF0IGFycml2YWwpIGFuZCBzdGFnZSBpdCBmb3IgZGVmZXJyZWRcbiAgICogZGVsaXZlcnkuIGBwb2xpY3lgIG92ZXJyaWRlcyB0aGUgcXVldWUgZGVmYXVsdCBwZXIgY2FsbCDigJQgZS5nLiBgJ3JlZidgXG4gICAqIGZvciBwYXlsb2FkcyB0aGUgY2FsbGVyIHByb3ZlZCBpbW11dGFibGUuIE5ldmVyIHRocm93cy5cbiAgICovXG4gIGVucXVldWUoaW5wdXQ6IEVucXVldWVJbnB1dCwgcG9saWN5PzogQ2FwdHVyZVBvbGljeSk6IEVucXVldWVSZXN1bHQge1xuICAgIGNvbnN0IGVudmVsb3BlID0gY2FwdHVyZShcbiAgICAgIHtcbiAgICAgICAgc2VxOiB0aGlzLnNlcSxcbiAgICAgICAgY2hhbm5lbDogaW5wdXQuY2hhbm5lbCxcbiAgICAgICAgbWV0aG9kOiBpbnB1dC5tZXRob2QsXG4gICAgICAgIHJ1bnRpbWVTdGFnZUlkOiBpbnB1dC5ydW50aW1lU3RhZ2VJZCxcbiAgICAgICAgcnVuSWQ6IGlucHV0LnJ1bklkLFxuICAgICAgICBwYXlsb2FkOiBpbnB1dC5wYXlsb2FkLFxuICAgICAgfSxcbiAgICAgIHBvbGljeSA/PyB0aGlzLmRlZmF1bHRQb2xpY3ksXG4gICAgICB0aGlzLmhvb2tzLFxuICAgICk7XG4gICAgdGhpcy5zZXEgKz0gMTtcblxuICAgIGNvbnN0IHB1c2hlZCA9IHRoaXMucmluZy5wdXNoKGVudmVsb3BlKTtcbiAgICBpZiAocHVzaGVkLmFjY2VwdGVkKSByZXR1cm4geyBlbnZlbG9wZSwgb3V0Y29tZTogJ3F1ZXVlZCcgfTtcbiAgICByZXR1cm4geyBlbnZlbG9wZSwgb3V0Y29tZTogdGhpcy5vdmVyZmxvdyA9PT0gJ2Jsb2NrJyA/ICdpbmxpbmUnIDogJ2Ryb3BwZWQnIH07XG4gIH1cblxuICAvKiogUG9wIHRoZSBvbGRlc3Qgc3RhZ2VkIGVudmVsb3BlICh0b3RhbCBhcnJpdmFsIG9yZGVyIGFjcm9zcyBjaGFubmVscykuICovXG4gIHNoaWZ0KCk6IENhcHR1cmVFbnZlbG9wZSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMucmluZy5zaGlmdCgpO1xuICB9XG5cbiAgLyoqIEN1cnJlbnQgYmFja2xvZy4gKi9cbiAgZ2V0IGRlcHRoKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmluZy5zaXplO1xuICB9XG5cbiAgLyoqIFJpbmcgY2FwYWNpdHkgKHRoZSBgbWF4UXVldWVgIGJvdW5kKS4gKi9cbiAgZ2V0IGNhcGFjaXR5KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmluZy5jYXBhY2l0eTtcbiAgfVxuXG4gIC8qKiBUaGUgbmV4dCBzZXEgdG8gYmUgYXNzaWduZWQgPT0gdG90YWwgZXZlbnRzIGNhcHR1cmVkIHNvIGZhci4gKi9cbiAgZ2V0IG5leHRTZXEoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5zZXE7XG4gIH1cblxuICAvKiogTGlmZXRpbWUgbG9zcy9kZWxpdmVyeSBhY2NvdW50aW5nIOKAlCBkZWxlZ2F0ZWQgdG8gdGhlIHJpbmcuICovXG4gIGdldENvdW50ZXJzKCk6IFJpbmdDb3VudGVycyB7XG4gICAgcmV0dXJuIHRoaXMucmluZy5nZXRDb3VudGVycygpO1xuICB9XG59XG4iXX0=