footprintjs 6.1.2 → 7.0.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 (45) hide show
  1. package/CLAUDE.md +31 -26
  2. package/README.md +1 -1
  3. package/dist/advanced.js +2 -6
  4. package/dist/esm/advanced.js +1 -3
  5. package/dist/esm/lib/builder/structure/StructureRecorder.js +2 -2
  6. package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +59 -24
  7. package/dist/esm/lib/recorder/InOutRecorder.js +31 -15
  8. package/dist/esm/lib/recorder/QualityRecorder.js +40 -13
  9. package/dist/esm/lib/recorder/RecorderOperation.js +3 -3
  10. package/dist/esm/lib/recorder/index.js +1 -8
  11. package/dist/esm/lib/recorder/qualityTrace.js +1 -1
  12. package/dist/esm/lib/runner/ExecutionRuntime.js +1 -1
  13. package/dist/esm/lib/scope/recorders/MetricRecorder.js +37 -9
  14. package/dist/esm/trace.js +1 -12
  15. package/dist/lib/builder/structure/StructureRecorder.js +2 -2
  16. package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +59 -24
  17. package/dist/lib/recorder/InOutRecorder.js +31 -15
  18. package/dist/lib/recorder/QualityRecorder.js +40 -13
  19. package/dist/lib/recorder/RecorderOperation.js +3 -3
  20. package/dist/lib/recorder/index.js +2 -12
  21. package/dist/lib/recorder/qualityTrace.js +1 -1
  22. package/dist/lib/runner/ExecutionRuntime.js +1 -1
  23. package/dist/lib/scope/recorders/MetricRecorder.js +37 -9
  24. package/dist/trace.js +2 -16
  25. package/dist/types/advanced.d.ts +0 -2
  26. package/dist/types/lib/builder/structure/StructureRecorder.d.ts +1 -1
  27. package/dist/types/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +26 -5
  28. package/dist/types/lib/recorder/InOutRecorder.d.ts +17 -6
  29. package/dist/types/lib/recorder/QualityRecorder.d.ts +17 -3
  30. package/dist/types/lib/recorder/RecorderOperation.d.ts +2 -2
  31. package/dist/types/lib/recorder/index.d.ts +0 -3
  32. package/dist/types/lib/recorder/qualityTrace.d.ts +5 -2
  33. package/dist/types/lib/runner/ExecutionRuntime.d.ts +1 -1
  34. package/dist/types/lib/scope/recorders/MetricRecorder.d.ts +18 -3
  35. package/dist/types/trace.d.ts +0 -3
  36. package/package.json +1 -1
  37. package/dist/esm/lib/recorder/BoundaryStateTracker.js +0 -260
  38. package/dist/esm/lib/recorder/KeyedRecorder.js +0 -94
  39. package/dist/esm/lib/recorder/SequenceRecorder.js +0 -193
  40. package/dist/lib/recorder/BoundaryStateTracker.js +0 -264
  41. package/dist/lib/recorder/KeyedRecorder.js +0 -98
  42. package/dist/lib/recorder/SequenceRecorder.js +0 -197
  43. package/dist/types/lib/recorder/BoundaryStateTracker.d.ts +0 -212
  44. package/dist/types/lib/recorder/KeyedRecorder.d.ts +0 -56
  45. package/dist/types/lib/recorder/SequenceRecorder.d.ts +0 -112
