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