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