@@ -1,264 +0,0 @@
1
- "use strict";
2
- /**
3
- * BoundaryStateTracker<TState> — third storage primitive on the recorder
4
- * shelf, alongside `SequenceRecorder<T>` and `KeyedRecorder<T>`.
5
- *
6
- * **Mental model — observers vs. bookkeepers:**
7
- *
8
- * `ScopeRecorder` / `FlowRecorder` / `EmitRecorder` / `CombinedRecorder`
9
- * are OBSERVER interfaces — they describe how a recorder hears
10
- * events from the executor.
11
- *
12
- * `SequenceRecorder<T>` / `KeyedRecorder<T>` / `BoundaryStateTracker<TState>`
13
- * are STORAGE primitives — three different bookkeeping shelves with
14
- * different durability and indexing properties. A real recorder
15
- * class typically picks ONE observer interface AND ONE storage
16
- * shelf, combining them via `extends + implements`.
17
- *
18
- * **What this primitive answers:** "At any moment during the run, what
19
- * is the LIVE transient state of every currently-active boundary?"
20
- *
21
- * A "boundary" is a matched event pair `[start, stop]` bracketing an
22
- * interval — for example, `(llm_start, llm_end)` for an LLM call,
23
- * `(tool_start, tool_end)` for tool execution, `(turn_start, turn_end)`
24
- * for an agent turn. Between the brackets, intermediate events evolve
25
- * the boundary's state (token chunks accumulating into a partial
26
- * answer, args streaming in, etc.). On `stop`, the state clears.
27
- *
28
- * Algorithmically this is the **DFS bracket-sequence pattern** —
29
- * stack-frame state during a graph-traversal interval. Same shape used
30
- * by Tarjan's SCC algorithm, tree decomposition, and push-down
31
- * automata. The `active` map is the open-brackets stack at any moment.
32
- *
33
- * **Comparison with the other storage primitives:**
34
- *
35
- * | Primitive | Stores | Time scope | Memory |
36
- * |---------------------------------|--------------------------------------|---------------------|-------------|
37
- * | `SequenceRecorder<T>` | append-only ordered + keyed entries | durable across run | O(N events) |
38
- * | `KeyedRecorder<T>` | 1:1 entry per `runtimeStageId` | durable across run | O(N steps) |
39
- * | `BoundaryStateTracker<TState>` | transient bracket-scoped state | live; clears on stop | O(K active) |
40
- *
41
- * **When to pick which:**
42
- *
43
- * - "I need to keep a permanent log of every event for time-travel"
44
- * → `SequenceRecorder<T>`
45
- * - "I want one durable record per stage execution (e.g., metrics)"
46
- * → `KeyedRecorder<T>`
47
- * - "I need to know what's happening RIGHT NOW inside an in-flight
48
- * boundary (e.g., partial LLM stream, partial tool args)"
49
- * → `BoundaryStateTracker<TState>` (this class)
50
- *
51
- * **What this is NOT for:**
52
- *
53
- * - Time-travel queries ("what was the state at past slider step N?")
54
- * — transient state clears on stop. For time-travel, snapshot the
55
- * state at each emit into a separate `SequenceRecorder<TState>`,
56
- * or wait for a future `BoundarySnapshotRecorder<TState>` primitive.
57
- *
58
- * - Aggregations across the whole run (totals, counts) — those are
59
- * `SequenceRecorder.aggregate()` / `KeyedRecorder.aggregate()`.
60
- *
61
- * - Stage-level concerns — those use `ScopeRecorder.onStageStart` /
62
- * `ScopeRecorder.onStageEnd`. This primitive operates at finer
63
- * granularity (events emitted DURING a stage execution).
64
- *
65
- * **Lifecycle contract — STRICT:**
66
- *
67
- * Every `startBoundary(key, ...)` call MUST be paired with a
68
- * `stopBoundary(key)` call. Failure to wire the stop side produces a
69
- * memory leak: the active map grows without bound, and `getAllActive()`
70
- * returns stale entries that look in-flight but aren't. Common cause:
71
- * subclass wires `start` to one event handler and forgets to wire
72
- * `stop`. **Always wire both at the same time.**
73
- *
74
- * Dev mode (`enableDevMode()`) detects leaks at `clear()` time —
75
- * warning includes the leaked keys so you can find the missing wiring.
76
- *
77
- * **Concurrency / nesting:**
78
- *
79
- * - Concurrent boundaries (parallel branches with two LLM calls
80
- * active at once) work correctly: each is keyed independently in
81
- * the active map.
82
- * - Nested boundaries of DIFFERENT KINDS (Agent boundary contains
83
- * LLM boundary) require SEPARATE tracker instances — one per kind.
84
- * The base class tracks one boundary kind per instance.
85
- *
86
- * **Key convention:**
87
- *
88
- * The `key: string` is whatever your subclass picks. Convention:
89
- * use `runtimeStageId` when the boundary maps 1:1 to a stage
90
- * execution — this gives free interop with `SequenceRecorder
91
- * .getEntriesForStep`, `KeyedRecorder.getByKey`, `findCommit` /
92
- * `findLastWriter`, and the rest of the trace ecosystem. Use a more
93
- * granular key (e.g., `toolCallId`) only when there are multiple
94
- * concurrent boundaries WITHIN one stage execution.
95
- *
96
- * @example Build a live LLM tracker (combining storage + observer):
97
- *
98
- * ```typescript
99
- * import { BoundaryStateTracker } from 'footprintjs/trace';
100
- * import { type CombinedRecorder, type EmitEvent } from 'footprintjs';
101
- *
102
- * interface LLMLiveState {
103
- * readonly partial: string;
104
- * readonly tokens: number;
105
- * }
106
- *
107
- * class LiveLLMTracker
108
- * extends BoundaryStateTracker<LLMLiveState> // STORAGE shelf
109
- * implements CombinedRecorder // OBSERVER interface
110
- * {
111
- * readonly id = 'live-llm';
112
- *
113
- * // Observer half — translate events into bracket mutations.
114
- * onEmit(event: EmitEvent): void {
115
- * if (event.name === 'agentfootprint.stream.llm_start') {
116
- * this.startBoundary(event.runtimeStageId, { partial: '', tokens: 0 });
117
- * } else if (event.name === 'agentfootprint.stream.llm_end') {
118
- * this.stopBoundary(event.runtimeStageId);
119
- * } else if (event.name === 'agentfootprint.stream.token') {
120
- * this.updateBoundary(event.runtimeStageId, (s) => ({
121
- * partial: s.partial + (event.payload as { content: string }).content,
122
- * tokens: s.tokens + 1,
123
- * }));
124
- * }
125
- * }
126
- *
127
- * // Public read API — O(1) at any moment.
128
- * isInFlight(): boolean { return this.hasActive; }
129
- * getPartial(stageId: string): string {
130
- * return this.getActive(stageId)?.partial ?? '';
131
- * }
132
- * }
133
- *
134
- * // Attached the same way as any other CombinedRecorder.
135
- * const tracker = new LiveLLMTracker();
136
- * executor.attachCombinedRecorder(tracker);
137
- * await executor.run({ input });
138
- *
139
- * // Read live state at any time during or after the run.
140
- * tracker.isInFlight();
141
- * tracker.getPartial(rid);
142
- * ```
143
- */
144
- Object.defineProperty(exports, "__esModule", { value: true });
145
- exports.BoundaryStateTracker = void 0;
146
- const detectCircular_js_1 = require("../scope/detectCircular.js");
147
- class BoundaryStateTracker {
148
- /** Open-brackets stack: key → current transient state. */
149
- active = new Map();
150
- /** Per-key count of `updateBoundary` calls that landed without a
151
- * matching active boundary. Drives rate-limited dev-mode warnings
152
- * so a stuck loop doesn't spam the console. */
153
- missedUpdates = new Map();
154
- // ── Mutator API (subclass calls these from observer hooks) ──────────
155
- /**
156
- * Open a new boundary with initial transient state.
157
- *
158
- * If a boundary with the same `key` is already active, the prior
159
- * state is overwritten (last-writer-wins). In dev mode, a warning
160
- * is logged because re-starting an active key usually indicates a
161
- * missed `stopBoundary` call upstream.
162
- *
163
- * @param key Boundary identifier — by convention, `runtimeStageId`
164
- * for 1:1-with-stage boundaries, or a more granular id
165
- * (e.g., `toolCallId`) when multiple concurrent boundaries
166
- * run within one stage execution.
167
- * @param initial Initial state — typed by `TState`.
168
- */
169
- startBoundary(key, initial) {
170
- if (this.active.has(key) && (0, detectCircular_js_1.isDevMode)()) {
171
- console.warn(`[${this.id}] startBoundary('${key}') called while an active boundary already exists. ` +
172
- 'Overwriting prior state — likely a missed stopBoundary upstream.');
173
- }
174
- this.active.set(key, initial);
175
- }
176
- /**
177
- * Evolve the transient state of an active boundary using an updater
178
- * function. Silent no-op if no boundary is active for `key`
179
- * (defensive against out-of-order events). In dev mode, a rate-limited
180
- * warning is logged on the 1st, 10th, and 100th missed update per key.
181
- *
182
- * @param key Boundary identifier (must match a prior `startBoundary`).
183
- * @param updater Pure function: previous state → next state.
184
- */
185
- updateBoundary(key, updater) {
186
- const cur = this.active.get(key);
187
- if (cur === undefined) {
188
- if ((0, detectCircular_js_1.isDevMode)()) {
189
- const n = (this.missedUpdates.get(key) ?? 0) + 1;
190
- this.missedUpdates.set(key, n);
191
- if (n === 1) {
192
- console.warn(`[${this.id}] updateBoundary('${key}') — no active boundary. Update dropped.`);
193
- }
194
- else if (n === 10 || n === 100) {
195
- console.warn(`[${this.id}] updateBoundary('${key}') — ${n} dropped updates. Wiring bug?`);
196
- }
197
- }
198
- return;
199
- }
200
- this.active.set(key, updater(cur));
201
- }
202
- /**
203
- * Close the boundary identified by `key` and return its FINAL
204
- * transient state (for any cleanup the subclass wants — e.g., emit a
205
- * snapshot to a SequenceRecorder for durable storage).
206
- *
207
- * @param key Boundary identifier.
208
- * @returns The final state, or `undefined` if no boundary was active.
209
- */
210
- stopBoundary(key) {
211
- const final = this.active.get(key);
212
- this.active.delete(key);
213
- return final;
214
- }
215
- // ── Read API (consumers call these — O(1)) ─────────────────────────
216
- /** Current transient state of ONE active boundary. `undefined` if no
217
- * boundary is active for `key`. */
218
- getActive(key) {
219
- return this.active.get(key);
220
- }
221
- /**
222
- * All currently-active boundaries.
223
- *
224
- * **Type-only readonly:** the returned reference IS the internal Map.
225
- * TypeScript prevents mutation through the `ReadonlyMap` type, but a
226
- * runtime cast or non-TS consumer can mutate it and corrupt internal
227
- * state. **Do not mutate.**
228
- */
229
- getAllActive() {
230
- return this.active;
231
- }
232
- /** True if any boundary is currently active. O(1). */
233
- get hasActive() {
234
- return this.active.size > 0;
235
- }
236
- /** Number of currently-active boundaries. O(1). */
237
- get activeCount() {
238
- return this.active.size;
239
- }
240
- // ── Lifecycle ───────────────────────────────────────────────────────
241
- /**
242
- * Reset all transient state. Called by executors before each `run()`
243
- * so consumers get a clean slate per run — same lifecycle contract
244
- * as `SequenceRecorder.clear()`.
245
- *
246
- * In dev mode, warns if any boundaries are still active when called
247
- * — likely indicates a missed `stopBoundary` upstream. The leaked
248
- * keys are listed (truncated to 10) so the wiring bug is findable.
249
- */
250
- clear() {
251
- if (this.active.size > 0 && (0, detectCircular_js_1.isDevMode)()) {
252
- const keys = [...this.active.keys()];
253
- const head = keys.slice(0, 10).join(', ');
254
- const more = keys.length > 10 ? ` ...(+${keys.length - 10} more)` : '';
255
- console.warn(`[${this.id}] clear() called with ${this.active.size} ` +
256
- 'still-active boundaries. Missed stopBoundary? ' +
257
- `Leaked keys: ${head}${more}`);
258
- }
259
- this.active.clear();
260
- this.missedUpdates.clear();
261
- }
262
- }
263
- exports.BoundaryStateTracker = BoundaryStateTracker;
264
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQm91bmRhcnlTdGF0ZVRyYWNrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3JlY29yZGVyL0JvdW5kYXJ5U3RhdGVUcmFja2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNklHOzs7QUFFSCxrRUFBdUQ7QUFFdkQsTUFBc0Isb0JBQW9CO0lBSXhDLDBEQUEwRDtJQUN6QyxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7SUFFcEQ7O29EQUVnRDtJQUMvQixhQUFhLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7SUFFM0QsdUVBQXVFO0lBRXZFOzs7Ozs7Ozs7Ozs7O09BYUc7SUFDTyxhQUFhLENBQUMsR0FBVyxFQUFFLE9BQWU7UUFDbEQsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFBLDZCQUFTLEdBQUUsRUFBRSxDQUFDO1lBQ3hDLE9BQU8sQ0FBQyxJQUFJLENBQ1YsSUFBSSxJQUFJLENBQUMsRUFBRSxvQkFBb0IsR0FBRyxxREFBcUQ7Z0JBQ3JGLGtFQUFrRSxDQUNyRSxDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDTyxjQUFjLENBQUMsR0FBVyxFQUFFLE9BQWlDO1FBQ3JFLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2pDLElBQUksR0FBRyxLQUFLLFNBQVMsRUFBRSxD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ZW50IjpbIi8qKlxuICogQm91bmRhcnlTdGF0ZVRyYWNrZXI8VFN0YXRlPiDigJQgdGhpcmQgc3RvcmFnZSBwcmltaXRpdmUgb24gdGhlIHJlY29yZGVyXG4gKiBzaGVsZiwgYWxvbmdzaWRlIGBTZXF1ZW5jZVJlY29yZGVyPFQ+YCBhbmQgYEtleWVkUmVjb3JkZXI8VD5gLlxuICpcbiAqICoqTWVudGFsIG1vZGVsIOKAlCBvYnNlcnZlcnMgdnMuIGJvb2trZWVwZXJzOioqXG4gKlxuICogICBgU2NvcGVSZWNvcmRlcmAgLyBgRmxvd1JlY29yZGVyYCAvIGBFbWl0UmVjb3JkZXJgIC8gYENvbWJpbmVkUmVjb3JkZXJgXG4gKiAgICAgYXJlIE9CU0VSVkVSIGludGVyZmFjZXMg4oCUIHRoZXkgZGVzY3JpYmUgaG93IGEgcmVjb3JkZXIgaGVhcnNcbiAqICAgICBldmVudHMgZnJvbSB0aGUgZXhlY3V0b3IuXG4gKlxuICogICBgU2VxdWVuY2VSZWNvcmRlcjxUPmAgLyBgS2V5ZWRSZWNvcmRlcjxUPmAgLyBgQm91bmRhcnlTdGF0ZVRyYWNrZXI8VFN0YXRlPmBcbiAqICAgICBhcmUgU1RPUkFHRSBwcmltaXRpdmVzIOKAlCB0aHJlZSBkaWZmZXJlbnQgYm9va2tlZXBpbmcgc2hlbHZlcyB3aXRoXG4gKiAgICAgZGlmZmVyZW50IGR1cmFiaWxpdHkgYW5kIGluZGV4aW5nIHByb3BlcnRpZXMuIEEgcmVhbCByZWNvcmRlclxuICogICAgIGNsYXNzIHR5cGljYWxseSBwaWNrcyBPTkUgb2JzZXJ2ZXIgaW50ZXJmYWNlIEFORCBPTkUgc3RvcmFnZVxuICogICAgIHNoZWxmLCBjb21iaW5pbmcgdGhlbSB2aWEgYGV4dGVuZHMgKyBpbXBsZW1lbnRzYC5cbiAqXG4gKiAqKldoYXQgdGhpcyBwcmltaXRpdmUgYW5zd2VyczoqKiBcIkF0IGFueSBtb21lbnQgZHVyaW5nIHRoZSBydW4sIHdoYXRcbiAqIGlzIHRoZSBMSVZFIHRyYW5zaWVudCBzdGF0ZSBvZiBldmVyeSBjdXJyZW50bHktYWN0aXZlIGJvdW5kYXJ5P1wiXG4gKlxuICogQSBcImJvdW5kYXJ5XCIgaXMgYSBtYXRjaGVkIGV2ZW50IHBhaXIgYFtzdGFydCwgc3RvcF1gIGJyYWNrZXRpbmcgYW5cbiAqIGludGVydmFsIOKAlCBmb3IgZXhhbXBsZSwgYChsbG1fc3RhcnQsIGxsbV9lbmQpYCBmb3IgYW4gTExNIGNhbGwsXG4gKiBgKHRvb2xfc3RhcnQsIHRvb2xfZW5kKWAgZm9yIHRvb2wgZXhlY3V0aW9uLCBgKHR1cm5fc3RhcnQsIHR1cm5fZW5kKWBcbiAqIGZvciBhbiBhZ2VudCB0dXJuLiBCZXR3ZWVuIHRoZSBicmFja2V0cywgaW50ZXJtZWRpYXRlIGV2ZW50cyBldm9sdmVcbiAqIHRoZSBib3VuZGFyeSdzIHN0YXRlICh0b2tlbiBjaHVua3MgYWNjdW11bGF0aW5nIGludG8gYSBwYXJ0aWFsXG4gKiBhbnN3ZXIsIGFyZ3Mgc3RyZWFtaW5nIGluLCBldGMuKS4gT24gYHN0b3BgLCB0aGUgc3RhdGUgY2xlYXJzLlxuICpcbiAqIEFsZ29yaXRobWljYWxseSB0aGlzIGlzIHRoZSAqKkRGUyBicmFja2V0LXNlcXVlbmNlIHBhdHRlcm4qKiDigJRcbiAqIHN0YWNrLWZyYW1lIHN0YXRlIGR1cmluZyBhIGdyYXBoLXRyYXZlcnNhbCBpbnRlcnZhbC4gU2FtZSBzaGFwZSB1c2VkXG4gKiBieSBUYXJqYW4ncyBTQ0MgYWxnb3JpdGhtLCB0cmVlIGRlY29tcG9zaXRpb24sIGFuZCBwdXNoLWRvd25cbiAqIGF1dG9tYXRhLiBUaGUgYGFjdGl2ZWAgbWFwIGlzIHRoZSBvcGVuLWJyYWNrZXRzIHN0YWNrIGF0IGFueSBtb21lbnQuXG4gKlxuICogKipDb21wYXJpc29uIHdpdGggdGhlIG90aGVyIHN0b3JhZ2UgcHJpbWl0aXZlczoqKlxuICpcbiAqIHwgUHJpbWl0aXZlICAgICAgICAgICAgICAgICAgICAgICB8IFN0b3JlcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IFRpbWUgc2NvcGUgICAgICAgICAgfCBNZW1vcnkgICAgICB8XG4gKiB8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfFxuICogfCBgU2VxdWVuY2VSZWNvcmRlcjxUPmAgICAgICAgICAgIHwgYXBwZW5kLW9ubHkgb3JkZXJlZCArIGtleWVkIGVudHJpZXMgIHwgZHVyYWJsZSBhY3Jvc3MgcnVuICB8IE8oTiBldmVudHMpIHxcbiAqIHwgYEtleWVkUmVjb3JkZXI8VD5gICAgICAgICAgICAgICB8IDE6MSBlbnRyeSBwZXIgYHJ1bnRpbWVTdGFnZUlkYCAgICAgICB8IGR1cmFibGUgYWNyb3NzIHJ1biAgfCBPKE4gc3RlcHMpICB8XG4gKiB8IGBCb3VuZGFyeVN0YXRlVHJhY2tlcjxUU3RhdGU+YCAgfCB0cmFuc2llbnQgYnJhY2tldC1zY29wZWQgc3RhdGUgICAgICAgfCBsaXZlOyBjbGVhcnMgb24gc3RvcCB8IE8oSyBhY3RpdmUpIHxcbiAqXG4gKiAqKldoZW4gdG8gcGljayB3aGljaDoqKlxuICpcbiAqICAgLSBcIkkgbmVlZCB0byBrZWVwIGEgcGVybWFuZW50IGxvZyBvZiBldmVyeSBldmVudCBmb3IgdGltZS10cmF2ZWxcIlxuICogICAgICDihpIgYFNlcXVlbmNlUmVjb3JkZXI8VD5gXG4gKiAgIC0gXCJJIHdhbnQgb25lIGR1cmFibGUgcmVjb3JkIHBlciBzdGFnZSBleGVjdXRpb24gKGUuZy4sIG1ldHJpY3MpXCJcbiAqICAgICAg4oaSIGBLZXllZFJlY29yZGVyPFQ+YFxuICogICAtIFwiSSBuZWVkIHRvIGtub3cgd2hhdCdzIGhhcHBlbmluZyBSSUdIVCBOT1cgaW5zaWRlIGFuIGluLWZsaWdodFxuICogICAgIGJvdW5kYXJ5IChlLmcuLCBwYXJ0aWFsIExMTSBzdHJlYW0sIHBhcnRpYWwgdG9vbCBhcmdzKVwiXG4gKiAgICAgIOKGkiBgQm91bmRhcnlTdGF0ZVRyYWNrZXI8VFN0YXRlPmAgKHRoaXMgY2xhc3MpXG4gKlxuICogKipXaGF0IHRoaXMgaXMgTk9UIGZvcjoqKlxuICpcbiAqICAgLSBUaW1lLXRyYXZlbCBxdWVyaWVzIChcIndoYXQgd2FzIHRoZSBzdGF0ZSBhdCBwYXN0IHNsaWRlciBzdGVwIE4/XCIpXG4gKiAgICAg4oCUIHRyYW5zaWVudCBzdGF0ZSBjbGVhcnMgb24gc3RvcC4gRm9yIHRpbWUtdHJhdmVsLCBzbmFwc2hvdCB0aGVcbiAqICAgICBzdGF0ZSBhdCBlYWNoIGVtaXQgaW50byBhIHNlcGFyYXRlIGBTZXF1ZW5jZVJlY29yZGVyPFRTdGF0ZT5gLFxuICogICAgIG9yIHdhaXQgZm9yIGEgZnV0dXJlIGBCb3VuZGFyeVNuYXBzaG90UmVjb3JkZXI8VFN0YXRlPmAgcHJpbWl0aXZlLlxuICpcbiAqICAgLSBBZ2dyZWdhdGlvbnMgYWNyb3NzIHRoZSB3aG9sZSBydW4gKHRvdGFscywgY291bnRzKSDigJQgdGhvc2UgYXJlXG4gKiAgICAgYFNlcXVlbmNlUmVjb3JkZXIuYWdncmVnYXRlKClgIC8gYEtleWVkUmVjb3JkZXIuYWdncmVnYXRlKClgLlxuICpcbiAqICAgLSBTdGFnZS1sZXZlbCBjb25jZXJucyDigJQgdGhvc2UgdXNlIGBTY29wZVJlY29yZGVyLm9uU3RhZ2VTdGFydGAgL1xuICogICAgIGBTY29wZVJlY29yZGVyLm9uU3RhZ2VFbmRgLiBUaGlzIHByaW1pdGl2ZSBvcGVyYXRlcyBhdCBmaW5lclxuICogICAgIGdyYW51bGFyaXR5IChldmVudHMgZW1pdHRlZCBEVVJJTkcgYSBzdGFnZSBleGVjdXRpb24pLlxuICpcbiAqICoqTGlmZWN5Y2xlIGNvbnRyYWN0IOKAlCBTVFJJQ1Q6KipcbiAqXG4gKiAgIEV2ZXJ5IGBzdGFydEJvdW5kYXJ5KGtleSwgLi4uKWAgY2FsbCBNVVNUIGJlIHBhaXJlZCB3aXRoIGFcbiAqICAgYHN0b3BCb3VuZGFyeShrZXkpYCBjYWxsLiBGYWlsdXJlIHRvIHdpcmUgdGhlIHN0b3Agc2lkZSBwcm9kdWNlcyBhXG4gKiAgIG1lbW9yeSBsZWFrOiB0aGUgYWN0aXZlIG1hcCBncm93cyB3aXRob3V0IGJvdW5kLCBhbmQgYGdldEFsbEFjdGl2ZSgpYFxuICogICByZXR1cm5zIHN0YWxlIGVudHJpZXMgdGhhdCBsb29rIGluLWZsaWdodCBidXQgYXJlbid0LiBDb21tb24gY2F1c2U6XG4gKiAgIHN1YmNsYXNzIHdpcmVzIGBzdGFydGAgdG8gb25lIGV2ZW50IGhhbmRsZXIgYW5kIGZvcmdldHMgdG8gd2lyZVxuICogICBgc3RvcGAuICoqQWx3YXlzIHdpcmUgYm90aCBhdCB0aGUgc2FtZSB0aW1lLioqXG4gKlxuICogICBEZXYgbW9kZSAoYGVuYWJsZURldk1vZGUoKWApIGRldGVjdHMgbGVha3MgYXQgYGNsZWFyKClgIHRpbWUg4oCUXG4gKiAgIHdhcm5pbmcgaW5jbHVkZXMgdGhlIGxlYWtlZCBrZXlzIHNvIHlvdSBjYW4gZmluZCB0aGUgbWlzc2luZyB3aXJpbmcuXG4gKlxuICogKipDb25jdXJyZW5jeSAvIG5lc3Rpbmc6KipcbiAqXG4gKiAgIC0gQ29uY3VycmVudCBib3VuZGFyaWVzIChwYXJhbGxlbCBicmFuY2hlcyB3aXRoIHR3byBMTE0gY2FsbHNcbiAqICAgICBhY3RpdmUgYXQgb25jZSkgd29yayBjb3JyZWN0bHk6IGVhY2ggaXMga2V5ZWQgaW5kZXBlbmRlbnRseSBpblxuICogICAgIHRoZSBhY3RpdmUgbWFwLlxuICogICAtIE5lc3RlZCBib3VuZGFyaWVzIG9mIERJRkZFUkVOVCBLSU5EUyAoQWdlbnQgYm91bmRhcnkgY29udGFpbnNcbiAqICAgICBMTE0gYm91bmRhcnkpIHJlcXVpcmUgU0VQQVJBVEUgdHJhY2tlciBpbnN0YW5jZXMg4oCUIG9uZSBwZXIga2luZC5cbiAqICAgICBUaGUgYmFzZSBjbGFzcyB0cmFja3Mgb25lIGJvdW5kYXJ5IGtpbmQgcGVyIGluc3RhbmNlLlxuICpcbiAqICoqS2V5IGNvbnZlbnRpb246KipcbiAqXG4gKiAgIFRoZSBga2V5OiBzdHJpbmdgIGlzIHdoYXRldmVyIHlvdXIgc3ViY2xhc3MgcGlja3MuIENvbnZlbnRpb246XG4gKiAgIHVzZSBgcnVudGltZVN0YWdlSWRgIHdoZW4gdGhlIGJvdW5kYXJ5IG1hcHMgMToxIHRvIGEgc3RhZ2VcbiAqICAgZXhlY3V0aW9uIOKAlCB0aGlzIGdpdmVzIGZyZWUgaW50ZXJvcCB3aXRoIGBTZXF1ZW5jZVJlY29yZGVyXG4gKiAgIC5nZXRFbnRyaWVzRm9yU3RlcGAsIGBLZXllZFJlY29yZGVyLmdldEJ5S2V5YCwgYGZpbmRDb21taXRgIC9cbiAqICAgYGZpbmRMYXN0V3JpdGVyYCwgYW5kIHRoZSByZXN0IG9mIHRoZSB0cmFjZSBlY29zeXN0ZW0uIFVzZSBhIG1vcmVcbiAqICAgZ3JhbnVsYXIga2V5IChlLmcuLCBgdG9vbENhbGxJZGApIG9ubHkgd2hlbiB0aGVyZSBhcmUgbXVsdGlwbGVcbiAqICAgY29uY3VycmVudCBib3VuZGFyaWVzIFdJVEhJTiBvbmUgc3RhZ2UgZXhlY3V0aW9uLlxuICpcbiAqIEBleGFtcGxlIEJ1aWxkIGEgbGl2ZSBMTE0gdHJhY2tlciAoY29tYmluaW5nIHN0b3JhZ2UgKyBvYnNlcnZlcik6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgQm91bmRhcnlTdGF0ZVRyYWNrZXIgfSBmcm9tICdmb290cHJpbnRqcy90cmFjZSc7XG4gKiBpbXBvcnQgeyB0eXBlIENvbWJpbmVkUmVjb3JkZXIsIHR5cGUgRW1pdEV2ZW50IH0gZnJvbSAnZm9vdHByaW50anMnO1xuICpcbiAqIGludGVyZmFjZSBMTE1MaXZlU3RhdGUge1xuICogICByZWFkb25seSBwYXJ0aWFsOiBzdHJpbmc7XG4gKiAgIHJlYWRvbmx5IHRva2VuczogbnVtYmVyO1xuICogfVxuICpcbiAqIGNsYXNzIExpdmVMTE1UcmFja2VyXG4gKiAgIGV4dGVuZHMgQm91bmRhcnlTdGF0ZVRyYWNrZXI8TExNTGl2ZVN0YXRlPiAgIC8vIFNUT1JBR0Ugc2hlbGZcbiAqICAgaW1wbGVtZW50cyBDb21iaW5lZFJlY29yZGVyICAgICAgICAgICAgICAgICAgIC8vIE9CU0VSVkVSIGludGVyZmFjZVxuICoge1xuICogICByZWFkb25seSBpZCA9ICdsaXZlLWxsbSc7XG4gKlxuICogICAvLyBPYnNlcnZlciBoYWxmIOKAlCB0cmFuc2xhdGUgZXZlbnRzIGludG8gYnJhY2tldCBtdXRhdGlvbnMuXG4gKiAgIG9uRW1pdChldmVudDogRW1pdEV2ZW50KTogdm9pZCB7XG4gKiAgICAgaWYgKGV2ZW50Lm5hbWUgPT09ICdhZ2VudGZvb3RwcmludC5zdHJlYW0ubGxtX3N0YXJ0Jykge1xuICogICAgICAgdGhpcy5zdGFydEJvdW5kYXJ5KGV2ZW50LnJ1bnRpbWVTdGFnZUlkLCB7IHBhcnRpYWw6ICcnLCB0b2tlbnM6IDAgfSk7XG4gKiAgICAgfSBlbHNlIGlmIChldmVudC5uYW1lID09PSAnYWdlbnRmb290cHJpbnQuc3RyZWFtLmxsbV9lbmQnKSB7XG4gKiAgICAgICB0aGlzLnN0b3BCb3VuZGFyeShldmVudC5ydW50aW1lU3RhZ2VJZCk7XG4gKiAgICAgfSBlbHNlIGlmIChldmVudC5uYW1lID09PSAnYWdlbnRmb290cHJpbnQuc3RyZWFtLnRva2VuJykge1xuICogICAgICAgdGhpcy51cGRhdGVCb3VuZGFyeShldmVudC5ydW50aW1lU3RhZ2VJZCwgKHMpID0+ICh7XG4gKiAgICAgICAgIHBhcnRpYWw6IHMucGFydGlhbCArIChldmVudC5wYXlsb2FkIGFzIHsgY29udGVudDogc3RyaW5nIH0pLmNvbnRlbnQsXG4gKiAgICAgICAgIHRva2Vuczogcy50b2tlbnMgKyAxLFxuICogICAgICAgfSkpO1xuICogICAgIH1cbiAqICAgfVxuICpcbiAqICAgLy8gUHVibGljIHJlYWQgQVBJIOKAlCBPKDEpIGF0IGFueSBtb21lbnQuXG4gKiAgIGlzSW5GbGlnaHQoKTogYm9vbGVhbiB7IHJldHVybiB0aGlzLmhhc0FjdGl2ZTsgfVxuICogICBnZXRQYXJ0aWFsKHN0YWdlSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gKiAgICAgcmV0dXJuIHRoaXMuZ2V0QWN0aXZlKHN0YWdlSWQpPy5wYXJ0aWFsID8/ICcnO1xuICogICB9XG4gKiB9XG4gKlxuICogLy8gQXR0YWNoZWQgdGhlIHNhbWUgd2F5IGFzIGFueSBvdGhlciBDb21iaW5lZFJlY29yZGVyLlxuICogY29uc3QgdHJhY2tlciA9IG5ldyBMaXZlTExNVHJhY2tlcigpO1xuICogZXhlY3V0b3IuYXR0YWNoQ29tYmluZWRSZWNvcmRlcih0cmFja2VyKTtcbiAqIGF3YWl0IGV4ZWN1dG9yLnJ1bih7IGlucHV0IH0pO1xuICpcbiAqIC8vIFJlYWQgbGl2ZSBzdGF0ZSBhdCBhbnkgdGltZSBkdXJpbmcgb3IgYWZ0ZXIgdGhlIHJ1bi5cbiAqIHRyYWNrZXIuaXNJbkZsaWdodCgpO1xuICogdHJhY2tlci5nZXRQYXJ0aWFsKHJpZCk7XG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQgeyBpc0Rldk1vZGUgfSBmcm9tICcuLi9zY29wZS9kZXRlY3RDaXJjdWxhci5qcyc7XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCb3VuZGFyeVN0YXRlVHJhY2tlcjxUU3RhdGU+IHtcbiAgLyoqIFN0YWJsZSBpZCDigJQgc2FtZSBpZGVtcG90ZW5jeSBjb250cmFjdCBhcyBvdGhlciByZWNvcmRlcnMuICovXG4gIGFic3RyYWN0IHJlYWRvbmx5IGlkOiBzdHJpbmc7XG5cbiAgLyoqIE9wZW4tYnJhY2tldHMgc3RhY2s6IGtleSDihpIgY3VycmVudCB0cmFuc2llbnQgc3RhdGUuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgYWN0aXZlID0gbmV3IE1hcDxzdHJpbmcsIFRTdGF0ZT4oKTtcblxuICAvKiogUGVyLWtleSBjb3VudCBvZiBgdXBkYXRlQm91bmRhcnlgIGNhbGxzIHRoYXQgbGFuZGVkIHdpdGhvdXQgYVxuICAgKiAgbWF0Y2hpbmcgYWN0aXZlIGJvdW5kYXJ5LiBEcml2ZXMgcmF0ZS1saW1pdGVkIGRldi1tb2RlIHdhcm5pbmdzXG4gICAqICBzbyBhIHN0dWNrIGxvb3AgZG9lc24ndCBzcGFtIHRoZSBjb25zb2xlLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IG1pc3NlZFVwZGF0ZXMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuXG4gIC8vIOKUgOKUgCBNdXRhdG9yIEFQSSAoc3ViY2xhc3MgY2FsbHMgdGhlc2UgZnJvbSBvYnNlcnZlciBob29rcykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIE9wZW4gYSBuZXcgYm91bmRhcnkgd2l0aCBpbml0aWFsIHRyYW5zaWVudCBzdGF0ZS5cbiAgICpcbiAgICogSWYgYSBib3VuZGFyeSB3aXRoIHRoZSBzYW1lIGBrZXlgIGlzIGFscmVhZHkgYWN0aXZlLCB0aGUgcHJpb3JcbiAgICogc3RhdGUgaXMgb3ZlcndyaXR0ZW4gKGxhc3Qtd3JpdGVyLXdpbnMpLiBJbiBkZXYgbW9kZSwgYSB3YXJuaW5nXG4gICAqIGlzIGxvZ2dlZCBiZWNhdXNlIHJlLXN0YXJ0aW5nIGFuIGFjdGl2ZSBrZXkgdXN1YWxseSBpbmRpY2F0ZXMgYVxuICAgKiBtaXNzZWQgYHN0b3BCb3VuZGFyeWAgY2FsbCB1cHN0cmVhbS5cbiAgICpcbiAgICogQHBhcmFtIGtleSBCb3VuZGFyeSBpZGVudGlmaWVyIOKAlCBieSBjb252ZW50aW9uLCBgcnVudGltZVN0YWdlSWRgXG4gICAqICAgICAgICAgICAgZm9yIDE6MS13aXRoLXN0YWdlIGJvdW5kYXJpZXMsIG9yIGEgbW9yZSBncmFudWxhciBpZFxuICAgKiAgICAgICAgICAgIChlLmcuLCBgdG9vbENhbGxJZGApIHdoZW4gbXVsdGlwbGUgY29uY3VycmVudCBib3VuZGFyaWVzXG4gICAqICAgICAgICAgICAgcnVuIHdpdGhpbiBvbmUgc3RhZ2UgZXhlY3V0aW9uLlxuICAgKiBAcGFyYW0gaW5pdGlhbCBJbml0aWFsIHN0YXRlIOKAlCB0eXBlZCBieSBgVFN0YXRlYC5cbiAgICovXG4gIHByb3RlY3RlZCBzdGFydEJvdW5kYXJ5KGtleTogc3RyaW5nLCBpbml0aWFsOiBUU3RhdGUpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hY3RpdmUuaGFzKGtleSkgJiYgaXNEZXZNb2RlKCkpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYFske3RoaXMuaWR9XSBzdGFydEJvdW5kYXJ5KCcke2tleX0nKSBjYWxsZWQgd2hpbGUgYW4gYWN0aXZlIGJvdW5kYXJ5IGFscmVhZHkgZXhpc3RzLiBgICtcbiAgICAgICAgICAnT3ZlcndyaXRpbmcgcHJpb3Igc3RhdGUg4oCUIGxpa2VseSBhIG1pc3NlZCBzdG9wQm91bmRhcnkgdXBzdHJlYW0uJyxcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMuYWN0aXZlLnNldChrZXksIGluaXRpYWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV2b2x2ZSB0aGUgdHJhbnNpZW50IHN0YXRlIG9mIGFuIGFjdGl2ZSBib3VuZGFyeSB1c2luZyBhbiB1cGRhdGVyXG4gICAqIGZ1bmN0aW9uLiBTaWxlbnQgbm8tb3AgaWYgbm8gYm91bmRhcnkgaXMgYWN0aXZlIGZvciBga2V5YFxuICAgKiAoZGVmZW5zaXZlIGFnYWluc3Qgb3V0LW9mLW9yZGVyIGV2ZW50cykuIEluIGRldiBtb2RlLCBhIHJhdGUtbGltaXRlZFxuICAgKiB3YXJuaW5nIGlzIGxvZ2dlZCBvbiB0aGUgMXN0LCAxMHRoLCBhbmQgMTAwdGggbWlzc2VkIHVwZGF0ZSBwZXIga2V5LlxuICAgKlxuICAgKiBAcGFyYW0ga2V5ICAgICAgQm91bmRhcnkgaWRlbnRpZmllciAobXVzdCBtYXRjaCBhIHByaW9yIGBzdGFydEJvdW5kYXJ5YCkuXG4gICAqIEBwYXJhbSB1cGRhdGVyICBQdXJlIGZ1bmN0aW9uOiBwcmV2aW91cyBzdGF0ZSDihpIgbmV4dCBzdGF0ZS5cbiAgICovXG4gIHByb3RlY3RlZCB1cGRhdGVCb3VuZGFyeShrZXk6IHN0cmluZywgdXBkYXRlcjogKHByZXY6IFRTdGF0ZSkgPT4gVFN0YXRlKTogdm9pZCB7XG4gICAgY29uc3QgY3VyID0gdGhpcy5hY3RpdmUuZ2V0KGtleSk7XG4gICAgaWYgKGN1ciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBpZiAoaXNEZXZNb2RlKCkpIHtcbiAgICAgICAgY29uc3QgbiA9ICh0aGlzLm1pc3NlZFVwZGF0ZXMuZ2V0KGtleSkgPz8gMCkgKyAxO1xuICAgICAgICB0aGlzLm1pc3NlZFVwZGF0ZXMuc2V0KGtleSwgbik7XG4gICAgICAgIGlmIChuID09PSAxKSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKGBbJHt0aGlzLmlkfV0gdXBkYXRlQm91bmRhcnkoJyR7a2V5fScpIOKAlCBubyBhY3RpdmUgYm91bmRhcnkuIFVwZGF0ZSBkcm9wcGVkLmApO1xuICAgICAgICB9IGVsc2UgaWYgKG4gPT09IDEwIHx8IG4gPT09IDEwMCkge1xuICAgICAgICAgIGNvbnNvbGUud2FybihgWyR7dGhpcy5pZH1dIHVwZGF0ZUJvdW5kYXJ5KCcke2tleX0nKSDigJQgJHtufSBkcm9wcGVkIHVwZGF0ZXMuIFdpcmluZyBidWc/YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5hY3RpdmUuc2V0KGtleSwgdXBkYXRlcihjdXIpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbG9zZSB0aGUgYm91bmRhcnkgaWRlbnRpZmllZCBieSBga2V5YCBhbmQgcmV0dXJuIGl0cyBGSU5BTFxuICAgKiB0cmFuc2llbnQgc3RhdGUgKGZvciBhbnkgY2xlYW51cCB0aGUgc3ViY2xhc3Mgd2FudHMg4oCUIGUuZy4sIGVtaXQgYVxuICAgKiBzbmFwc2hvdCB0byBhIFNlcXVlbmNlUmVjb3JkZXIgZm9yIGR1cmFibGUgc3RvcmFnZSkuXG4gICAqXG4gICAqIEBwYXJhbSBrZXkgQm91bmRhcnkgaWRlbnRpZmllci5cbiAgICogQHJldHVybnMgVGhlIGZpbmFsIHN0YXRlLCBvciBgdW5kZWZpbmVkYCBpZiBubyBib3VuZGFyeSB3YXMgYWN0aXZlLlxuICAgKi9cbiAgcHJvdGVjdGVkIHN0b3BCb3VuZGFyeShrZXk6IHN0cmluZyk6IFRTdGF0ZSB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgZmluYWwgPSB0aGlzLmFjdGl2ZS5nZXQoa2V5KTtcbiAgICB0aGlzLmFjdGl2ZS5kZWxldGUoa2V5KTtcbiAgICByZXR1cm4gZmluYWw7XG4gIH1cblxuICAvLyDilIDilIAgUmVhZCBBUEkgKGNvbnN1bWVycyBjYWxsIHRoZXNlIOKAlCBPKDEpKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogQ3VycmVudCB0cmFuc2llbnQgc3RhdGUgb2YgT05FIGFjdGl2ZSBib3VuZGFyeS4gYHVuZGVmaW5lZGAgaWYgbm9cbiAgICogIGJvdW5kYXJ5IGlzIGFjdGl2ZSBmb3IgYGtleWAuICovXG4gIGdldEFjdGl2ZShrZXk6IHN0cmluZyk6IFRTdGF0ZSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlLmdldChrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFsbCBjdXJyZW50bHktYWN0aXZlIGJvdW5kYXJpZXMuXG4gICAqXG4gICAqICoqVHlwZS1vbmx5IHJlYWRvbmx5OioqIHRoZSByZXR1cm5lZCByZWZlcmVuY2UgSVMgdGhlIGludGVybmFsIE1hcC5cbiAgICogVHlwZVNjcmlwdCBwcmV2ZW50cyBtdXRhdGlvbiB0aHJvdWdoIHRoZSBgUmVhZG9ubHlNYXBgIHR5cGUsIGJ1dCBhXG4gICAqIHJ1bnRpbWUgY2FzdCBvciBub24tVFMgY29uc3VtZXIgY2FuIG11dGF0ZSBpdCBhbmQgY29ycnVwdCBpbnRlcm5hbFxuICAgKiBzdGF0ZS4gKipEbyBub3QgbXV0YXRlLioqXG4gICAqL1xuICBnZXRBbGxBY3RpdmUoKTogUmVhZG9ubHlNYXA8c3RyaW5nLCBUU3RhdGU+IHtcbiAgICByZXR1cm4gdGhpcy5hY3RpdmU7XG4gIH1cblxuICAvKiogVHJ1ZSBpZiBhbnkgYm91bmRhcnkgaXMgY3VycmVudGx5IGFjdGl2ZS4gTygxKS4gKi9cbiAgZ2V0IGhhc0FjdGl2ZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5hY3RpdmUuc2l6ZSA+IDA7XG4gIH1cblxuICAvKiogTnVtYmVyIG9mIGN1cnJlbnRseS1hY3RpdmUgYm91bmRhcmllcy4gTygxKS4gKi9cbiAgZ2V0IGFjdGl2ZUNvdW50KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlLnNpemU7XG4gIH1cblxuICAvLyDilIDilIAgTGlmZWN5Y2xlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKlxuICAgKiBSZXNldCBhbGwgdHJhbnNpZW50IHN0YXRlLiBDYWxsZWQgYnkgZXhlY3V0b3JzIGJlZm9yZSBlYWNoIGBydW4oKWBcbiAgICogc28gY29uc3VtZXJzIGdldCBhIGNsZWFuIHNsYXRlIHBlciBydW4g4oCUIHNhbWUgbGlmZWN5Y2xlIGNvbnRyYWN0XG4gICAqIGFzIGBTZXF1ZW5jZVJlY29yZGVyLmNsZWFyKClgLlxuICAgKlxuICAgKiBJbiBkZXYgbW9kZSwgd2FybnMgaWYgYW55IGJvdW5kYXJpZXMgYXJlIHN0aWxsIGFjdGl2ZSB3aGVuIGNhbGxlZFxuICAgKiDigJQgbGlrZWx5IGluZGljYXRlcyBhIG1pc3NlZCBgc3RvcEJvdW5kYXJ5YCB1cHN0cmVhbS4gVGhlIGxlYWtlZFxuICAgKiBrZXlzIGFyZSBsaXN0ZWQgKHRydW5jYXRlZCB0byAxMCkgc28gdGhlIHdpcmluZyBidWcgaXMgZmluZGFibGUuXG4gICAqL1xuICBjbGVhcigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hY3RpdmUuc2l6ZSA+IDAgJiYgaXNEZXZNb2RlKCkpIHtcbiAgICAgIGNvbnN0IGtleXMgPSBbLi4udGhpcy5hY3RpdmUua2V5cygpXTtcbiAgICAgIGNvbnN0IGhlYWQgPSBrZXlzLnNsaWNlKDAsIDEwKS5qb2luKCcsICcpO1xuICAgICAgY29uc3QgbW9yZSA9IGtleXMubGVuZ3RoID4gMTAgPyBgIC4uLigrJHtrZXlzLmxlbmd0aCAtIDEwfSBtb3JlKWAgOiAnJztcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYFske3RoaXMuaWR9XSBjbGVhcigpIGNhbGxlZCB3aXRoICR7dGhpcy5hY3RpdmUuc2l6ZX0gYCArXG4gICAgICAgICAgJ3N0aWxsLWFjdGl2ZSBib3VuZGFyaWVzLiBNaXNzZWQgc3RvcEJvdW5kYXJ5PyAnICtcbiAgICAgICAgICBgTGVha2VkIGtleXM6ICR7aGVhZH0ke21vcmV9YCxcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMuYWN0aXZlLmNsZWFyKCk7XG4gICAgdGhpcy5taXNzZWRVcGRhdGVzLmNsZWFyKCk7XG4gIH1cbn1cbiJdfQ==
@@ -1,98 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.KeyedRecorder = void 0;
4
- /**
5
- * KeyedRecorder<T> — base class for Map-based recorders keyed by runtimeStageId.
6
- *
7
- * Provides typed key-value storage with O(1) lookup, insertion-ordered iteration,
8
- * and three standard operations on auto-collected traversal data:
9
- *
10
- * - **Translate** (raw): `getByKey(id)` — per-step value
11
- * - **Accumulate** (progressive): `accumulate(fn, initial, keys?)` — running total up to a point
12
- * - **Aggregate** (summary): `aggregate(fn, initial)` — reduce all entries
13
- *
14
- * Data is automatically collected during the single DFS traversal.
15
- * The consumer chooses the operation at read time.
16
- *
17
- * @example
18
- * ```typescript
19
- * class TokenRecorder extends KeyedRecorder<LLMCallEntry> {
20
- * readonly id = 'tokens';
21
- * onLLMCall(event) { this.store(event.runtimeStageId, { tokens: event.usage }); }
22
- *
23
- * // Translate: per-step
24
- * getForStep(id: string) { return this.getByKey(id); }
25
- *
26
- * // Aggregate: total
27
- * getTotalTokens() { return this.aggregate((sum, e) => sum + e.tokens, 0); }
28
- *
29
- * // Accumulate: progressive up to slider position
30
- * getTokensUpTo(keys: Set<string>) { return this.accumulate((sum, e) => sum + e.tokens, 0, keys); }
31
- * }
32
- * ```
33
- */
34
- class KeyedRecorder {
35
- data = new Map();
36
- /** Store an entry keyed by runtimeStageId. */
37
- store(runtimeStageId, entry) {
38
- this.data.set(runtimeStageId, entry);
39
- }
40
- // ── Translate (raw per-step) ──────────────────────────────
41
- /** O(1) lookup by runtimeStageId. */
42
- getByKey(runtimeStageId) {
43
- return this.data.get(runtimeStageId);
44
- }
45
- /** All entries as a read-only Map (insertion-ordered). */
46
- getMap() {
47
- return this.data;
48
- }
49
- /** All entries as an array (insertion-ordered). */
50
- values() {
51
- return [...this.data.values()];
52
- }
53
- /** Number of entries stored. */
54
- get size() {
55
- return this.data.size;
56
- }
57
- // ── Aggregate (reduce all entries) ────────────────────────
58
- /** Reduce ALL entries to a single value. For dashboards, totals, summaries. */
59
- aggregate(fn, initial) {
60
- let acc = initial;
61
- for (const [key, entry] of this.data) {
62
- acc = fn(acc, entry, key);
63
- }
64
- return acc;
65
- }
66
- // ── Accumulate (progressive reduce) ───────────────────────
67
- /**
68
- * Reduce entries, optionally filtered by a set of keys.
69
- * For time-travel progressive view: pass the runtimeStageIds visible at the current slider position.
70
- * Without keys, reduces all entries (same as aggregate).
71
- */
72
- accumulate(fn, initial, keys) {
73
- let acc = initial;
74
- for (const [key, entry] of this.data) {
75
- if (keys && !keys.has(key))
76
- continue;
77
- acc = fn(acc, entry, key);
78
- }
79
- return acc;
80
- }
81
- // ── Filter (subset by keys) ───────────────────────────────
82
- /** Return entries whose keys are in the set, preserving insertion order. */
83
- filterByKeys(keys) {
84
- const result = [];
85
- for (const [key, entry] of this.data) {
86
- if (keys.has(key))
87
- result.push(entry);
88
- }
89
- return result;
90
- }
91
- // ── Lifecycle ─────────────────────────────────────────────
92
- /** Clear all stored data. Called by executor before each run(). */
93
- clear() {
94
- this.data.clear();
95
- }
96
- }
97
- exports.KeyedRecorder = KeyedRecorder;
98
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiS2V5ZWRSZWNvcmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvcmVjb3JkZXIvS2V5ZWRSZWNvcmRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2Qkc7QUFDSCxNQUFzQixhQUFhO0lBR2hCLElBQUksR0FBRyxJQUFJLEdBQUcsRUFBYSxDQUFDO0lBRTdDLDhDQUE4QztJQUNwQyxLQUFLLENBQUMsY0FBc0IsRUFBRSxLQUFRO1FBQzlDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQsNkRBQTZEO0lBRTdELHFDQUFxQztJQUNyQyxRQUFRLENBQUMsY0FBc0I7UUFDN0IsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQsMERBQTBEO0lBQzFELE1BQU07UUFDSixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDbkIsQ0FBQztJQUVELG1EQUFtRDtJQUNuRCxNQUFNO1FBQ0osT0FBTyxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFRCxnQ0FBZ0M7SUFDaEMsSUFBSSxJQUFJO1FBQ04sT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztJQUN4QixDQUFDO0lBRUQsNkRBQTZEO0lBRTdELCtFQUErRTtJQUMvRSxTQUFTLENBQUksRUFBd0MsRUFBRSxPQUFVO1FBQy9ELElBQUksR0FBRyxHQUFHLE9BQU8sQ0FBQztRQUNsQixLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ3JDLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztRQUM1QixDQUFDO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRUQsNkRBQTZEO0lBRTdEOzs7O09BSUc7SUFDSCxVQUFVLENBQUksRUFBd0MsRUFBRSxPQUFVLEVBQUUsSUFBMEI7UUFDNUYsSUFBSSxHQUFHLEdBQUcsT0FBTyxDQUFDO1FBQ2xCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDckMsSUFBSSxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztnQkFBRSxTQUFTO1lBQ3JDLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztRQUM1QixDQUFDO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRUQsNkRBQTZEO0lBRTdELDRFQUE0RTtJQUM1RSxZQUFZLENBQUMsSUFBeUI7UUFDcEMsTUFBTSxNQUFNLEdBQVEsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDckMsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztnQkFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsNkRBQTZEO0lBRTdELG1FQUFtRTtJQUNuRSxLQUFLO1FBQ0gsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNwQixDQUFDO0NBQ0Y7QUE1RUQsc0NBNEVDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBLZXllZFJlY29yZGVyPFQ+IOKAlCBiYXNlIGNsYXNzIGZvciBNYXAtYmFzZWQgcmVjb3JkZXJzIGtleWVkIGJ5IHJ1bnRpbWVTdGFnZUlkLlxuICpcbiAqIFByb3ZpZGVzIHR5cGVkIGtleS12YWx1ZSBzdG9yYWdlIHdpdGggTygxKSBsb29rdXAsIGluc2VydGlvbi1vcmRlcmVkIGl0ZXJhdGlvbixcbiAqIGFuZCB0aHJlZSBzdGFuZGFyZCBvcGVyYXRpb25zIG9uIGF1dG8tY29sbGVjdGVkIHRyYXZlcnNhbCBkYXRhOlxuICpcbiAqICAgLSAqKlRyYW5zbGF0ZSoqIChyYXcpOiBgZ2V0QnlLZXkoaWQpYCDigJQgcGVyLXN0ZXAgdmFsdWVcbiAqICAgLSAqKkFjY3VtdWxhdGUqKiAocHJvZ3Jlc3NpdmUpOiBgYWNjdW11bGF0ZShmbiwgaW5pdGlhbCwga2V5cz8pYCDigJQgcnVubmluZyB0b3RhbCB1cCB0byBhIHBvaW50XG4gKiAgIC0gKipBZ2dyZWdhdGUqKiAoc3VtbWFyeSk6IGBhZ2dyZWdhdGUoZm4sIGluaXRpYWwpYCDigJQgcmVkdWNlIGFsbCBlbnRyaWVzXG4gKlxuICogRGF0YSBpcyBhdXRvbWF0aWNhbGx5IGNvbGxlY3RlZCBkdXJpbmcgdGhlIHNpbmdsZSBERlMgdHJhdmVyc2FsLlxuICogVGhlIGNvbnN1bWVyIGNob29zZXMgdGhlIG9wZXJhdGlvbiBhdCByZWFkIHRpbWUuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNsYXNzIFRva2VuUmVjb3JkZXIgZXh0ZW5kcyBLZXllZFJlY29yZGVyPExMTUNhbGxFbnRyeT4ge1xuICogICByZWFkb25seSBpZCA9ICd0b2tlbnMnO1xuICogICBvbkxMTUNhbGwoZXZlbnQpIHsgdGhpcy5zdG9yZShldmVudC5ydW50aW1lU3RhZ2VJZCwgeyB0b2tlbnM6IGV2ZW50LnVzYWdlIH0pOyB9XG4gKlxuICogICAvLyBUcmFuc2xhdGU6IHBlci1zdGVwXG4gKiAgIGdldEZvclN0ZXAoaWQ6IHN0cmluZykgeyByZXR1cm4gdGhpcy5nZXRCeUtleShpZCk7IH1cbiAqXG4gKiAgIC8vIEFnZ3JlZ2F0ZTogdG90YWxcbiAqICAgZ2V0VG90YWxUb2tlbnMoKSB7IHJldHVybiB0aGlzLmFnZ3JlZ2F0ZSgoc3VtLCBlKSA9PiBzdW0gKyBlLnRva2VucywgMCk7IH1cbiAqXG4gKiAgIC8vIEFjY3VtdWxhdGU6IHByb2dyZXNzaXZlIHVwIHRvIHNsaWRlciBwb3NpdGlvblxuICogICBnZXRUb2tlbnNVcFRvKGtleXM6IFNldDxzdHJpbmc+KSB7IHJldHVybiB0aGlzLmFjY3VtdWxhdGUoKHN1bSwgZSkgPT4gc3VtICsgZS50b2tlbnMsIDAsIGtleXMpOyB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEtleWVkUmVjb3JkZXI8VD4ge1xuICBhYnN0cmFjdCByZWFkb25seSBpZDogc3RyaW5nO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZGF0YSA9IG5ldyBNYXA8c3RyaW5nLCBUPigpO1xuXG4gIC8qKiBTdG9yZSBhbiBlbnRyeSBrZXllZCBieSBydW50aW1lU3RhZ2VJZC4gKi9cbiAgcHJvdGVjdGVkIHN0b3JlKHJ1bnRpbWVTdGFnZUlkOiBzdHJpbmcsIGVudHJ5OiBUKTogdm9pZCB7XG4gICAgdGhpcy5kYXRhLnNldChydW50aW1lU3RhZ2VJZCwgZW50cnkpO1xuICB9XG5cbiAgLy8g4pSA4pSAIFRyYW5zbGF0ZSAocmF3IHBlci1zdGVwKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogTygxKSBsb29rdXAgYnkgcnVudGltZVN0YWdlSWQuICovXG4gIGdldEJ5S2V5KHJ1bnRpbWVTdGFnZUlkOiBzdHJpbmcpOiBUIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5kYXRhLmdldChydW50aW1lU3RhZ2VJZCk7XG4gIH1cblxuICAvKiogQWxsIGVudHJpZXMgYXMgYSByZWFkLW9ubHkgTWFwIChpbnNlcnRpb24tb3JkZXJlZCkuICovXG4gIGdldE1hcCgpOiBSZWFkb25seU1hcDxzdHJpbmcsIFQ+IHtcbiAgICByZXR1cm4gdGhpcy5kYXRhO1xuICB9XG5cbiAgLyoqIEFsbCBlbnRyaWVzIGFzIGFuIGFycmF5IChpbnNlcnRpb24tb3JkZXJlZCkuICovXG4gIHZhbHVlcygpOiBUW10ge1xuICAgIHJldHVybiBbLi4udGhpcy5kYXRhLnZhbHVlcygpXTtcbiAgfVxuXG4gIC8qKiBOdW1iZXIgb2YgZW50cmllcyBzdG9yZWQuICovXG4gIGdldCBzaXplKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YS5zaXplO1xuICB9XG5cbiAgLy8g4pSA4pSAIEFnZ3JlZ2F0ZSAocmVkdWNlIGFsbCBlbnRyaWVzKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogUmVkdWNlIEFMTCBlbnRyaWVzIHRvIGEgc2luZ2xlIHZhbHVlLiBGb3IgZGFzaGJvYXJkcywgdG90YWxzLCBzdW1tYXJpZXMuICovXG4gIGFnZ3JlZ2F0ZTxSPihmbjogKGFjYzogUiwgZW50cnk6IFQsIGtleTogc3RyaW5nKSA9PiBSLCBpbml0aWFsOiBSKTogUiB7XG4gICAgbGV0IGFjYyA9IGluaXRpYWw7XG4gICAgZm9yIChjb25zdCBba2V5LCBlbnRyeV0gb2YgdGhpcy5kYXRhKSB7XG4gICAgICBhY2MgPSBmbihhY2MsIGVudHJ5LCBrZXkpO1xuICAgIH1cbiAgICByZXR1cm4gYWNjO1xuICB9XG5cbiAgLy8g4pSA4pSAIEFjY3VtdWxhdGUgKHByb2dyZXNzaXZlIHJlZHVjZSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFJlZHVjZSBlbnRyaWVzLCBvcHRpb25hbGx5IGZpbHRlcmVkIGJ5IGEgc2V0IG9mIGtleXMuXG4gICAqIEZvciB0aW1lLXRyYXZlbCBwcm9ncmVzc2l2ZSB2aWV3OiBwYXNzIHRoZSBydW50aW1lU3RhZ2VJZHMgdmlzaWJsZSBhdCB0aGUgY3VycmVudCBzbGlkZXIgcG9zaXRpb24uXG4gICAqIFdpdGhvdXQga2V5cywgcmVkdWNlcyBhbGwgZW50cmllcyAoc2FtZSBhcyBhZ2dyZWdhdGUpLlxuICAgKi9cbiAgYWNjdW11bGF0ZTxSPihmbjogKGFjYzogUiwgZW50cnk6IFQsIGtleTogc3RyaW5nKSA9PiBSLCBpbml0aWFsOiBSLCBrZXlzPzogUmVhZG9ubHlTZXQ8c3RyaW5nPik6IFIge1xuICAgIGxldCBhY2MgPSBpbml0aWFsO1xuICAgIGZvciAoY29uc3QgW2tleSwgZW50cnldIG9mIHRoaXMuZGF0YSkge1xuICAgICAgaWYgKGtleXMgJiYgIWtleXMuaGFzKGtleSkpIGNvbnRpbnVlO1xuICAgICAgYWNjID0gZm4oYWNjLCBlbnRyeSwga2V5KTtcbiAgICB9XG4gICAgcmV0dXJuIGFjYztcbiAgfVxuXG4gIC8vIOKUgOKUgCBGaWx0ZXIgKHN1YnNldCBieSBrZXlzKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogUmV0dXJuIGVudHJpZXMgd2hvc2Uga2V5cyBhcmUgaW4gdGhlIHNldCwgcHJlc2VydmluZyBpbnNlcnRpb24gb3JkZXIuICovXG4gIGZpbHRlckJ5S2V5cyhrZXlzOiBSZWFkb25seVNldDxzdHJpbmc+KTogVFtdIHtcbiAgICBjb25zdCByZXN1bHQ6IFRbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgW2tleSwgZW50cnldIG9mIHRoaXMuZGF0YSkge1xuICAgICAgaWYgKGtleXMuaGFzKGtleSkpIHJlc3VsdC5wdXNoKGVudHJ5KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8vIOKUgOKUgCBMaWZlY3ljbGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIENsZWFyIGFsbCBzdG9yZWQgZGF0YS4gQ2FsbGVkIGJ5IGV4ZWN1dG9yIGJlZm9yZSBlYWNoIHJ1bigpLiAqL1xuICBjbGVhcigpOiB2b2lkIHtcbiAgICB0aGlzLmRhdGEuY2xlYXIoKTtcbiAgfVxufVxuIl19
@@ -1,197 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SequenceRecorder = void 0;
4
- /**
5
- * SequenceRecorder<T> — base class for ordered sequence recorders with keyed index.
6
- *
7
- * Provides dual-indexed storage: a flat array preserving insertion order plus a
8
- * Map<runtimeStageId, T[]> for O(1) per-step lookup. One entry type, multiple entries
9
- * per step. Designed for recorders that implement BOTH ScopeRecorder and FlowRecorder
10
- * (merging data ops and control flow into a single interleaved sequence).
11
- *
12
- * **Contrast with KeyedRecorder<T>:**
13
- * - `KeyedRecorder<T>` — 1:1 Map. One entry per runtimeStageId. For single-value recorders
14
- * like MetricRecorder (one StepMetrics per stage execution).
15
- * - `SequenceRecorder<T>` — 1:N sequence + Map. Multiple entries per runtimeStageId,
16
- * plus ordering matters. For recorders that produce a prose narrative or event log
17
- * where a single step generates stage + data + decision entries.
18
- *
19
- * **How to choose:**
20
- * - If each step produces exactly one record → extend `KeyedRecorder<T>`
21
- * - If each step produces multiple records or ordering matters → extend `SequenceRecorder<T>`
22
- *
23
- * @example
24
- * ```typescript
25
- * import { SequenceRecorder } from 'footprintjs/trace';
26
- *
27
- * interface AuditEntry {
28
- * runtimeStageId?: string;
29
- * type: 'read' | 'write' | 'decision';
30
- * detail: string;
31
- * }
32
- *
33
- * class AuditRecorder extends SequenceRecorder<AuditEntry> {
34
- * readonly id = 'audit';
35
- *
36
- * // Scope hooks (fires during stage execution)
37
- * onRead(event: ReadEvent) {
38
- * this.emit({ runtimeStageId: event.runtimeStageId, type: 'read', detail: event.key });
39
- * }
40
- * onWrite(event: WriteEvent) {
41
- * this.emit({ runtimeStageId: event.runtimeStageId, type: 'write', detail: event.key });
42
- * }
43
- *
44
- * // Flow hooks (fires after stage execution)
45
- * onDecision(event: FlowDecisionEvent) {
46
- * this.emit({
47
- * runtimeStageId: event.traversalContext?.runtimeStageId,
48
- * type: 'decision',
49
- * detail: `${event.decider} chose ${event.chosen}`,
50
- * });
51
- * }
52
- *
53
- * // Time-travel: entries up to slider position
54
- * getAuditUpTo(visibleIds: ReadonlySet<string>) {
55
- * return this.getEntriesUpTo(visibleIds);
56
- * }
57
- * }
58
- * ```
59
- */
60
- class SequenceRecorder {
61
- /** Ordered sequence of all entries (insertion order). */
62
- entries = [];
63
- /** Per-step index: runtimeStageId → entries for that step. Same objects as entries[]. */
64
- byRuntimeStageId = new Map();
65
- /** Per-step range index: runtimeStageId → [firstIdx, endIdx) in entries array.
66
- * endIdx includes trailing keyless entries (structural markers). Maintained during emit(). */
67
- entryRanges = new Map();
68
- /** The runtimeStageId of the most recently emitted keyed entry. Used to extend ranges for trailing markers. */
69
- lastEmittedId;
70
- // ── Write ─────────────────────────────────────────────────────────────
71
- /**
72
- * Append an entry to both the ordered sequence, keyed index, and range index.
73
- * All reference the same entry object — no duplication.
74
- */
75
- emit(entry) {
76
- const idx = this.entries.length;
77
- this.entries.push(entry);
78
- const id = entry.runtimeStageId;
79
- if (id) {
80
- let arr = this.byRuntimeStageId.get(id);
81
- if (!arr) {
82
- arr = [];
83
- this.byRuntimeStageId.set(id, arr);
84
- this.entryRanges.set(id, { firstIdx: idx, endIdx: idx + 1 });
85
- }
86
- else {
87
- this.entryRanges.get(id).endIdx = idx + 1;
88
- }
89
- arr.push(entry);
90
- this.lastEmittedId = id;
91
- }
92
- else if (this.lastEmittedId) {
93
- // Structural marker (no runtimeStageId) — extend the preceding step's range
94
- this.entryRanges.get(this.lastEmittedId).endIdx = idx + 1;
95
- }
96
- }
97
- // ── Ordered access ────────────────────────────────────────────────────
98
- /** All entries in insertion order (returns a shallow copy — entry objects are shared). */
99
- getEntries() {
100
- return [...this.entries];
101
- }
102
- /** Number of entries in the sequence. */
103
- get entryCount() {
104
- return this.entries.length;
105
- }
106
- /** Zero-copy iteration for subclass rendering methods (avoids getEntries() spread). */
107
- forEachEntry(fn) {
108
- for (const entry of this.entries) {
109
- fn(entry);
110
- }
111
- }
112
- // ── Keyed access ──────────────────────────────────────────────────────
113
- /** O(1) lookup: all entries for a specific execution step (returns a copy). */
114
- getEntriesForStep(runtimeStageId) {
115
- return [...(this.byRuntimeStageId.get(runtimeStageId) ?? [])];
116
- }
117
- /** Number of unique execution steps that have entries. */
118
- get stepCount() {
119
- return this.byRuntimeStageId.size;
120
- }
121
- /**
122
- * Pre-built range index: runtimeStageId → half-open range [firstIdx, endIdx) in entries array.
123
- * Maintained during emit() — no rebuild needed. Use for O(1) per-step lookups during time-travel.
124
- * endIdx includes trailing keyless entries (structural markers following a step).
125
- */
126
- getEntryRanges() {
127
- return this.entryRanges;
128
- }
129
- // ── Aggregate (reduce all entries) ────────────────────────────────────
130
- /** Reduce ALL entries to a single value. For dashboards, totals, summaries. */
131
- aggregate(fn, initial) {
132
- let acc = initial;
133
- for (const entry of this.entries) {
134
- acc = fn(acc, entry);
135
- }
136
- return acc;
137
- }
138
- // ── Accumulate (progressive reduce) ─────────────────────────────────
139
- /**
140
- * Reduce entries, optionally filtered by a set of runtimeStageIds.
141
- * For time-travel progressive view: pass the runtimeStageIds visible at the current slider position.
142
- * Entries without runtimeStageId (structural markers) are excluded when keys are provided.
143
- * Without keys, reduces all entries (same as aggregate).
144
- */
145
- accumulate(fn, initial, keys) {
146
- let acc = initial;
147
- for (const entry of this.entries) {
148
- if (keys) {
149
- if (!entry.runtimeStageId || !keys.has(entry.runtimeStageId))
150
- continue;
151
- }
152
- acc = fn(acc, entry);
153
- }
154
- return acc;
155
- }
156
- // ── Time-travel queries ───────────────────────────────────────────────
157
- /**
158
- * Progressive reveal: entries whose runtimeStageId is in the visible set.
159
- * Preserves insertion order. Entries without runtimeStageId (structural markers)
160
- * are buffered and included only when surrounded by visible steps on both sides —
161
- * trailing markers after the last visible step are discarded.
162
- */
163
- getEntriesUpTo(visibleIds) {
164
- const result = [];
165
- let pendingMarkers = [];
166
- for (const entry of this.entries) {
167
- const id = entry.runtimeStageId;
168
- if (!id) {
169
- // Structural marker — buffer until next visible keyed entry confirms it's between visible steps.
170
- if (result.length > 0)
171
- pendingMarkers.push(entry);
172
- }
173
- else if (visibleIds.has(id)) {
174
- // Flush buffered markers — they sit between a previous visible step and this one.
175
- if (pendingMarkers.length > 0) {
176
- result.push(...pendingMarkers);
177
- pendingMarkers = [];
178
- }
179
- result.push(entry);
180
- }
181
- // Non-visible keyed entries: don't discard pending markers — a later visible entry
182
- // may still flush them. Markers are only discarded at the end (trailing).
183
- }
184
- // Discard remaining pendingMarkers — they trail the last visible step.
185
- return result;
186
- }
187
- // ── Lifecycle ─────────────────────────────────────────────────────────
188
- /** Clear all stored data. Called by executor before each run(). */
189
- clear() {
190
- this.entries.length = 0;
191
- this.byRuntimeStageId.clear();
192
- this.entryRanges.clear();
193
- this.lastEmittedId = undefined;
194
- }
195
- }
196
- exports.SequenceRecorder = SequenceRecorder;
197
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VxdWVuY2VSZWNvcmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvcmVjb3JkZXIvU2VxdWVuY2VSZWNvcmRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVERztBQUNILE1BQXNCLGdCQUFnQjtJQUdwQyx5REFBeUQ7SUFDeEMsT0FBTyxHQUFRLEVBQUUsQ0FBQztJQUNuQyx5RkFBeUY7SUFDeEUsZ0JBQWdCLEdBQUcsSUFBSSxHQUFHLEVBQWUsQ0FBQztJQUMzRDttR0FDK0Y7SUFDOUUsV0FBVyxHQUFHLElBQUksR0FBRyxFQUFnRCxDQUFDO0lBQ3ZGLCtHQUErRztJQUN2RyxhQUFhLENBQXFCO0lBRTFDLHlFQUF5RTtJQUV6RTs7O09BR0c7SUFDTyxJQUFJLENBQUMsS0FBUTtRQUNyQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztRQUNoQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN6QixNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsY0FBYyxDQUFDO1FBQ2hDLElBQUksRUFBRSxFQUFFLENBQUM7WUFDUCxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3hDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDVCxHQUFHLEdBQUcsRUFBRSxDQUFDO2dCQUNULElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUNuQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxHQUFHLEdBQUcsQ0FBQyxFQUFF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RSxFQUFFLENBQUM7Z0JBQ1IsaUdBQWlHO2dCQUNqRyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQztvQkFBRSxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3BELENBQUM7aUJBQU0sSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7Z0JBQzlCLGtGQUFrRjtnQkFDbEYsSUFBSSxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUM5QixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsY0FBYyxDQUFDLENBQUM7b0JBQy9CLGNBQWMsR0FBRyxFQUFFLENBQUM7Z0JBQ3RCLENBQUM7Z0JBQ0QsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNyQixDQUFDO1lBQ0QsbUZBQW1GO1lBQ25GLDBFQUEwRTtRQUM1RSxDQUFDO1FBQ0QsdUVBQXVFO1FBQ3ZFLE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFFRCx5RUFBeUU7SUFFekUsbUVBQW1FO0lBQ25FLEtBQUs7UUFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFDeEIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzlCLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLGFBQWEsR0FBRyxTQUFTLENBQUM7SUFDakMsQ0FBQztDQUNGO0FBdEpELDRDQXNKQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2VxdWVuY2VSZWNvcmRlcjxUPiDigJQgYmFzZSBjbGFzcyBmb3Igb3JkZXJlZCBzZXF1ZW5jZSByZWNvcmRlcnMgd2l0aCBrZXllZCBpbmRleC5cbiAqXG4gKiBQcm92aWRlcyBkdWFsLWluZGV4ZWQgc3RvcmFnZTogYSBmbGF0IGFycmF5IHByZXNlcnZpbmcgaW5zZXJ0aW9uIG9yZGVyIHBsdXMgYVxuICogTWFwPHJ1bnRpbWVTdGFnZUlkLCBUW10+IGZvciBPKDEpIHBlci1zdGVwIGxvb2t1cC4gT25lIGVudHJ5IHR5cGUsIG11bHRpcGxlIGVudHJpZXNcbiAqIHBlciBzdGVwLiBEZXNpZ25lZCBmb3IgcmVjb3JkZXJzIHRoYXQgaW1wbGVtZW50IEJPVEggU2NvcGVSZWNvcmRlciBhbmQgRmxvd1JlY29yZGVyXG4gKiAobWVyZ2luZyBkYXRhIG9wcyBhbmQgY29udHJvbCBmbG93IGludG8gYSBzaW5nbGUgaW50ZXJsZWF2ZWQgc2VxdWVuY2UpLlxuICpcbiAqICoqQ29udHJhc3Qgd2l0aCBLZXllZFJlY29yZGVyPFQ+OioqXG4gKiAtIGBLZXllZFJlY29yZGVyPFQ+YCDigJQgMToxIE1hcC4gT25lIGVudHJ5IHBlciBydW50aW1lU3RhZ2VJZC4gRm9yIHNpbmdsZS12YWx1ZSByZWNvcmRlcnNcbiAqICAgbGlrZSBNZXRyaWNSZWNvcmRlciAob25lIFN0ZXBNZXRyaWNzIHBlciBzdGFnZSBleGVjdXRpb24pLlxuICogLSBgU2VxdWVuY2VSZWNvcmRlcjxUPmAg4oCUIDE6TiBzZXF1ZW5jZSArIE1hcC4gTXVsdGlwbGUgZW50cmllcyBwZXIgcnVudGltZVN0YWdlSWQsXG4gKiAgIHBsdXMgb3JkZXJpbmcgbWF0dGVycy4gRm9yIHJlY29yZGVycyB0aGF0IHByb2R1Y2UgYSBwcm9zZSBuYXJyYXRpdmUgb3IgZXZlbnQgbG9nXG4gKiAgIHdoZXJlIGEgc2luZ2xlIHN0ZXAgZ2VuZXJhdGVzIHN0YWdlICsgZGF0YSArIGRlY2lzaW9uIGVudHJpZXMuXG4gKlxuICogKipIb3cgdG8gY2hvb3NlOioqXG4gKiAtIElmIGVhY2ggc3RlcCBwcm9kdWNlcyBleGFjdGx5IG9uZSByZWNvcmQg4oaSIGV4dGVuZCBgS2V5ZWRSZWNvcmRlcjxUPmBcbiAqIC0gSWYgZWFjaCBzdGVwIHByb2R1Y2VzIG11bHRpcGxlIHJlY29yZHMgb3Igb3JkZXJpbmcgbWF0dGVycyDihpIgZXh0ZW5kIGBTZXF1ZW5jZVJlY29yZGVyPFQ+YFxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBTZXF1ZW5jZVJlY29yZGVyIH0gZnJvbSAnZm9vdHByaW50anMvdHJhY2UnO1xuICpcbiAqIGludGVyZmFjZSBBdWRpdEVudHJ5IHtcbiAqICAgcnVudGltZVN0YWdlSWQ/OiBzdHJpbmc7XG4gKiAgIHR5cGU6ICdyZWFkJyB8ICd3cml0ZScgfCAnZGVjaXNpb24nO1xuICogICBkZXRhaWw6IHN0cmluZztcbiAqIH1cbiAqXG4gKiBjbGFzcyBBdWRpdFJlY29yZGVyIGV4dGVuZHMgU2VxdWVuY2VSZWNvcmRlcjxBdWRpdEVudHJ5PiB7XG4gKiAgIHJlYWRvbmx5IGlkID0gJ2F1ZGl0JztcbiAqXG4gKiAgIC8vIFNjb3BlIGhvb2tzIChmaXJlcyBkdXJpbmcgc3RhZ2UgZXhlY3V0aW9uKVxuICogICBvblJlYWQoZXZlbnQ6IFJlYWRFdmVudCkge1xuICogICAgIHRoaXMuZW1pdCh7IHJ1bnRpbWVTdGFnZUlkOiBldmVudC5ydW50aW1lU3RhZ2VJZCwgdHlwZTogJ3JlYWQnLCBkZXRhaWw6IGV2ZW50LmtleSB9KTtcbiAqICAgfVxuICogICBvbldyaXRlKGV2ZW50OiBXcml0ZUV2ZW50KSB7XG4gKiAgICAgdGhpcy5lbWl0KHsgcnVudGltZVN0YWdlSWQ6IGV2ZW50LnJ1bnRpbWVTdGFnZUlkLCB0eXBlOiAnd3JpdGUnLCBkZXRhaWw6IGV2ZW50LmtleSB9KTtcbiAqICAgfVxuICpcbiAqICAgLy8gRmxvdyBob29rcyAoZmlyZXMgYWZ0ZXIgc3RhZ2UgZXhlY3V0aW9uKVxuICogICBvbkRlY2lzaW9uKGV2ZW50OiBGbG93RGVjaXNpb25FdmVudCkge1xuICogICAgIHRoaXMuZW1pdCh7XG4gKiAgICAgICBydW50aW1lU3RhZ2VJZDogZXZlbnQudHJhdmVyc2FsQ29udGV4dD8ucnVudGltZVN0YWdlSWQsXG4gKiAgICAgICB0eXBlOiAnZGVjaXNpb24nLFxuICogICAgICAgZGV0YWlsOiBgJHtldmVudC5kZWNpZGVyfSBjaG9zZSAke2V2ZW50LmNob3Nlbn1gLFxuICogICAgIH0pO1xuICogICB9XG4gKlxuICogICAvLyBUaW1lLXRyYXZlbDogZW50cmllcyB1cCB0byBzbGlkZXIgcG9zaXRpb25cbiAqICAgZ2V0QXVkaXRVcFRvKHZpc2libGVJZHM6IFJlYWRvbmx5U2V0PHN0cmluZz4pIHtcbiAqICAgICByZXR1cm4gdGhpcy5nZXRFbnRyaWVzVXBUbyh2aXNpYmxlSWRzKTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBTZXF1ZW5jZVJlY29yZGVyPFQgZXh0ZW5kcyB7IHJ1bnRpbWVTdGFnZUlkPzogc3RyaW5nIH0+IHtcbiAgYWJzdHJhY3QgcmVhZG9ubHkgaWQ6IHN0cmluZztcblxuICAvKiogT3JkZXJlZCBzZXF1ZW5jZSBvZiBhbGwgZW50cmllcyAoaW5zZXJ0aW9uIG9yZGVyKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBlbnRyaWVzOiBUW10gPSBbXTtcbiAgLyoqIFBlci1zdGVwIGluZGV4OiBydW50aW1lU3RhZ2VJZCDihpIgZW50cmllcyBmb3IgdGhhdCBzdGVwLiBTYW1lIG9iamVjdHMgYXMgZW50cmllc1tdLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGJ5UnVudGltZVN0YWdlSWQgPSBuZXcgTWFwPHN0cmluZywgVFtdPigpO1xuICAvKiogUGVyLXN0ZXAgcmFuZ2UgaW5kZXg6IHJ1bnRpbWVTdGFnZUlkIOKGkiBbZmlyc3RJZHgsIGVuZElkeCkgaW4gZW50cmllcyBhcnJheS5cbiAgICogIGVuZElkeCBpbmNsdWRlcyB0cmFpbGluZyBrZXlsZXNzIGVudHJpZXMgKHN0cnVjdHVyYWwgbWFya2VycykuIE1haW50YWluZWQgZHVyaW5nIGVtaXQoKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBlbnRyeVJhbmdlcyA9IG5ldyBNYXA8c3RyaW5nLCB7IGZpcnN0SWR4OiBudW1iZXI7IGVuZElkeDogbnVtYmVyIH0+KCk7XG4gIC8qKiBUaGUgcnVudGltZVN0YWdlSWQgb2YgdGhlIG1vc3QgcmVjZW50bHkgZW1pdHRlZCBrZXllZCBlbnRyeS4gVXNlZCB0byBleHRlbmQgcmFuZ2VzIGZvciB0cmFpbGluZyBtYXJrZXJzLiAqL1xuICBwcml2YXRlIGxhc3RFbWl0dGVkSWQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAvLyDilIDilIAgV3JpdGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIEFwcGVuZCBhbiBlbnRyeSB0byBib3RoIHRoZSBvcmRlcmVkIHNlcXVlbmNlLCBrZXllZCBpbmRleCwgYW5kIHJhbmdlIGluZGV4LlxuICAgKiBBbGwgcmVmZXJlbmNlIHRoZSBzYW1lIGVudHJ5IG9iamVjdCDigJQgbm8gZHVwbGljYXRpb24uXG4gICAqL1xuICBwcm90ZWN0ZWQgZW1pdChlbnRyeTogVCk6IHZvaWQge1xuICAgIGNvbnN0IGlkeCA9IHRoaXMuZW50cmllcy5sZW5ndGg7XG4gICAgdGhpcy5lbnRyaWVzLnB1c2goZW50cnkpO1xuICAgIGNvbnN0IGlkID0gZW50cnkucnVudGltZVN0YWdlSWQ7XG4gICAgaWYgKGlkKSB7XG4gICAgICBsZXQgYXJyID0gdGhpcy5ieVJ1bnRpbWVTdGFnZUlkLmdldChpZCk7XG4gICAgICBpZiAoIWFycikge1xuICAgICAgICBhcnIgPSBbXTtcbiAgICAgICAgdGhpcy5ieVJ1bnRpbWVTdGFnZUlkLnNldChpZCwgYXJyKTtcbiAgICAgICAgdGhpcy5lbnRyeVJhbmdlcy5zZXQoaWQsIHsgZmlyc3RJZHg6IGlkeCwgZW5kSWR4OiBpZHggKyAxIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5lbnRyeVJhbmdlcy5nZXQoaWQpIS5lbmRJZHggPSBpZHggKyAxO1xuICAgICAgfVxuICAgICAgYXJyLnB1c2goZW50cnkpO1xuICAgICAgdGhpcy5sYXN0RW1pdHRlZElkID0gaWQ7XG4gICAgfSBlbHNlIGlmICh0aGlzLmxhc3RFbWl0dGVkSWQpIHtcbiAgICAgIC8vIFN0cnVjdHVyYWwgbWFya2VyIChubyBydW50aW1lU3RhZ2VJZCkg4oCUIGV4dGVuZCB0aGUgcHJlY2VkaW5nIHN0ZXAncyByYW5nZVxuICAgICAgdGhpcy5lbnRyeVJhbmdlcy5nZXQodGhpcy5sYXN0RW1pdHRlZElkKSEuZW5kSWR4ID0gaWR4ICsgMTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgT3JkZXJlZCBhY2Nlc3Mg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIEFsbCBlbnRyaWVzIGluIGluc2VydGlvbiBvcmRlciAocmV0dXJucyBhIHNoYWxsb3cgY29weSDigJQgZW50cnkgb2JqZWN0cyBhcmUgc2hhcmVkKS4gKi9cbiAgZ2V0RW50cmllcygpOiBUW10ge1xuICAgIHJldHVybiBbLi4udGhpcy5lbnRyaWVzXTtcbiAgfVxuXG4gIC8qKiBOdW1iZXIgb2YgZW50cmllcyBpbiB0aGUgc2VxdWVuY2UuICovXG4gIGdldCBlbnRyeUNvdW50KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuZW50cmllcy5sZW5ndGg7XG4gIH1cblxuICAvKiogWmVyby1jb3B5IGl0ZXJhdGlvbiBmb3Igc3ViY2xhc3MgcmVuZGVyaW5nIG1ldGhvZHMgKGF2b2lkcyBnZXRFbnRyaWVzKCkgc3ByZWFkKS4gKi9cbiAgcHJvdGVjdGVkIGZvckVhY2hFbnRyeShmbjogKGVudHJ5OiBUKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiB0aGlzLmVudHJpZXMpIHtcbiAgICAgIGZuKGVudHJ5KTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgS2V5ZWQgYWNjZXNzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBPKDEpIGxvb2t1cDogYWxsIGVudHJpZXMgZm9yIGEgc3BlY2lmaWMgZXhlY3V0aW9uIHN0ZXAgKHJldHVybnMgYSBjb3B5KS4gKi9cbiAgZ2V0RW50cmllc0ZvclN0ZXAocnVudGltZVN0YWdlSWQ6IHN0cmluZyk6IFRbXSB7XG4gICAgcmV0dXJuIFsuLi4odGhpcy5ieVJ1bnRpbWVTdGFnZUlkLmdldChydW50aW1lU3RhZ2VJZCkgPz8gW10pXTtcbiAgfVxuXG4gIC8qKiBOdW1iZXIgb2YgdW5pcXVlIGV4ZWN1dGlvbiBzdGVwcyB0aGF0IGhhdmUgZW50cmllcy4gKi9cbiAgZ2V0IHN0ZXBDb3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmJ5UnVudGltZVN0YWdlSWQuc2l6ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcmUtYnVpbHQgcmFuZ2UgaW5kZXg6IHJ1bnRpbWVTdGFnZUlkIOKGkiBoYWxmLW9wZW4gcmFuZ2UgW2ZpcnN0SWR4LCBlbmRJZHgpIGluIGVudHJpZXMgYXJyYXkuXG4gICAqIE1haW50YWluZWQgZHVyaW5nIGVtaXQoKSDigJQgbm8gcmVidWlsZCBuZWVkZWQuIFVzZSBmb3IgTygxKSBwZXItc3RlcCBsb29rdXBzIGR1cmluZyB0aW1lLXRyYXZlbC5cbiAgICogZW5kSWR4IGluY2x1ZGVzIHRyYWlsaW5nIGtleWxlc3MgZW50cmllcyAoc3RydWN0dXJhbCBtYXJrZXJzIGZvbGxvd2luZyBhIHN0ZXApLlxuICAgKi9cbiAgZ2V0RW50cnlSYW5nZXMoKTogUmVhZG9ubHlNYXA8c3RyaW5nLCB7IHJlYWRvbmx5IGZpcnN0SWR4OiBudW1iZXI7IHJlYWRvbmx5IGVuZElkeDogbnVtYmVyIH0+IHtcbiAgICByZXR1cm4gdGhpcy5lbnRyeVJhbmdlcztcbiAgfVxuXG4gIC8vIOKUgOKUgCBBZ2dyZWdhdGUgKHJlZHVjZSBhbGwgZW50cmllcykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFJlZHVjZSBBTEwgZW50cmllcyB0byBhIHNpbmdsZSB2YWx1ZS4gRm9yIGRhc2hib2FyZHMsIHRvdGFscywgc3VtbWFyaWVzLiAqL1xuICBhZ2dyZWdhdGU8Uj4oZm46IChhY2M6IFIsIGVudHJ5OiBUKSA9PiBSLCBpbml0aWFsOiBSKTogUiB7XG4gICAgbGV0IGFjYyA9IGluaXRpYWw7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiB0aGlzLmVudHJpZXMpIHtcbiAgICAgIGFjYyA9IGZuKGFjYywgZW50cnkpO1xuICAgIH1cbiAgICByZXR1cm4gYWNjO1xuICB9XG5cbiAgLy8g4pSA4pSAIEFjY3VtdWxhdGUgKHByb2dyZXNzaXZlIHJlZHVjZSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFJlZHVjZSBlbnRyaWVzLCBvcHRpb25hbGx5IGZpbHRlcmVkIGJ5IGEgc2V0IG9mIHJ1bnRpbWVTdGFnZUlkcy5cbiAgICogRm9yIHRpbWUtdHJhdmVsIHByb2dyZXNzaXZlIHZpZXc6IHBhc3MgdGhlIHJ1bnRpbWVTdGFnZUlkcyB2aXNpYmxlIGF0IHRoZSBjdXJyZW50IHNsaWRlciBwb3NpdGlvbi5cbiAgICogRW50cmllcyB3aXRob3V0IHJ1bnRpbWVTdGFnZUlkIChzdHJ1Y3R1cmFsIG1hcmtlcnMpIGFyZSBleGNsdWRlZCB3aGVuIGtleXMgYXJlIHByb3ZpZGVkLlxuICAgKiBXaXRob3V0IGtleXMsIHJlZHVjZXMgYWxsIGVudHJpZXMgKHNhbWUgYXMgYWdncmVnYXRlKS5cbiAgICovXG4gIGFjY3VtdWxhdGU8Uj4oZm46IChhY2M6IFIsIGVudHJ5OiBUKSA9PiBSLCBpbml0aWFsOiBSLCBrZXlzPzogUmVhZG9ubHlTZXQ8c3RyaW5nPik6IFIge1xuICAgIGxldCBhY2MgPSBpbml0aWFsO1xuICAgIGZvciAoY29uc3QgZW50cnkgb2YgdGhpcy5lbnRyaWVzKSB7XG4gICAgICBpZiAoa2V5cykge1xuICAgICAgICBpZiAoIWVudHJ5LnJ1bnRpbWVTdGFnZUlkIHx8ICFrZXlzLmhhcyhlbnRyeS5ydW50aW1lU3RhZ2VJZCkpIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgYWNjID0gZm4oYWNjLCBlbnRyeSk7XG4gICAgfVxuICAgIHJldHVybiBhY2M7XG4gIH1cblxuICAvLyDilIDilIAgVGltZS10cmF2ZWwgcXVlcmllcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKipcbiAgICogUHJvZ3Jlc3NpdmUgcmV2ZWFsOiBlbnRyaWVzIHdob3NlIHJ1bnRpbWVTdGFnZUlkIGlzIGluIHRoZSB2aXNpYmxlIHNldC5cbiAgICogUHJlc2VydmVzIGluc2VydGlvbiBvcmRlci4gRW50cmllcyB3aXRob3V0IHJ1bnRpbWVTdGFnZUlkIChzdHJ1Y3R1cmFsIG1hcmtlcnMpXG4gICAqIGFyZSBidWZmZXJlZCBhbmQgaW5jbHVkZWQgb25seSB3aGVuIHN1cnJvdW5kZWQgYnkgdmlzaWJsZSBzdGVwcyBvbiBib3RoIHNpZGVzIOKAlFxuICAgKiB0cmFpbGluZyBtYXJrZXJzIGFmdGVyIHRoZSBsYXN0IHZpc2libGUgc3RlcCBhcmUgZGlzY2FyZGVkLlxuICAgKi9cbiAgZ2V0RW50cmllc1VwVG8odmlzaWJsZUlkczogUmVhZG9ubHlTZXQ8c3RyaW5nPik6IFRbXSB7XG4gICAgY29uc3QgcmVzdWx0OiBUW10gPSBbXTtcbiAgICBsZXQgcGVuZGluZ01hcmtlcnM6IFRbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgZW50cnkgb2YgdGhpcy5lbnRyaWVzKSB7XG4gICAgICBjb25zdCBpZCA9IGVudHJ5LnJ1bnRpbWVTdGFnZUlkO1xuICAgICAgaWYgKCFpZCkge1xuICAgICAgICAvLyBTdHJ1Y3R1cmFsIG1hcmtlciDigJQgYnVmZmVyIHVudGlsIG5leHQgdmlzaWJsZSBrZXllZCBlbnRyeSBjb25maXJtcyBpdCdzIGJldHdlZW4gdmlzaWJsZSBzdGVwcy5cbiAgICAgICAgaWYgKHJlc3VsdC5sZW5ndGggPiAwKSBwZW5kaW5nTWFya2Vycy5wdXNoKGVudHJ5KTtcbiAgICAgIH0gZWxzZSBpZiAodmlzaWJsZUlkcy5oYXMoaWQpKSB7XG4gICAgICAgIC8vIEZsdXNoIGJ1ZmZlcmVkIG1hcmtlcnMg4oCUIHRoZXkgc2l0IGJldHdlZW4gYSBwcmV2aW91cyB2aXNpYmxlIHN0ZXAgYW5kIHRoaXMgb25lLlxuICAgICAgICBpZiAocGVuZGluZ01hcmtlcnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIHJlc3VsdC5wdXNoKC4uLnBlbmRpbmdNYXJrZXJzKTtcbiAgICAgICAgICBwZW5kaW5nTWFya2VycyA9IFtdO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdC5wdXNoKGVudHJ5KTtcbiAgICAgIH1cbiAgICAgIC8vIE5vbi12aXNpYmxlIGtleWVkIGVudHJpZXM6IGRvbid0IGRpc2NhcmQgcGVuZGluZyBtYXJrZXJzIOKAlCBhIGxhdGVyIHZpc2libGUgZW50cnlcbiAgICAgIC8vIG1heSBzdGlsbCBmbHVzaCB0aGVtLiBNYXJrZXJzIGFyZSBvbmx5IGRpc2NhcmRlZCBhdCB0aGUgZW5kICh0cmFpbGluZykuXG4gICAgfVxuICAgIC8vIERpc2NhcmQgcmVtYWluaW5nIHBlbmRpbmdNYXJrZXJzIOKAlCB0aGV5IHRyYWlsIHRoZSBsYXN0IHZpc2libGUgc3RlcC5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLy8g4pSA4pSAIExpZmVjeWNsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogQ2xlYXIgYWxsIHN0b3JlZCBkYXRhLiBDYWxsZWQgYnkgZXhlY3V0b3IgYmVmb3JlIGVhY2ggcnVuKCkuICovXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIHRoaXMuZW50cmllcy5sZW5ndGggPSAwO1xuICAgIHRoaXMuYnlSdW50aW1lU3RhZ2VJZC5jbGVhcigpO1xuICAgIHRoaXMuZW50cnlSYW5nZXMuY2xlYXIoKTtcbiAgICB0aGlzLmxhc3RFbWl0dGVkSWQgPSB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==