footprintjs 9.48.2 → 10.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.
- package/AGENTS.md +12 -10
- package/CLAUDE.md +21 -23
- package/README.md +1 -1
- package/dist/advanced.js +71 -128
- package/dist/esm/advanced.d.ts +24 -58
- package/dist/esm/advanced.js +13 -51
- package/dist/esm/index.d.ts +5 -8
- package/dist/esm/index.js +3 -3
- package/dist/esm/lib/builder/FlowChartBuilder.d.ts +1 -1
- package/dist/esm/lib/builder/FlowChartBuilder.js +3 -3
- package/dist/esm/lib/builder/structure/StructureRecorder.d.ts +1 -1
- package/dist/esm/lib/builder/structure/StructureRecorder.js +1 -1
- package/dist/esm/lib/capture/index.d.ts +0 -1
- package/dist/esm/lib/capture/index.js +1 -2
- package/dist/esm/lib/engine/graph/prefixNodeTree.js +2 -2
- package/dist/esm/lib/engine/handlers/ResumeEntry.d.ts +3 -3
- package/dist/esm/lib/engine/handlers/ResumeEntry.js +4 -4
- package/dist/esm/lib/engine/handlers/SubflowExecutor.d.ts +1 -2
- package/dist/esm/lib/engine/handlers/SubflowExecutor.js +4 -8
- package/dist/esm/lib/engine/index.d.ts +1 -1
- package/dist/esm/lib/engine/index.js +1 -1
- package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +4 -4
- package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +1 -1
- package/dist/esm/lib/engine/narrative/index.d.ts +1 -1
- package/dist/esm/lib/engine/narrative/index.js +1 -1
- package/dist/esm/lib/engine/narrative/narrativeTypes.d.ts +1 -11
- package/dist/esm/lib/engine/narrative/narrativeTypes.js +1 -1
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.d.ts +2 -10
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +4 -6
- package/dist/esm/lib/engine/traversalContext.d.ts +1 -1
- package/dist/esm/lib/engine/traversalContext.js +2 -2
- package/dist/esm/lib/engine/types.d.ts +2 -10
- package/dist/esm/lib/engine/types.js +1 -1
- package/dist/esm/lib/engine/walkSubflowSpec.js +2 -2
- package/dist/esm/lib/ids/reservedIds.js +2 -2
- package/dist/esm/lib/memory/DiagnosticCollector.js +2 -2
- package/dist/esm/lib/memory/StageContext.d.ts +2 -4
- package/dist/esm/lib/memory/StageContext.js +2 -2
- package/dist/esm/lib/memory/borrowedMutation.js +2 -2
- package/dist/esm/lib/memory/index.d.ts +6 -21
- package/dist/esm/lib/memory/index.js +4 -22
- package/dist/esm/lib/memory/redaction.d.ts +1 -1
- package/dist/esm/lib/memory/redaction.js +2 -2
- package/dist/esm/lib/memory/runPolicy.d.ts +3 -2
- package/dist/esm/lib/memory/runPolicy.js +1 -1
- package/dist/esm/lib/reactive/createTypedScope.js +2 -2
- package/dist/esm/lib/reactive/writeTraps.js +2 -2
- package/dist/esm/lib/recorder/ControlDepRecorder.d.ts +3 -2
- package/dist/esm/lib/recorder/ControlDepRecorder.js +3 -2
- package/dist/esm/lib/recorder/EmitRecorder.d.ts +1 -1
- package/dist/esm/lib/recorder/EmitRecorder.js +1 -1
- package/dist/esm/lib/recorder/InOutRecorder.js +2 -2
- package/dist/esm/lib/recorder/qualityTrace.d.ts +1 -1
- package/dist/esm/lib/recorder/qualityTrace.js +2 -2
- package/dist/esm/lib/runner/DeferredObserverTier.js +2 -2
- package/dist/esm/lib/runner/ExecutionRuntime.d.ts +4 -5
- package/dist/esm/lib/runner/ExecutionRuntime.js +2 -5
- package/dist/esm/lib/runner/FlowChartExecutor.d.ts +1 -1
- package/dist/esm/lib/runner/FlowChartExecutor.js +1 -1
- package/dist/esm/lib/runner/getSubtreeSnapshot.d.ts +1 -1
- package/dist/esm/lib/runner/getSubtreeSnapshot.js +4 -4
- package/dist/esm/lib/runner/resume.js +2 -2
- package/dist/esm/lib/runner/snapshot.js +3 -2
- package/dist/esm/lib/scope/ScopeFacade.js +2 -2
- package/dist/esm/lib/scope/state/zod/scopeFactory.js +2 -2
- package/dist/esm/recorders.d.ts +2 -3
- package/dist/esm/recorders.js +1 -1
- package/dist/esm/trace.d.ts +11 -57
- package/dist/esm/trace.js +10 -68
- package/dist/index.js +3 -3
- package/dist/lib/builder/FlowChartBuilder.js +5 -5
- package/dist/lib/builder/structure/StructureRecorder.js +1 -1
- package/dist/lib/capture/index.js +2 -4
- package/dist/lib/engine/graph/prefixNodeTree.js +5 -5
- package/dist/lib/engine/handlers/ResumeEntry.js +4 -4
- package/dist/lib/engine/handlers/SubflowExecutor.js +5 -9
- package/dist/lib/engine/index.js +1 -1
- package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +1 -1
- package/dist/lib/engine/narrative/index.js +1 -1
- package/dist/lib/engine/narrative/narrativeTypes.js +1 -1
- package/dist/lib/engine/traversal/FlowchartTraverser.js +8 -10
- package/dist/lib/engine/traversalContext.js +4 -4
- package/dist/lib/engine/types.js +1 -1
- package/dist/lib/engine/walkSubflowSpec.js +3 -3
- package/dist/lib/ids/reservedIds.js +5 -5
- package/dist/lib/memory/DiagnosticCollector.js +3 -3
- package/dist/lib/memory/StageContext.js +3 -3
- package/dist/lib/memory/borrowedMutation.js +3 -3
- package/dist/lib/memory/index.js +7 -42
- package/dist/lib/memory/redaction.js +3 -3
- package/dist/lib/memory/runPolicy.js +1 -1
- package/dist/lib/reactive/createTypedScope.js +3 -3
- package/dist/lib/reactive/writeTraps.js +4 -4
- package/dist/lib/recorder/ControlDepRecorder.js +3 -2
- package/dist/lib/recorder/EmitRecorder.js +1 -1
- package/dist/lib/recorder/InOutRecorder.js +3 -3
- package/dist/lib/recorder/qualityTrace.js +4 -4
- package/dist/lib/runner/DeferredObserverTier.js +3 -3
- package/dist/lib/runner/ExecutionRuntime.js +6 -9
- package/dist/lib/runner/FlowChartExecutor.js +1 -1
- package/dist/lib/runner/getSubtreeSnapshot.js +6 -6
- package/dist/lib/runner/resume.js +3 -3
- package/dist/lib/runner/snapshot.js +6 -5
- package/dist/lib/scope/ScopeFacade.js +3 -3
- package/dist/lib/scope/state/zod/scopeFactory.js +4 -4
- package/dist/recorders.js +1 -1
- package/dist/trace.js +18 -120
- package/dist/types/advanced.d.ts +24 -58
- package/dist/types/index.d.ts +5 -8
- package/dist/types/lib/builder/FlowChartBuilder.d.ts +1 -1
- package/dist/types/lib/builder/structure/StructureRecorder.d.ts +1 -1
- package/dist/types/lib/capture/index.d.ts +0 -1
- package/dist/types/lib/engine/handlers/ResumeEntry.d.ts +3 -3
- package/dist/types/lib/engine/handlers/SubflowExecutor.d.ts +1 -2
- package/dist/types/lib/engine/index.d.ts +1 -1
- package/dist/types/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +4 -4
- package/dist/types/lib/engine/narrative/index.d.ts +1 -1
- package/dist/types/lib/engine/narrative/narrativeTypes.d.ts +1 -11
- package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +2 -10
- package/dist/types/lib/engine/traversalContext.d.ts +1 -1
- package/dist/types/lib/engine/types.d.ts +2 -10
- package/dist/types/lib/memory/StageContext.d.ts +2 -4
- package/dist/types/lib/memory/index.d.ts +6 -21
- package/dist/types/lib/memory/redaction.d.ts +1 -1
- package/dist/types/lib/memory/runPolicy.d.ts +3 -2
- package/dist/types/lib/recorder/ControlDepRecorder.d.ts +3 -2
- package/dist/types/lib/recorder/EmitRecorder.d.ts +1 -1
- package/dist/types/lib/recorder/qualityTrace.d.ts +1 -1
- package/dist/types/lib/runner/ExecutionRuntime.d.ts +4 -5
- package/dist/types/lib/runner/FlowChartExecutor.d.ts +1 -1
- package/dist/types/lib/runner/getSubtreeSnapshot.d.ts +1 -1
- package/dist/types/recorders.d.ts +2 -3
- package/dist/types/trace.d.ts +11 -57
- package/package.json +6 -15
- package/dist/esm/lib/capture/freeze.d.ts +0 -91
- package/dist/esm/lib/capture/freeze.js +0 -314
- package/dist/esm/lib/capture/ownData.d.ts +0 -7
- package/dist/esm/lib/capture/ownData.js +0 -15
- package/dist/esm/lib/capture/valueKinds.d.ts +0 -57
- package/dist/esm/lib/capture/valueKinds.js +0 -142
- package/dist/esm/lib/ids/runtimeStageId.d.ts +0 -173
- package/dist/esm/lib/ids/runtimeStageId.js +0 -194
- package/dist/esm/lib/memory/EventLog.d.ts +0 -105
- package/dist/esm/lib/memory/EventLog.js +0 -148
- package/dist/esm/lib/memory/RecordFrame.d.ts +0 -232
- package/dist/esm/lib/memory/RecordFrame.js +0 -296
- package/dist/esm/lib/memory/SharedMemory.d.ts +0 -46
- package/dist/esm/lib/memory/SharedMemory.js +0 -88
- package/dist/esm/lib/memory/TransactionBuffer.d.ts +0 -521
- package/dist/esm/lib/memory/TransactionBuffer.js +0 -946
- package/dist/esm/lib/memory/admission.d.ts +0 -81
- package/dist/esm/lib/memory/admission.js +0 -153
- package/dist/esm/lib/memory/backtrack.d.ts +0 -286
- package/dist/esm/lib/memory/backtrack.js +0 -457
- package/dist/esm/lib/memory/commitLogUtils.d.ts +0 -217
- package/dist/esm/lib/memory/commitLogUtils.js +0 -384
- package/dist/esm/lib/memory/deltaEncoding.d.ts +0 -66
- package/dist/esm/lib/memory/deltaEncoding.js +0 -122
- package/dist/esm/lib/memory/equality.d.ts +0 -93
- package/dist/esm/lib/memory/equality.js +0 -262
- package/dist/esm/lib/memory/eventPosition.d.ts +0 -18
- package/dist/esm/lib/memory/eventPosition.js +0 -2
- package/dist/esm/lib/memory/honesty.d.ts +0 -93
- package/dist/esm/lib/memory/honesty.js +0 -92
- package/dist/esm/lib/memory/keyPaths.d.ts +0 -125
- package/dist/esm/lib/memory/keyPaths.js +0 -227
- package/dist/esm/lib/memory/logModel.d.ts +0 -76
- package/dist/esm/lib/memory/logModel.js +0 -364
- package/dist/esm/lib/memory/merge.d.ts +0 -26
- package/dist/esm/lib/memory/merge.js +0 -60
- package/dist/esm/lib/memory/pathOps.d.ts +0 -115
- package/dist/esm/lib/memory/pathOps.js +0 -290
- package/dist/esm/lib/memory/paths.d.ts +0 -52
- package/dist/esm/lib/memory/paths.js +0 -57
- package/dist/esm/lib/memory/placeholders.d.ts +0 -39
- package/dist/esm/lib/memory/placeholders.js +0 -40
- package/dist/esm/lib/memory/recordCommit.d.ts +0 -45
- package/dist/esm/lib/memory/recordCommit.js +0 -61
- package/dist/esm/lib/memory/scrub.d.ts +0 -53
- package/dist/esm/lib/memory/scrub.js +0 -74
- package/dist/esm/lib/memory/types.d.ts +0 -209
- package/dist/esm/lib/memory/types.js +0 -10
- package/dist/esm/lib/memory/utils.d.ts +0 -73
- package/dist/esm/lib/memory/utils.js +0 -159
- package/dist/esm/lib/memory/verbs.d.ts +0 -333
- package/dist/esm/lib/memory/verbs.js +0 -427
- package/dist/esm/lib/recorder/CommitRangeIndex.d.ts +0 -147
- package/dist/esm/lib/recorder/CommitRangeIndex.js +0 -207
- package/dist/esm/lib/scope/detectCircular.d.ts +0 -13
- package/dist/esm/lib/scope/detectCircular.js +0 -14
- package/dist/esm/lib/scope/recorders/summarizeValue.d.ts +0 -5
- package/dist/esm/lib/scope/recorders/summarizeValue.js +0 -6
- package/dist/esm/lib/slice/elementProvenance.d.ts +0 -81
- package/dist/esm/lib/slice/elementProvenance.js +0 -190
- package/dist/esm/lib/slice/forwardSliceForKey.d.ts +0 -88
- package/dist/esm/lib/slice/forwardSliceForKey.js +0 -243
- package/dist/esm/lib/slice/index.d.ts +0 -25
- package/dist/esm/lib/slice/index.js +0 -25
- package/dist/esm/lib/slice/keyIndex.d.ts +0 -137
- package/dist/esm/lib/slice/keyIndex.js +0 -293
- package/dist/esm/lib/slice/keyTimeline.d.ts +0 -49
- package/dist/esm/lib/slice/keyTimeline.js +0 -113
- package/dist/esm/lib/slice/keysReadSources.d.ts +0 -51
- package/dist/esm/lib/slice/keysReadSources.js +0 -95
- package/dist/esm/lib/slice/serialize.d.ts +0 -78
- package/dist/esm/lib/slice/serialize.js +0 -278
- package/dist/esm/lib/slice/sliceForKey.d.ts +0 -47
- package/dist/esm/lib/slice/sliceForKey.js +0 -88
- package/dist/esm/lib/slice/types.d.ts +0 -567
- package/dist/esm/lib/slice/types.js +0 -25
- package/dist/esm/lib/time-travel/axis.d.ts +0 -119
- package/dist/esm/lib/time-travel/axis.js +0 -179
- package/dist/esm/lib/time-travel/bundles.d.ts +0 -77
- package/dist/esm/lib/time-travel/bundles.js +0 -136
- package/dist/esm/lib/time-travel/chain.d.ts +0 -93
- package/dist/esm/lib/time-travel/chain.js +0 -188
- package/dist/esm/lib/time-travel/commitStops.d.ts +0 -55
- package/dist/esm/lib/time-travel/commitStops.js +0 -202
- package/dist/esm/lib/time-travel/index.d.ts +0 -22
- package/dist/esm/lib/time-travel/index.js +0 -21
- package/dist/esm/lib/time-travel/stateAt.d.ts +0 -102
- package/dist/esm/lib/time-travel/stateAt.js +0 -153
- package/dist/esm/lib/time-travel/tagStops.d.ts +0 -72
- package/dist/esm/lib/time-travel/tagStops.js +0 -102
- package/dist/esm/lib/time-travel/timeTravel.d.ts +0 -70
- package/dist/esm/lib/time-travel/timeTravel.js +0 -360
- package/dist/esm/lib/time-travel/types.d.ts +0 -470
- package/dist/esm/lib/time-travel/types.js +0 -23
- package/dist/esm/write.d.ts +0 -47
- package/dist/esm/write.js +0 -46
- package/dist/lib/capture/freeze.js +0 -320
- package/dist/lib/capture/ownData.js +0 -19
- package/dist/lib/capture/valueKinds.js +0 -146
- package/dist/lib/ids/runtimeStageId.js +0 -210
- package/dist/lib/memory/EventLog.js +0 -152
- package/dist/lib/memory/RecordFrame.js +0 -300
- package/dist/lib/memory/SharedMemory.js +0 -92
- package/dist/lib/memory/TransactionBuffer.js +0 -950
- package/dist/lib/memory/admission.js +0 -159
- package/dist/lib/memory/backtrack.js +0 -463
- package/dist/lib/memory/commitLogUtils.js +0 -399
- package/dist/lib/memory/deltaEncoding.js +0 -128
- package/dist/lib/memory/equality.js +0 -266
- package/dist/lib/memory/eventPosition.js +0 -3
- package/dist/lib/memory/honesty.js +0 -95
- package/dist/lib/memory/keyPaths.js +0 -243
- package/dist/lib/memory/logModel.js +0 -372
- package/dist/lib/memory/merge.js +0 -64
- package/dist/lib/memory/pathOps.js +0 -306
- package/dist/lib/memory/paths.js +0 -62
- package/dist/lib/memory/placeholders.js +0 -43
- package/dist/lib/memory/recordCommit.js +0 -65
- package/dist/lib/memory/scrub.js +0 -79
- package/dist/lib/memory/types.js +0 -11
- package/dist/lib/memory/utils.js +0 -178
- package/dist/lib/memory/verbs.js +0 -444
- package/dist/lib/recorder/CommitRangeIndex.js +0 -211
- package/dist/lib/scope/detectCircular.js +0 -21
- package/dist/lib/scope/recorders/summarizeValue.js +0 -10
- package/dist/lib/slice/elementProvenance.js +0 -195
- package/dist/lib/slice/forwardSliceForKey.js +0 -247
- package/dist/lib/slice/index.js +0 -42
- package/dist/lib/slice/keyIndex.js +0 -313
- package/dist/lib/slice/keyTimeline.js +0 -117
- package/dist/lib/slice/keysReadSources.js +0 -101
- package/dist/lib/slice/serialize.js +0 -286
- package/dist/lib/slice/sliceForKey.js +0 -93
- package/dist/lib/slice/types.js +0 -26
- package/dist/lib/time-travel/axis.js +0 -184
- package/dist/lib/time-travel/bundles.js +0 -144
- package/dist/lib/time-travel/chain.js +0 -193
- package/dist/lib/time-travel/commitStops.js +0 -206
- package/dist/lib/time-travel/index.js +0 -32
- package/dist/lib/time-travel/stateAt.js +0 -160
- package/dist/lib/time-travel/tagStops.js +0 -106
- package/dist/lib/time-travel/timeTravel.js +0 -364
- package/dist/lib/time-travel/types.js +0 -24
- package/dist/types/lib/capture/freeze.d.ts +0 -91
- package/dist/types/lib/capture/ownData.d.ts +0 -7
- package/dist/types/lib/capture/valueKinds.d.ts +0 -57
- package/dist/types/lib/ids/runtimeStageId.d.ts +0 -173
- package/dist/types/lib/memory/EventLog.d.ts +0 -105
- package/dist/types/lib/memory/RecordFrame.d.ts +0 -232
- package/dist/types/lib/memory/SharedMemory.d.ts +0 -46
- package/dist/types/lib/memory/TransactionBuffer.d.ts +0 -521
- package/dist/types/lib/memory/admission.d.ts +0 -81
- package/dist/types/lib/memory/backtrack.d.ts +0 -286
- package/dist/types/lib/memory/commitLogUtils.d.ts +0 -217
- package/dist/types/lib/memory/deltaEncoding.d.ts +0 -66
- package/dist/types/lib/memory/equality.d.ts +0 -93
- package/dist/types/lib/memory/eventPosition.d.ts +0 -18
- package/dist/types/lib/memory/honesty.d.ts +0 -93
- package/dist/types/lib/memory/keyPaths.d.ts +0 -125
- package/dist/types/lib/memory/logModel.d.ts +0 -76
- package/dist/types/lib/memory/merge.d.ts +0 -26
- package/dist/types/lib/memory/pathOps.d.ts +0 -115
- package/dist/types/lib/memory/paths.d.ts +0 -52
- package/dist/types/lib/memory/placeholders.d.ts +0 -39
- package/dist/types/lib/memory/recordCommit.d.ts +0 -45
- package/dist/types/lib/memory/scrub.d.ts +0 -53
- package/dist/types/lib/memory/types.d.ts +0 -209
- package/dist/types/lib/memory/utils.d.ts +0 -73
- package/dist/types/lib/memory/verbs.d.ts +0 -333
- package/dist/types/lib/recorder/CommitRangeIndex.d.ts +0 -147
- package/dist/types/lib/scope/detectCircular.d.ts +0 -13
- package/dist/types/lib/scope/recorders/summarizeValue.d.ts +0 -5
- package/dist/types/lib/slice/elementProvenance.d.ts +0 -81
- package/dist/types/lib/slice/forwardSliceForKey.d.ts +0 -88
- package/dist/types/lib/slice/index.d.ts +0 -25
- package/dist/types/lib/slice/keyIndex.d.ts +0 -137
- package/dist/types/lib/slice/keyTimeline.d.ts +0 -49
- package/dist/types/lib/slice/keysReadSources.d.ts +0 -51
- package/dist/types/lib/slice/serialize.d.ts +0 -78
- package/dist/types/lib/slice/sliceForKey.d.ts +0 -47
- package/dist/types/lib/slice/types.d.ts +0 -567
- package/dist/types/lib/time-travel/axis.d.ts +0 -119
- package/dist/types/lib/time-travel/bundles.d.ts +0 -77
- package/dist/types/lib/time-travel/chain.d.ts +0 -93
- package/dist/types/lib/time-travel/commitStops.d.ts +0 -55
- package/dist/types/lib/time-travel/index.d.ts +0 -22
- package/dist/types/lib/time-travel/stateAt.d.ts +0 -102
- package/dist/types/lib/time-travel/tagStops.d.ts +0 -72
- package/dist/types/lib/time-travel/timeTravel.d.ts +0 -70
- package/dist/types/lib/time-travel/types.d.ts +0 -470
- package/dist/types/write.d.ts +0 -47
- package/dist/write.js +0 -52
|
@@ -1,457 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* backtrack.ts — Backward causal chain analysis on the commit log.
|
|
3
|
-
*
|
|
4
|
-
* Implements **backward program slicing** (Weiser 1984, thin-slice variant):
|
|
5
|
-
* given a starting execution step, walk backwards through read→write
|
|
6
|
-
* dependencies to build the causal DAG that produced the data at that step.
|
|
7
|
-
*
|
|
8
|
-
* ## Algorithm
|
|
9
|
-
*
|
|
10
|
-
* BFS on the implicit dependency graph where edges run from reader → writer.
|
|
11
|
-
*
|
|
12
|
-
* 1. Locate startId in commitLog → root node
|
|
13
|
-
* 2. Get keysRead for root via `getKeysRead` callback
|
|
14
|
-
* 3. For each key read, find who last wrote it before this step → parent commit
|
|
15
|
-
* ("wrote" is the writer rule of `keyPaths.ts`, 9.33.0: a row on the key, inside it, or
|
|
16
|
-
* around it that changed it — so a stage that read `cfg` links to the subflow seed or
|
|
17
|
-
* merge-back that wrote `cfg␟b`)
|
|
18
|
-
* 4. Create parent CausalNode, link to root.parents
|
|
19
|
-
* 5. Enqueue parent. Repeat until queue empty or limits hit.
|
|
20
|
-
*
|
|
21
|
-
* Output is a **DAG** (not a linked list): a stage reading `creditScore` AND `dti`
|
|
22
|
-
* from different writers has two parents.
|
|
23
|
-
*
|
|
24
|
-
* ## Staged Optimization
|
|
25
|
-
*
|
|
26
|
-
* Two writer-lookup strategies, chosen automatically by commit log size:
|
|
27
|
-
*
|
|
28
|
-
* | Strategy | When | Complexity per lookup |
|
|
29
|
-
* |----------|------|----------------------|
|
|
30
|
-
* | Linear scan | N ≤ 256 | O(N) — simple backward scan |
|
|
31
|
-
* | Reverse index | N > 256 | O(K log N) — prebuilt key→[indices], binary search |
|
|
32
|
-
*
|
|
33
|
-
* The threshold (256) is chosen so the O(N) build cost of the reverse index
|
|
34
|
-
* is amortized over the BFS traversal. Below 256, linear scan wins because
|
|
35
|
-
* there's no index build overhead. The consumer never sees this — `causalChain()`
|
|
36
|
-
* picks the right strategy internally (like a query optimizer choosing between
|
|
37
|
-
* sequential scan vs index scan based on table size).
|
|
38
|
-
*
|
|
39
|
-
* ## Complexity
|
|
40
|
-
*
|
|
41
|
-
* - **Small logs (N ≤ 256):** O(V × K × N) total. V=visited, K=avg keys/node.
|
|
42
|
-
* - **Large logs (N > 256):** O(N × U) index build + O(V × K × log N) lookups.
|
|
43
|
-
* U = unique keys. Amortized over all BFS hops.
|
|
44
|
-
*
|
|
45
|
-
* ## References
|
|
46
|
-
*
|
|
47
|
-
* - Weiser, M. (1984). "Program Slicing." IEEE TSE.
|
|
48
|
-
* - Sridharan, M. et al. (2007). "Thin Slicing." PLDI.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```typescript
|
|
52
|
-
* import { causalChain, flattenCausalDAG, formatCausalChain } from 'footprintjs/trace';
|
|
53
|
-
*
|
|
54
|
-
* const dag = causalChain(commitLog, 'decide#2', (id) => recorder.getKeysRead(id));
|
|
55
|
-
* const flat = flattenCausalDAG(dag); // BFS-ordered flat list
|
|
56
|
-
* console.log(formatCausalChain(dag)); // human-readable
|
|
57
|
-
* ```
|
|
58
|
-
*/
|
|
59
|
-
import { findLastWriter } from './commitLogUtils.js';
|
|
60
|
-
import { queryWork, relation, writesOnlyInside } from './keyPaths.js';
|
|
61
|
-
import { logModel } from './logModel.js';
|
|
62
|
-
// ── Staged optimization: writer lookup strategies ──────────────────────
|
|
63
|
-
/**
|
|
64
|
-
* Threshold for switching from linear scan to reverse index.
|
|
65
|
-
* Below this, O(N) scan is faster (no index build cost).
|
|
66
|
-
* Above this, O(log N) binary search wins.
|
|
67
|
-
*/
|
|
68
|
-
const REVERSE_INDEX_THRESHOLD = 256;
|
|
69
|
-
/** Strategy 1: Linear scan — O(N) per lookup, zero setup cost. */
|
|
70
|
-
function linearScanLookup(commitLog) {
|
|
71
|
-
return (key, beforeIdx) => findLastWriter(commitLog, key, beforeIdx);
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Strategy 2: Reverse index — one O(rows) build, O(depth + log N) per lookup.
|
|
75
|
-
* The log's read model (`logModel.ts`: a path trie, each top-level key folded at
|
|
76
|
-
* most once) answers the writer rule — rows on, inside or around the key — by
|
|
77
|
-
* binary search for the last write on or inside it, then a verdict only for the
|
|
78
|
-
* around-candidates after it. The same answer `findLastWriter` gives, so the
|
|
79
|
-
* strategy switch below never changes a slice.
|
|
80
|
-
*/
|
|
81
|
-
function reverseIndexLookup(commitLog) {
|
|
82
|
-
const model = logModel(commitLog);
|
|
83
|
-
return (key, beforeIdx) => {
|
|
84
|
-
const at = model.lastWriterBefore(key, beforeIdx);
|
|
85
|
-
return at >= 0 ? commitLog[at] : undefined;
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* The trace entries of `commit` that make it a writer of `linkKey` — the entries whose read
|
|
90
|
-
* prefix (`TraceEntry.readKeys`) a per-write edge expands through. The FIRST entry on the exact
|
|
91
|
-
* path when there is one (the #P1 behaviour, unchanged); otherwise every entry inside or around
|
|
92
|
-
* the key (9.33.0: the commit wrote the key through a nested row — a subflow seed, an
|
|
93
|
-
* outputMapper merge-back — and all of those rows wrote it).
|
|
94
|
-
*/
|
|
95
|
-
function linkingEntries(commit, linkKey) {
|
|
96
|
-
const exact = commit.trace.find((t) => t.path === linkKey);
|
|
97
|
-
if (exact !== undefined)
|
|
98
|
-
return [exact];
|
|
99
|
-
return commit.trace.filter((t) => relation(t.path, linkKey) !== undefined);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Staged optimization: pick the right writer-lookup strategy based on data size.
|
|
103
|
-
*
|
|
104
|
-
* Like a database query optimizer choosing between sequential scan and index scan:
|
|
105
|
-
*
|
|
106
|
-
* - **Small log (≤ 256):** Linear scan wins. Zero setup cost, good cache locality.
|
|
107
|
-
* The overhead of building a reverse index isn't worth it for short logs.
|
|
108
|
-
*
|
|
109
|
-
* - **Large log (> 256):** Reverse index wins. O(N×U) upfront build cost is amortized
|
|
110
|
-
* across all BFS hops. Each lookup becomes O(log N) via binary search instead of O(N).
|
|
111
|
-
* For an agent loop with 500 iterations and 5 keys per hop, this is 500×5×log(500)≈22K ops
|
|
112
|
-
* vs 500×5×500=1.25M ops with linear scan.
|
|
113
|
-
*
|
|
114
|
-
* The caller never sees this — `causalChain()` picks automatically.
|
|
115
|
-
*/
|
|
116
|
-
function createWriterLookup(commitLog) {
|
|
117
|
-
if (commitLog.length <= REVERSE_INDEX_THRESHOLD) {
|
|
118
|
-
return linearScanLookup(commitLog);
|
|
119
|
-
}
|
|
120
|
-
return reverseIndexLookup(commitLog);
|
|
121
|
-
}
|
|
122
|
-
// ── Core algorithm ─────────────────────────────────────────────────────
|
|
123
|
-
/**
|
|
124
|
-
* RFC-003 D2: the `incompleteSources` node fragment for a commit — `{}`
|
|
125
|
-
* when the stage consumed no untracked read paths, keeping the field
|
|
126
|
-
* ABSENT (not empty-array-valued) for fully-tracked stages.
|
|
127
|
-
*/
|
|
128
|
-
function incompleteSourcesFragment(commit) {
|
|
129
|
-
if (!commit.untrackedSources || commit.untrackedSources.length === 0)
|
|
130
|
-
return {};
|
|
131
|
-
return { incompleteSources: commit.untrackedSources };
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Build the causal DAG rooted at `startId` by walking backwards
|
|
135
|
-
* through read→write dependencies in the commit log.
|
|
136
|
-
*
|
|
137
|
-
* Automatically selects the optimal writer lookup strategy:
|
|
138
|
-
* - Linear scan for small logs (≤ 256 commits)
|
|
139
|
-
* - Reverse index with binary search for large logs (> 256 commits)
|
|
140
|
-
*
|
|
141
|
-
* Produces a DAG (not a tree): if two children both read from the same
|
|
142
|
-
* parent, the parent node is shared (deduped by runtimeStageId).
|
|
143
|
-
*
|
|
144
|
-
* @param commitLog Ordered commit bundles from executor.getSnapshot().commitLog
|
|
145
|
-
* @param startId runtimeStageId to start backtracking from
|
|
146
|
-
* @param getKeysRead Callback returning keys read by a given execution step
|
|
147
|
-
* @param options Depth and node limits
|
|
148
|
-
* @returns Root CausalNode with .parents forming the DAG, or undefined if startId not found
|
|
149
|
-
*/
|
|
150
|
-
export function causalChain(commitLog, startId, getKeysRead, options) {
|
|
151
|
-
const maxDepth = options?.maxDepth ?? 20;
|
|
152
|
-
const maxNodes = options?.maxNodes ?? 100;
|
|
153
|
-
const controlDeps = options?.controlDeps;
|
|
154
|
-
const weigh = options?.weigh;
|
|
155
|
-
const perWrite = options?.edgeAttribution === 'per-write';
|
|
156
|
-
// RFC-003 D4 — truncation visibility. Set only when a limit actually
|
|
157
|
-
// cuts the slice; surfaced on the root as `truncated` so a consumer can
|
|
158
|
-
// never mistake a truncated slice for a complete one.
|
|
159
|
-
let truncatedByDepth = false;
|
|
160
|
-
let truncatedByNodes = false;
|
|
161
|
-
// Build position index: runtimeStageId → array position (O(n) once)
|
|
162
|
-
const idxMap = new Map();
|
|
163
|
-
for (let i = 0; i < commitLog.length; i++) {
|
|
164
|
-
idxMap.set(commitLog[i].runtimeStageId, i);
|
|
165
|
-
}
|
|
166
|
-
queryWork.units += commitLog.length;
|
|
167
|
-
const startIdx = idxMap.get(startId);
|
|
168
|
-
if (startIdx === undefined)
|
|
169
|
-
return undefined;
|
|
170
|
-
const startCommit = commitLog[startIdx];
|
|
171
|
-
// Pick writer lookup strategy based on log size
|
|
172
|
-
const findWriter = createWriterLookup(commitLog);
|
|
173
|
-
// Node dedup map: runtimeStageId → CausalNode (ensures DAG, not tree)
|
|
174
|
-
const nodeMap = new Map();
|
|
175
|
-
const root = {
|
|
176
|
-
runtimeStageId: startId,
|
|
177
|
-
stageId: startCommit.stageId,
|
|
178
|
-
stageName: startCommit.stage,
|
|
179
|
-
keysWritten: startCommit.trace.map((t) => t.path),
|
|
180
|
-
linkedBy: '',
|
|
181
|
-
depth: 0,
|
|
182
|
-
parents: [],
|
|
183
|
-
parentEdges: [],
|
|
184
|
-
...incompleteSourcesFragment(startCommit),
|
|
185
|
-
};
|
|
186
|
-
nodeMap.set(startId, root);
|
|
187
|
-
// ── #P1 per-write attribution machinery (inert under 'stage') ──────────
|
|
188
|
-
// expandedReads: per node, the reads already queued for expansion — late
|
|
189
|
-
// links via additional keys re-enqueue only the DELTA, so the slice grows
|
|
190
|
-
// monotonically toward the stage-level ceiling and terminates (each key
|
|
191
|
-
// expands at most once per node). fullyExpanded: nodes that fell back to
|
|
192
|
-
// stage level (no readKeys on a linking entry) — nothing left to add.
|
|
193
|
-
const expandedReads = new Map();
|
|
194
|
-
const fullyExpanded = new Set();
|
|
195
|
-
/**
|
|
196
|
-
* Resolve a node's expansion read-set for the given linking WRITTEN keys.
|
|
197
|
-
* Per-write mode with provenance present → union of the linking writes'
|
|
198
|
-
* temporal-prefix `readKeys`. Any linking entry WITHOUT `readKeys` (or no
|
|
199
|
-
* linkKeys at all) → honest stage-level fallback, flagged via the second
|
|
200
|
-
* tuple member so the caller marks the node fully expanded.
|
|
201
|
-
*/
|
|
202
|
-
function readsForLinks(commit, linkKeys) {
|
|
203
|
-
if (!perWrite || !linkKeys || linkKeys.length === 0) {
|
|
204
|
-
return [getKeysRead(commit.runtimeStageId), true];
|
|
205
|
-
}
|
|
206
|
-
const union = new Set();
|
|
207
|
-
for (const linkKey of linkKeys) {
|
|
208
|
-
const entries = linkingEntries(commit, linkKey);
|
|
209
|
-
if (entries.length === 0 || entries.some((e) => e.readKeys === undefined)) {
|
|
210
|
-
// Mixed/dial-off log — degrade THIS node to stage level, honestly.
|
|
211
|
-
return [getKeysRead(commit.runtimeStageId), true];
|
|
212
|
-
}
|
|
213
|
-
for (const entry of entries)
|
|
214
|
-
for (const rk of entry.readKeys)
|
|
215
|
-
union.add(rk);
|
|
216
|
-
}
|
|
217
|
-
return [[...union], false];
|
|
218
|
-
}
|
|
219
|
-
// BFS/worklist queue: [node, commitIdx, depth, keysToExpand]
|
|
220
|
-
const [rootReads, rootIsFull] = perWrite
|
|
221
|
-
? readsForLinks(startCommit, options?.rootLinkKeys)
|
|
222
|
-
: [getKeysRead(startId), true];
|
|
223
|
-
expandedReads.set(startId, new Set(rootReads));
|
|
224
|
-
if (rootIsFull)
|
|
225
|
-
fullyExpanded.add(startId);
|
|
226
|
-
const queue = [[root, startIdx, 0, rootReads]];
|
|
227
|
-
let visited = 1;
|
|
228
|
-
/**
|
|
229
|
-
* Link `node → parent` (creating + enqueueing the parent when new).
|
|
230
|
-
* Shared by data-edge expansion (read→write) and control-edge expansion
|
|
231
|
-
* (D3). One CausalEdge per distinct (parent, kind, key) link; `parents`
|
|
232
|
-
* keeps its historical one-entry-per-parent dedup.
|
|
233
|
-
*/
|
|
234
|
-
function linkParent(node, parentCommit, kind, key, depth) {
|
|
235
|
-
const parentId = parentCommit.runtimeStageId;
|
|
236
|
-
// the dedup scans below, and the parent's trace when it is new — counted for the scaling test
|
|
237
|
-
queryWork.units += 1 + node.parents.length + node.parentEdges.length;
|
|
238
|
-
// #P1: the parent's expansion reads, resolved LAZILY (only for new nodes
|
|
239
|
-
// or per-write re-expansion — duplicate links under 'stage' pay nothing).
|
|
240
|
-
// Data links expand through the reads that fed the parent's write of
|
|
241
|
-
// `key`; control links expand the decider at stage level (a decision
|
|
242
|
-
// depends on everything it read).
|
|
243
|
-
const resolveLinkReads = () => kind === 'data'
|
|
244
|
-
? readsForLinks(parentCommit, key !== undefined ? [key] : undefined)
|
|
245
|
-
: [getKeysRead(parentId), true];
|
|
246
|
-
let parentNode = nodeMap.get(parentId);
|
|
247
|
-
if (!parentNode) {
|
|
248
|
-
// New node — create and enqueue (respecting the node budget)
|
|
249
|
-
if (visited >= maxNodes) {
|
|
250
|
-
truncatedByNodes = true; // D4: a discovered parent was dropped
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
const parentIdx = idxMap.get(parentId);
|
|
254
|
-
if (parentIdx === undefined)
|
|
255
|
-
return;
|
|
256
|
-
queryWork.units += parentCommit.trace.length;
|
|
257
|
-
parentNode = {
|
|
258
|
-
runtimeStageId: parentId,
|
|
259
|
-
stageId: parentCommit.stageId,
|
|
260
|
-
stageName: parentCommit.stage,
|
|
261
|
-
keysWritten: parentCommit.trace.map((t) => t.path),
|
|
262
|
-
// linkedBy stays a DATA-key concept (back-compat) — control-linked
|
|
263
|
-
// nodes carry their label on the edge instead.
|
|
264
|
-
linkedBy: kind === 'data' ? key ?? '' : '',
|
|
265
|
-
depth: depth + 1,
|
|
266
|
-
parents: [],
|
|
267
|
-
parentEdges: [],
|
|
268
|
-
...incompleteSourcesFragment(parentCommit),
|
|
269
|
-
};
|
|
270
|
-
nodeMap.set(parentId, parentNode);
|
|
271
|
-
visited++;
|
|
272
|
-
const [linkReads, linkIsFull] = resolveLinkReads();
|
|
273
|
-
expandedReads.set(parentId, new Set(linkReads));
|
|
274
|
-
if (linkIsFull)
|
|
275
|
-
fullyExpanded.add(parentId);
|
|
276
|
-
queue.push([parentNode, parentIdx, depth + 1, linkReads]);
|
|
277
|
-
}
|
|
278
|
-
else if (perWrite && !fullyExpanded.has(parentId)) {
|
|
279
|
-
// #P1 worklist: an EXISTING node linked via another key may owe more
|
|
280
|
-
// expansion — enqueue only the reads not yet expanded (monotone; the
|
|
281
|
-
// node budget is untouched, no node is created). Re-expansion keeps
|
|
282
|
-
// the node's ORIGINAL depth so its parents get a consistent depth+1.
|
|
283
|
-
const [linkReads, linkIsFull] = resolveLinkReads();
|
|
284
|
-
const expanded = expandedReads.get(parentId);
|
|
285
|
-
const delta = linkReads.filter((k) => !expanded.has(k));
|
|
286
|
-
if (linkIsFull)
|
|
287
|
-
fullyExpanded.add(parentId);
|
|
288
|
-
if (delta.length > 0) {
|
|
289
|
-
for (const k of delta)
|
|
290
|
-
expanded.add(k);
|
|
291
|
-
const parentIdx = idxMap.get(parentId);
|
|
292
|
-
if (parentIdx !== undefined)
|
|
293
|
-
queue.push([parentNode, parentIdx, parentNode.depth, delta]);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
// DAG merge: one parents[] entry per distinct parent (historical shape)
|
|
297
|
-
if (!node.parents.some((p) => p.runtimeStageId === parentId)) {
|
|
298
|
-
node.parents.push(parentNode);
|
|
299
|
-
}
|
|
300
|
-
// One edge per distinct (parent, kind, key) link. The weigher (D4)
|
|
301
|
-
// stamps the weight at creation; `undefined` → 1.0 — the engine never
|
|
302
|
-
// computes weights itself.
|
|
303
|
-
if (!node.parentEdges.some((e) => e.parent.runtimeStageId === parentId && e.kind === kind && e.key === key)) {
|
|
304
|
-
// Error isolation (review finding): a consumer weigher that throws
|
|
305
|
-
// must degrade to the default weight, never crash the slice — the
|
|
306
|
-
// same contract every other consumer callback in the library gets.
|
|
307
|
-
let weight = 1.0;
|
|
308
|
-
if (weigh) {
|
|
309
|
-
try {
|
|
310
|
-
weight = weigh(node, parentNode, key, kind) ?? 1.0;
|
|
311
|
-
}
|
|
312
|
-
catch {
|
|
313
|
-
/* weigher threw — keep 1.0, the slice stays usable */
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
const nested = kind === 'data' && key !== undefined && writesOnlyInside(parentCommit, key);
|
|
317
|
-
node.parentEdges.push({
|
|
318
|
-
parent: parentNode,
|
|
319
|
-
kind,
|
|
320
|
-
key,
|
|
321
|
-
weight,
|
|
322
|
-
...(nested && { basis: 'nested-rows' }),
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
while (queue.length > 0) {
|
|
327
|
-
const [node, commitIdx, depth, keysToExpand] = queue.shift();
|
|
328
|
-
queryWork.units += 1 + keysToExpand.length;
|
|
329
|
-
if (depth >= maxDepth) {
|
|
330
|
-
// D4: only a node that still HAD something to expand counts as a cut
|
|
331
|
-
// (a leaf at the horizon truncates nothing).
|
|
332
|
-
if (keysToExpand.length > 0 || controlDeps?.(node.runtimeStageId) !== undefined) {
|
|
333
|
-
truncatedByDepth = true;
|
|
334
|
-
}
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
// Data edges: for each key in this expansion's read-set, find who wrote
|
|
338
|
-
// it. Under 'stage' this is the node's full read-set (historical
|
|
339
|
-
// behavior); under 'per-write' it is the linking writes' temporal prefix
|
|
340
|
-
// (or a worklist delta on re-expansion).
|
|
341
|
-
const keysRead = keysToExpand;
|
|
342
|
-
for (const key of keysRead) {
|
|
343
|
-
const writer = findWriter(key, commitIdx);
|
|
344
|
-
if (!writer) {
|
|
345
|
-
// F4b: say why there is no edge — no commit before this node wrote the key.
|
|
346
|
-
node.preRunReads ??= { code: 'pre-run-origin', keys: [] };
|
|
347
|
-
if (!node.preRunReads.keys.includes(key))
|
|
348
|
-
node.preRunReads.keys.push(key);
|
|
349
|
-
continue;
|
|
350
|
-
}
|
|
351
|
-
linkParent(node, writer, 'data', key, depth);
|
|
352
|
-
}
|
|
353
|
-
// Control edge (RFC-003 D3): link the governing decider, labeled by the
|
|
354
|
-
// decide() rule label when present. The decider node then expands
|
|
355
|
-
// normally through its own data reads (and its own control parent).
|
|
356
|
-
if (controlDeps) {
|
|
357
|
-
const dep = controlDeps(node.runtimeStageId);
|
|
358
|
-
if (dep) {
|
|
359
|
-
const deciderIdx = idxMap.get(dep.deciderId);
|
|
360
|
-
if (deciderIdx !== undefined) {
|
|
361
|
-
linkParent(node, commitLog[deciderIdx], 'control', dep.label, depth);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
// RFC-003 D4 — truncation visibility on the root (absent when complete). It is DATA, and only
|
|
367
|
-
// data: a reader reads `root.truncated` (and `formatCausalChain` prints it); the record writes no
|
|
368
|
-
// console line (the dev-mode warning went in C6 — the record imports nothing outside itself).
|
|
369
|
-
if (truncatedByDepth || truncatedByNodes) {
|
|
370
|
-
root.truncated = { byDepth: truncatedByDepth, byNodes: truncatedByNodes };
|
|
371
|
-
}
|
|
372
|
-
return root;
|
|
373
|
-
}
|
|
374
|
-
// ── Utilities ──────────────────────────────────────────────────────────
|
|
375
|
-
/**
|
|
376
|
-
* Flatten the causal DAG into a BFS-ordered list of nodes.
|
|
377
|
-
* Each node appears exactly once (first occurrence by BFS order).
|
|
378
|
-
* Useful for linear display or iteration.
|
|
379
|
-
*/
|
|
380
|
-
export function flattenCausalDAG(root) {
|
|
381
|
-
const result = [];
|
|
382
|
-
const visited = new Set();
|
|
383
|
-
const queue = [root];
|
|
384
|
-
while (queue.length > 0) {
|
|
385
|
-
const node = queue.shift();
|
|
386
|
-
if (visited.has(node.runtimeStageId))
|
|
387
|
-
continue;
|
|
388
|
-
visited.add(node.runtimeStageId);
|
|
389
|
-
result.push(node);
|
|
390
|
-
for (const parent of node.parents) {
|
|
391
|
-
if (!visited.has(parent.runtimeStageId)) {
|
|
392
|
-
queue.push(parent);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
return result;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Format a causal DAG as human-readable indented text.
|
|
400
|
-
* Shows the dependency chain with depth indentation and linked-by keys.
|
|
401
|
-
*
|
|
402
|
-
* RFC-003 D2: nodes that consumed untracked read paths render an extra
|
|
403
|
-
* `⚠ also consumed … — slice may be incomplete here` line, so a consumer
|
|
404
|
-
* (human or LLM) debugging from the slice is TOLD when it is incomplete.
|
|
405
|
-
*
|
|
406
|
-
* RFC-003 D3: control edges render as `← [control: <rule label>]`
|
|
407
|
-
* (label omitted when the decision carried none). Data rendering is
|
|
408
|
-
* byte-identical to the pre-D3 output — `← via <key>` from the node's
|
|
409
|
-
* discovery-time `linkedBy`.
|
|
410
|
-
*
|
|
411
|
-
* RFC-003 D4: edge weights from the `weigh` hook render as a suffix —
|
|
412
|
-
* `← via systemPrompt (0.18)` — only when ≠ 1.0, so unweighted output is
|
|
413
|
-
* unchanged. A truncated slice (root.truncated) appends a final
|
|
414
|
-
* `⚠ slice truncated …` line.
|
|
415
|
-
*/
|
|
416
|
-
export function formatCausalChain(root) {
|
|
417
|
-
const lines = [];
|
|
418
|
-
const visited = new Set();
|
|
419
|
-
const weightSuffix = (edge) => edge !== undefined && edge.weight !== 1 ? ` (${edge.weight})` : '';
|
|
420
|
-
function walk(node, indent, edgesFromChild) {
|
|
421
|
-
if (visited.has(node.runtimeStageId)) {
|
|
422
|
-
lines.push(`${' '.repeat(indent)}↳ ${node.runtimeStageId} (see above)`);
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
visited.add(node.runtimeStageId);
|
|
426
|
-
const linkParts = [];
|
|
427
|
-
if (node.linkedBy) {
|
|
428
|
-
const dataEdge = edgesFromChild?.find((e) => e.kind === 'data');
|
|
429
|
-
linkParts.push(`via ${node.linkedBy}${weightSuffix(dataEdge)}`);
|
|
430
|
-
}
|
|
431
|
-
const controlEdge = edgesFromChild?.find((e) => e.kind === 'control');
|
|
432
|
-
if (controlEdge) {
|
|
433
|
-
linkParts.push(`[control${controlEdge.key ? `: ${controlEdge.key}` : ''}]${weightSuffix(controlEdge)}`);
|
|
434
|
-
}
|
|
435
|
-
const link = linkParts.length > 0 ? ` ← ${linkParts.join(' ← ')}` : '';
|
|
436
|
-
const writes = node.keysWritten.length > 0 ? ` [wrote: ${node.keysWritten.join(', ')}]` : '';
|
|
437
|
-
lines.push(`${' '.repeat(indent)}${node.stageName} (${node.runtimeStageId})${link}${writes}`);
|
|
438
|
-
if (node.incompleteSources && node.incompleteSources.length > 0) {
|
|
439
|
-
lines.push(`${' '.repeat(indent + 1)}⚠ also consumed ${node.incompleteSources.join('/')} — slice may be incomplete here`);
|
|
440
|
-
}
|
|
441
|
-
for (const parent of node.parents) {
|
|
442
|
-
walk(parent, indent + 1, node.parentEdges.filter((e) => e.parent === parent));
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
walk(root, 0);
|
|
446
|
-
if (root.truncated) {
|
|
447
|
-
const causes = [root.truncated.byDepth && 'maxDepth reached', root.truncated.byNodes && 'maxNodes reached']
|
|
448
|
-
.filter(Boolean)
|
|
449
|
-
.join(', ');
|
|
450
|
-
lines.push(`⚠ slice truncated (${causes}) — older causes exist beyond this horizon`);
|
|
451
|
-
}
|
|
452
|
-
return lines.join('\n');
|
|
453
|
-
}
|
|
454
|
-
// ── Exported for testing (internal) ────────────────────────────────────
|
|
455
|
-
/** @internal Exposed for testing the strategy selection. */
|
|
456
|
-
export const _REVERSE_INDEX_THRESHOLD = REVERSE_INDEX_THRESHOLD;
|
|
457
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja3RyYWNrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9tZW1vcnkvYmFja3RyYWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5REc7QUFFSCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFckQsT0FBTyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDdEUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQWdNekMsMEVBQTBFO0FBRTFFOzs7O0dBSUc7QUFDSCxNQUFNLHVCQUF1QixHQUFHLEdBQUcsQ0FBQztBQVFwQyxrRUFBa0U7QUFDbEUsU0FBUyxnQkFBZ0IsQ0FBQyxTQUF5QjtJQUNqRCxPQUFPLENBQUMsR0FBRyxFQUFFLFNBQVMsRUFBRSxFQUFFLENBQUMsY0FBYyxDQUFDLFNBQVMsRUFBRSxHQUFHLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxTQUFTLGtCQUFrQixDQUFDLFNBQXlCO0lBQ25ELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNsQyxPQUFPLENBQUMsR0FBVyxFQUFFLFNBQWlCLEVBQTRCLEVBQUU7UUFDbEUsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUNsRCxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQzdDLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFTLGNBQWMsQ0FBQyxNQUFvQixF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QztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztJQUVkLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ25CLE1BQU0sTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLElBQUksa0JBQWtCLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLElBQUksa0JBQWtCLENBQUM7YUFDeEcsTUFBTSxDQUFDLE9BQU8sQ0FBQzthQUNmLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNkLEtBQUssQ0FBQyxJQUFJLENBQUMsc0JBQXNCLE1BQU0sNENBQTRDLENBQUMsQ0FBQztJQUN2RixDQUFDO0lBRUQsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzFCLENBQUM7QUFFRCwwRUFBMEU7QUFFMUUsNERBQTREO0FBQzVELE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUFHLHVCQUF1QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBiYWNrdHJhY2sudHMg4oCUIEJhY2t3YXJkIGNhdXNhbCBjaGFpbiBhbmFseXNpcyBvbiB0aGUgY29tbWl0IGxvZy5cbiAqXG4gKiBJbXBsZW1lbnRzICoqYmFja3dhcmQgcHJvZ3JhbSBzbGljaW5nKiogKFdlaXNlciAxOTg0LCB0aGluLXNsaWNlIHZhcmlhbnQpOlxuICogZ2l2ZW4gYSBzdGFydGluZyBleGVjdXRpb24gc3RlcCwgd2FsayBiYWNrd2FyZHMgdGhyb3VnaCByZWFk4oaSd3JpdGVcbiAqIGRlcGVuZGVuY2llcyB0byBidWlsZCB0aGUgY2F1c2FsIERBRyB0aGF0IHByb2R1Y2VkIHRoZSBkYXRhIGF0IHRoYXQgc3RlcC5cbiAqXG4gKiAjIyBBbGdvcml0aG1cbiAqXG4gKiBCRlMgb24gdGhlIGltcGxpY2l0IGRlcGVuZGVuY3kgZ3JhcGggd2hlcmUgZWRnZXMgcnVuIGZyb20gcmVhZGVyIOKGkiB3cml0ZXIuXG4gKlxuICogMS4gTG9jYXRlIHN0YXJ0SWQgaW4gY29tbWl0TG9nIOKGkiByb290IG5vZGVcbiAqIDIuIEdldCBrZXlzUmVhZCBmb3Igcm9vdCB2aWEgYGdldEtleXNSZWFkYCBjYWxsYmFja1xuICogMy4gRm9yIGVhY2gga2V5IHJlYWQsIGZpbmQgd2hvIGxhc3Qgd3JvdGUgaXQgYmVmb3JlIHRoaXMgc3RlcCDihpIgcGFyZW50IGNvbW1pdFxuICogICAgKFwid3JvdGVcIiBpcyB0aGUgd3JpdGVyIHJ1bGUgb2YgYGtleVBhdGhzLnRzYCwgOS4zMy4wOiBhIHJvdyBvbiB0aGUga2V5LCBpbnNpZGUgaXQsIG9yXG4gKiAgICBhcm91bmQgaXQgdGhhdCBjaGFuZ2VkIGl0IOKAlCBzbyBhIHN0YWdlIHRoYXQgcmVhZCBgY2ZnYCBsaW5rcyB0byB0aGUgc3ViZmxvdyBzZWVkIG9yXG4gKiAgICBtZXJnZS1iYWNrIHRoYXQgd3JvdGUgYGNmZ+KQn2JgKVxuICogNC4gQ3JlYXRlIHBhcmVudCBDYXVzYWxOb2RlLCBsaW5rIHRvIHJvb3QucGFyZW50c1xuICogNS4gRW5xdWV1ZSBwYXJlbnQuIFJlcGVhdCB1bnRpbCBxdWV1ZSBlbXB0eSBvciBsaW1pdHMgaGl0LlxuICpcbiAqIE91dHB1dCBpcyBhICoqREFHKiogKG5vdCBhIGxpbmtlZCBsaXN0KTogYSBzdGFnZSByZWFkaW5nIGBjcmVkaXRTY29yZWAgQU5EIGBkdGlgXG4gKiBmcm9tIGRpZmZlcmVudCB3cml0ZXJzIGhhcyB0d28gcGFyZW50cy5cbiAqXG4gKiAjIyBTdGFnZWQgT3B0aW1pemF0aW9uXG4gKlxuICogVHdvIHdyaXRlci1sb29rdXAgc3RyYXRlZ2llcywgY2hvc2VuIGF1dG9tYXRpY2FsbHkgYnkgY29tbWl0IGxvZyBzaXplOlxuICpcbiAqIHwgU3RyYXRlZ3kgfCBXaGVuIHwgQ29tcGxleGl0eSBwZXIgbG9va3VwIHxcbiAqIHwtLS0tLS0tLS0tfC0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tfFxuICogfCBMaW5lYXIgc2NhbiB8IE4g4omkIDI1NiB8IE8oTikg4oCUIHNpbXBsZSBiYWNrd2FyZCBzY2FuIHxcbiAqIHwgUmV2ZXJzZSBpbmRleCB8IE4gPiAyNTYgfCBPKEsgbG9nIE4pIOKAlCBwcmVidWlsdCBrZXnihpJbaW5kaWNlc10sIGJpbmFyeSBzZWFyY2ggfFxuICpcbiAqIFRoZSB0aHJlc2hvbGQgKDI1NikgaXMgY2hvc2VuIHNvIHRoZSBPKE4pIGJ1aWxkIGNvc3Qgb2YgdGhlIHJldmVyc2UgaW5kZXhcbiAqIGlzIGFtb3J0aXplZCBvdmVyIHRoZSBCRlMgdHJhdmVyc2FsLiBCZWxvdyAyNTYsIGxpbmVhciBzY2FuIHdpbnMgYmVjYXVzZVxuICogdGhlcmUncyBubyBpbmRleCBidWlsZCBvdmVyaGVhZC4gVGhlIGNvbnN1bWVyIG5ldmVyIHNlZXMgdGhpcyDigJQgYGNhdXNhbENoYWluKClgXG4gKiBwaWNrcyB0aGUgcmlnaHQgc3RyYXRlZ3kgaW50ZXJuYWxseSAobGlrZSBhIHF1ZXJ5IG9wdGltaXplciBjaG9vc2luZyBiZXR3ZWVuXG4gKiBzZXF1ZW50aWFsIHNjYW4gdnMgaW5kZXggc2NhbiBiYXNlZCBvbiB0YWJsZSBzaXplKS5cbiAqXG4gKiAjIyBDb21wbGV4aXR5XG4gKlxuICogLSAqKlNtYWxsIGxvZ3MgKE4g4omkIDI1Nik6KiogTyhWIMOXIEsgw5cgTikgdG90YWwuIFY9dmlzaXRlZCwgSz1hdmcga2V5cy9ub2RlLlxuICogLSAqKkxhcmdlIGxvZ3MgKE4gPiAyNTYpOioqIE8oTiDDlyBVKSBpbmRleCBidWlsZCArIE8oViDDlyBLIMOXIGxvZyBOKSBsb29rdXBzLlxuICogICBVID0gdW5pcXVlIGtleXMuIEFtb3J0aXplZCBvdmVyIGFsbCBCRlMgaG9wcy5cbiAqXG4gKiAjIyBSZWZlcmVuY2VzXG4gKlxuICogLSBXZWlzZXIsIE0uICgxOTg0KS4gXCJQcm9ncmFtIFNsaWNpbmcuXCIgSUVFRSBUU0UuXG4gKiAtIFNyaWRoYXJhbiwgTS4gZXQgYWwuICgyMDA3KS4gXCJUaGluIFNsaWNpbmcuXCIgUExESS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgY2F1c2FsQ2hhaW4sIGZsYXR0ZW5DYXVzYWxEQUcsIGZvcm1hdENhdXNhbENoYWluIH0gZnJvbSAnZm9vdHByaW50anMvdHJhY2UnO1xuICpcbiAqIGNvbnN0IGRhZyA9IGNhdXNhbENoYWluKGNvbW1pdExvZywgJ2RlY2lkZSMyJywgKGlkKSA9PiByZWNvcmRlci5nZXRLZXlzUmVhZChpZCkpO1xuICogY29uc3QgZmxhdCA9IGZsYXR0ZW5DYXVzYWxEQUcoZGFnKTsgICAgIC8vIEJGUy1vcmRlcmVkIGZsYXQgbGlzdFxuICogY29uc29sZS5sb2coZm9ybWF0Q2F1c2FsQ2hhaW4oZGFnKSk7ICAgICAvLyBodW1hbi1yZWFkYWJsZVxuICogYGBgXG4gKi9cblxuaW1wb3J0IHsgZmluZExhc3RXcml0ZXIgfSBmcm9tICcuL2NvbW1pdExvZ1V0aWxzLmpzJztcbmltcG9ydCB0eXBlIHsgUmVnaXN0ZXJlZENvZGUgfSBmcm9tICcuL2hvbmVzdHkuanMnO1xuaW1wb3J0IHsgcXVlcnlXb3JrLCByZWxhdGlvbiwgd3JpdGVzT25seUluc2lkZSB9IGZyb20gJy4va2V5UGF0aHMuanMnO1xuaW1wb3J0IHsgbG9nTW9kZWwgfSBmcm9tICcuL2xvZ01vZGVsLmpzJztcbmltcG9ydCB0eXBlIHsgQ29tbWl0QnVuZGxlLCBUcmFjZUVudHJ5LCBVbnRyYWNrZWRTb3VyY2UgfSBmcm9tICcuL3R5cGVzLmpzJztcblxuLy8g4pSA4pSAIFR5cGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKiogQSBzaW5nbGUgbm9kZSBpbiB0aGUgY2F1c2FsIERBRy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2F1c2FsTm9kZSB7XG4gIC8qKiBVbmlxdWUgZXhlY3V0aW9uIHN0ZXAgaWRlbnRpZmllci4gKi9cbiAgcnVudGltZVN0YWdlSWQ6IHN0cmluZztcbiAgLyoqIFN0YWJsZSBzdGFnZSBpZGVudGlmaWVyLiAqL1xuICBzdGFnZUlkOiBzdHJpbmc7XG4gIC8qKiBIdW1hbi1yZWFkYWJsZSBzdGFnZSBuYW1lLiAqL1xuICBzdGFnZU5hbWU6IHN0cmluZztcbiAgLyoqIEtleXMgdGhpcyBzdGFnZSB3cm90ZSAoZnJvbSBpdHMgQ29tbWl0QnVuZGxlLnRyYWNlKS4gKi9cbiAga2V5c1dyaXR0ZW46IHN0cmluZ1tdO1xuICAvKiogVGhlIGtleSB3aG9zZSByZWFk4oaSd3JpdGUgZGVwZW5kZW5jeSBsaW5rZWQgdGhpcyBub2RlIHRvIGl0cyBjaGlsZC4gRW1wdHkgZm9yIHRoZSByb290LiAqL1xuICBsaW5rZWRCeTogc3RyaW5nO1xuICAvKiogQkZTIGRlcHRoIGZyb20gdGhlIHN0YXJ0aW5nIG5vZGUgKDAgPSBzdGFydCkuICovXG4gIGRlcHRoOiBudW1iZXI7XG4gIC8qKlxuICAgKiBQYXJlbnQgbm9kZXMg4oCUIHN0YWdlcyB0aGlzIG5vZGUgZGVwZW5kcyBvbi4gREFHOiBtdWx0aXBsZSBwYXJlbnRzXG4gICAqIHBvc3NpYmxlLiBLRVBUIGZvciBjb21wYXRpYmlsaXR5OyB3aXRoIHRoZSBgY29udHJvbERlcHNgIG9wdGlvblxuICAgKiAoUkZDLTAwMyBEMykgZ292ZXJuaW5nIGRlY2lkZXJzIGFwcGVhciBoZXJlIHRvby4gRm9yIHR5cGVkL2tleWVkL1xuICAgKiB3ZWlnaHRlZCBkZXRhaWwgdXNlIHtAbGluayBwYXJlbnRFZGdlc30uXG4gICAqL1xuICBwYXJlbnRzOiBDYXVzYWxOb2RlW107XG4gIC8qKlxuICAgKiBSRkMtMDAzIEQzIOKAlCBvbmUgZWRnZSBwZXIgZGVwZW5kZW5jeSBMSU5LIChub3QgcGVyIHBhcmVudCk6IGEgbm9kZVxuICAgKiByZWFkaW5nIHR3byBrZXlzIGZyb20gdGhlIHNhbWUgd3JpdGVyIGhhcyBPTkUgZW50cnkgaW4ge0BsaW5rIHBhcmVudHN9XG4gICAqIGJ1dCBUV08gYCdkYXRhJ2AgZWRnZXMgaGVyZS4gQ29udHJvbCBkZXBlbmRlbmNpZXMgKHZpYSB0aGVcbiAgICogYGNvbnRyb2xEZXBzYCBvcHRpb24pIGFkZCBhIGAnY29udHJvbCdgIGVkZ2UgdG8gdGhlIGdvdmVybmluZyBkZWNpZGVyLlxuICAgKi9cbiAgcGFyZW50RWRnZXM6IENhdXNhbEVkZ2VbXTtcbiAgLyoqXG4gICAqIFJGQy0wMDMgRDIgaG9uZXN0eSBtYXJrZXIg4oCUIHN0YW1wZWQgZnJvbSB0aGUgc3RhZ2Unc1xuICAgKiBgQ29tbWl0QnVuZGxlLnVudHJhY2tlZFNvdXJjZXNgLiBQcmVzZW50IHdoZW4gdGhpcyBzdGFnZSBBTFNPIGNvbnN1bWVkXG4gICAqIHVudHJhY2tlZCByZWFkIHBhdGhzIChgYXJnc2AgLyBgZW52YCAvIHVuc2hhZG93ZWQgYHNpbGVudGAgcmVhZHMpOiB0aGVcbiAgICogYmFja3dhcmQgc2xpY2UgdGhyb3VnaCB0aGlzIG5vZGUgbWF5IGJlIGluY29tcGxldGUsIGJlY2F1c2UgdGhvc2UgcmVhZHNcbiAgICogcHJvZHVjZSBubyByZWFk4oaSd3JpdGUgZWRnZSB0byBmb2xsb3cuIGBmb3JtYXRDYXVzYWxDaGFpbmAgcmVuZGVycyB0aGlzXG4gICAqIGFzIGEgYOKaoCDigKYgc2xpY2UgbWF5IGJlIGluY29tcGxldGUgaGVyZWAgbGluZS4gQWJzZW50IHdoZW4gdGhlIHN0YWdlJ3NcbiAgICogcmVhZHMgd2VyZSBmdWxseSB0cmFja2VkLlxuICAgKlxuICAgKiBSZWdpc3RyeSBjb2RlOiBgJ2luY29tcGxldGUtc291cmNlcydgIChgbWVtb3J5L2hvbmVzdHkudHMgwrdcbiAgICogSE9ORVNUWV9DT0RFU2AsIHNlcnZlZCBvbiBgZm9vdHByaW50anMvdHJhY2VgKSBzYXlzIHdoYXQgdGhpcyBmaWVsZFxuICAgKiBtZWFucy4gVGhlIGZpZWxkIGNhcnJpZXMgbm8gYGNvZGVgIOKAlCBpdHMgdmFsdWVzIGFyZSB0aGVcbiAgICoge0BsaW5rIFVudHJhY2tlZFNvdXJjZX1zLlxuICAgKi9cbiAgaW5jb21wbGV0ZVNvdXJjZXM/OiBSZWFkb25seUFycmF5PFVudHJhY2tlZFNvdXJjZT47XG4gIC8qKlxuICAgKiBSRkMtMDAzIEQ0IHRydW5jYXRpb24gdmlzaWJpbGl0eSDigJQgc2V0IG9uIHRoZSBST09UIG5vZGUgb25seSwgYW5kIG9ubHlcbiAgICogd2hlbiBhIGxpbWl0IGFjdHVhbGx5IGN1dCB0aGUgc2xpY2U6IGBieURlcHRoYCB3aGVuIGEgbm9kZSBhdCB0aGVcbiAgICogYG1heERlcHRoYCBob3Jpem9uIHN0aWxsIGhhZCBlZGdlcyB0byBleHBhbmQsIGBieU5vZGVzYCB3aGVuIHRoZVxuICAgKiBgbWF4Tm9kZXNgIGJ1ZGdldCBibG9ja2VkIGNyZWF0aW5nIGEgZGlzY292ZXJlZCBwYXJlbnQuIEFic2VudCB3aGVuIHRoZVxuICAgKiBzbGljZSBpcyBjb21wbGV0ZS4gYGZvcm1hdENhdXNhbENoYWluYCBhcHBlbmRzIGEgYOKaoCBzbGljZSB0cnVuY2F0ZWQg4oCmYFxuICAgKiBsaW5lIOKAlCBhIGNvbnN1bWVyIG11c3QgbmV2ZXIgbWlzdGFrZSBhIHRydW5jYXRlZCBzbGljZSBmb3IgYSBmdWxsIG9uZS5cbiAgICogKFVudGlsIDkuNDguMCBkZXYgbW9kZSBhbHNvIHdhcm5lZCBvbiB0aGUgY29uc29sZTsgdGhlIGZpZWxkIGlzIHRoZVxuICAgKiBzaWduYWwsIHJlYWQgaXQuKVxuICAgKlxuICAgKiBSZWdpc3RyeSBjb2RlOiBgJ3RydW5jYXRlZCdgIChgbWVtb3J5L2hvbmVzdHkudHMgwrcgSE9ORVNUWV9DT0RFU2AsIHNlcnZlZFxuICAgKiBvbiBgZm9vdHByaW50anMvdHJhY2VgKSBzYXlzIHdoYXQgdGhpcyBmaWVsZCBtZWFuczsgdGhlIGZpZWxkIGNhcnJpZXMgbm9cbiAgICogYGNvZGVgLlxuICAgKi9cbiAgdHJ1bmNhdGVkPzogeyBieURlcHRoOiBib29sZWFuOyBieU5vZGVzOiBib29sZWFuIH07XG4gIC8qKlxuICAgKiBGNGIgKDkuMzMuMCkg4oCUIHRoZSBrZXlzIHRoaXMgbm9kZSByZWFkIHRoYXQgTk8gY29tbWl0IGJlZm9yZSBpdCB3cm90ZSAodW5kZXIgdGhlIHdyaXRlciBydWxlKSwgc28gdGhlXG4gICAqIHdhbGsgaGFzIG5vIGVkZ2UgdG8gZm9sbG93IGZvciB0aGVtOiB0aGVpciB2YWx1ZSBjYW1lIGZyb20gdGhlIGluaXRpYWwgc3RhdGUsIGZyb3plbiBydW4gaW5wdXQgb3IgYVxuICAgKiBjbG9zdXJlIOKAlCBvdXRzaWRlIHRoZSBjb21taXQgbG9nLiBUaGUgY29kZSBzYXlzIHNvIChgJ3ByZS1ydW4tb3JpZ2luJ2AsIHJlZ2lzdGVyZWQgaW5cbiAgICogYG1lbW9yeS9ob25lc3R5LnRzIMK3IEhPTkVTVFlfQ09ERVNgKTsgYGtleXNgIGFyZSBpbiB0aGUgb3JkZXIgdGhlIHdhbGsgbWV0IHRoZW0uIEFCU0VOVCB3aGVuIGV2ZXJ5IGtleVxuICAgKiB0aGUgbm9kZSBleHBhbmRlZCBoYWQgYSB3cml0ZXIsIHNvIHN1Y2ggYSBub2RlIGtlZXBzIGl0cyA5LjMyLjAgc2hhcGUuIEJlZm9yZSA5LjMzLjAgdGhlc2UgcmVhZHMgd2VyZVxuICAgKiBkcm9wcGVkIHdpdGhvdXQgYSB3b3JkLlxuICAgKi9cbiAgcHJlUnVuUmVhZHM/OiB7IGNvZGU6IFJlZ2lzdGVyZWRDb2RlPCdwcmUtcnVuLW9yaWdpbic+OyBrZXlzOiBzdHJpbmdbXSB9O1xufVxuXG4vKipcbiAqIFJGQy0wMDMgRDMg4oCUIGEgdHlwZWQgZGVwZW5kZW5jeSBlZGdlIGZyb20gYSBjaGlsZCBub2RlIHRvIG9uZSBwYXJlbnQuXG4gKlxuICogLSBga2luZDogJ2RhdGEnYCAgICDigJQgcmVhZOKGkndyaXRlIGRlcGVuZGVuY3k7IGBrZXlgIGlzIHRoZSBzdGF0ZSBrZXkuXG4gKiAtIGBraW5kOiAnY29udHJvbCdgIOKAlCB0aGUgcGFyZW50IGlzIHRoZSBkZWNpZGVyL3NlbGVjdG9yIHdob3NlIGRlY2lzaW9uXG4gKiAgIGFsbG93ZWQgdGhlIGNoaWxkIHRvIHJ1bjsgYGtleWAgaXMgdGhlIGRlY2lkZSgpIHJ1bGUgbGFiZWwgd2hlbiBwcmVzZW50LlxuICpcbiAqIGB3ZWlnaHRgIGRlZmF1bHRzIHRvIDEuMDsgdGhlIGB3ZWlnaGAgaG9vayAoUkZDLTAwMyBENCkgY2FuIG92ZXJyaWRlIGl0LlxuICogVGhlIGVuZ2luZSBpdHNlbGYgTkVWRVIgY29tcHV0ZXMgd2VpZ2h0cyDigJQgc2VtYW50aWNzIGJlbG9uZyB0byB0aGVcbiAqIGNvbnN1bWVyLWluamVjdGVkIHdlaWdoZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2F1c2FsRWRnZSB7XG4gIHBhcmVudDogQ2F1c2FsTm9kZTtcbiAga2luZDogJ2RhdGEnIHwgJ2NvbnRyb2wnO1xuICBrZXk/OiBzdHJpbmc7XG4gIHdlaWdodDogbnVtYmVyO1xuICAvKipcbiAgICogRjRiICg5LjMzLjApIOKAlCBwcmVzZW50IG9ubHkgb24gYSBgJ2RhdGEnYCBlZGdlIHdob3NlIHBhcmVudCB3cm90ZSBga2V5YCBPTkxZIHRocm91Z2ggcm93cyBpbnNpZGUgaXRcbiAgICogKGEgc3ViZmxvdydzIGlucHV0IHNlZWQsIGFuIG91dHB1dE1hcHBlciBtZXJnZS1iYWNrLCBhIGZvcmsgY2hpbGQncyBuYW1lc3BhY2UpOiB0aGF0IHdyaXRlIG1hZGUgcGFydFxuICAgKiBvZiB0aGUgdmFsdWUsIGFuZCBlYXJsaWVyIHdyaXRlcnMgbWF5IGFjY291bnQgZm9yIHRoZSByZXN0LiBSZWdpc3RlcmVkIGFzIGAnbmVzdGVkLXJvd3MnYCBpblxuICAgKiBgbWVtb3J5L2hvbmVzdHkudHMgwrcgSE9ORVNUWV9DT0RFU2AuIEFic2VudCBmb3IgYSB3cml0ZSBvbiBvciBhcm91bmQgdGhlIGtleSwgc28gYW4gZXhhY3QgZWRnZSBrZWVwc1xuICAgKiBpdHMgOS4zMi4wIHNoYXBlLlxuICAgKi9cbiAgYmFzaXM/OiBSZWdpc3RlcmVkQ29kZTwnbmVzdGVkLXJvd3MnPjtcbn1cblxuLyoqXG4gKiBSRkMtMDAzIEQzIOKAlCBhIGNvbnRyb2wgZGVwZW5kZW5jeSByZXNvbHZlZCBmb3Igb25lIGV4ZWN1dGlvbiBzdGVwOlxuICogd2hpY2ggZGVjaWRlci9zZWxlY3RvciBleGVjdXRpb24gYWxsb3dlZCB0aGlzIHN0YWdlIHRvIHJ1bi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb250cm9sRGVwZW5kZW5jeSB7XG4gIC8qKiBydW50aW1lU3RhZ2VJZCBvZiB0aGUgZ292ZXJuaW5nIGRlY2lkZXIvc2VsZWN0b3IgZXhlY3V0aW9uIHN0ZXAuICovXG4gIGRlY2lkZXJJZDogc3RyaW5nO1xuICAvKiogVGhlIGRlY2lkZSgpIHJ1bGUgbGFiZWwgZm9yIHRoZSBjaG9zZW4gYnJhbmNoLCB3aGVuIHByZXNlbnQuICovXG4gIGxhYmVsPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJGQy0wMDMgRDMg4oCUIGNhbGxiYWNrIHJlc29sdmluZyB0aGUgZ292ZXJuaW5nIGRlY2lkZXIgZm9yIGFuIGV4ZWN1dGlvblxuICogc3RlcC4gUmV0dXJuIGB1bmRlZmluZWRgIHdoZW4gdGhlIHN0ZXAgaXMgbm90IGNvbnRyb2wtZGVwZW5kZW50IG9uIGFueVxuICogcmVjb3JkZWQgZGVjaXNpb24uIEJ1aWxkIG9uZSB3aXRoIGBjb250cm9sRGVwUmVjb3JkZXIoKWAgZnJvbVxuICogYGZvb3RwcmludGpzL3RyYWNlYCwgb3Igc3VwcGx5IHlvdXIgb3duLlxuICovXG5leHBvcnQgdHlwZSBDb250cm9sRGVwTG9va3VwID0gKHJ1bnRpbWVTdGFnZUlkOiBzdHJpbmcpID0+IENvbnRyb2xEZXBlbmRlbmN5IHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIFJGQy0wMDMgRDQg4oCUIGNvbnN1bWVyLWluamVjdGVkIGVkZ2Ugd2VpZ2hlci4gQ2FsbGVkIG9uY2UgcGVyIGNyZWF0ZWRcbiAqIGVkZ2U7IHJldHVybiBhIHdlaWdodCwgb3IgYHVuZGVmaW5lZGAgdG8ga2VlcCB0aGUgZGVmYXVsdCAxLjAuIFRoZVxuICogRU5HSU5FIG5ldmVyIGNvbXB1dGVzIHdlaWdodHMgKHplcm8gbmV3IGRlcGVuZGVuY2llcyDigJQgc2VtYW50aWNzIGxpa2VcbiAqIGVtYmVkZGluZyBzaW1pbGFyaXR5IG9yIEZETCBpbmZsdWVuY2UgYmVsb25nIHRvIGRvd25zdHJlYW0gbGlicmFyaWVzLFxuICogdGhlIHNhbWUgcGx1Zy1pbiBwYXR0ZXJuIGFzIGBOYXJyYXRpdmVGb3JtYXR0ZXJgKS4gV2VpZ2h0cyByZW5kZXIgaW5cbiAqIGBmb3JtYXRDYXVzYWxDaGFpbmAgYXMgYOKGkCB2aWEgc3lzdGVtUHJvbXB0ICgwLjE4KWAuXG4gKi9cbmV4cG9ydCB0eXBlIEVkZ2VXZWlnaGVyID0gKFxuICBjaGlsZDogQ2F1c2FsTm9kZSxcbiAgcGFyZW50OiBDYXVzYWxOb2RlLFxuICBrZXk6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAga2luZDogJ2RhdGEnIHwgJ2NvbnRyb2wnLFxuKSA9PiBudW1iZXIgfCB1bmRlZmluZWQ7XG5cbi8qKiBPcHRpb25zIGZvciBjYXVzYWxDaGFpbigpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBDYXVzYWxDaGFpbk9wdGlvbnMge1xuICAvKiogTWF4aW11bSBCRlMgZGVwdGggKGRlZmF1bHQ6IDIwKS4gUHJldmVudHMgcnVuYXdheSB0cmF2ZXJzYWwuICovXG4gIG1heERlcHRoPzogbnVtYmVyO1xuICAvKiogTWF4aW11bSB0b3RhbCBub2RlcyB0byB2aXNpdCAoZGVmYXVsdDogMTAwKS4gSGFyZCBjYXAgZm9yIHNhZmV0eS4gKi9cbiAgbWF4Tm9kZXM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBSRkMtMDAzIEQzIOKAlCBjb250cm9sLWRlcGVuZGVuY2UgbG9va3VwLiBXaGVuIHByb3ZpZGVkLCBleHBhbmRpbmcgYSBub2RlXG4gICAqIEFMU08gbGlua3MgYSBgJ2NvbnRyb2wnYCBlZGdlIHRvIGl0cyBnb3Zlcm5pbmcgZGVjaWRlciAobGFiZWxlZCBieSB0aGVcbiAgICogZGVjaWRlKCkgcnVsZSBsYWJlbCB3aGVuIHByZXNlbnQpOyB0aGUgZGVjaWRlciBub2RlIHRoZW4gZXhwYW5kc1xuICAgKiBub3JtYWxseSB0aHJvdWdoIGl0cyBvd24gZGF0YSByZWFkcywgc28gY2hhaW5zIGxpa2VcbiAgICogYHN0YXR1cyDihpAgW2NvbnRyb2xdIENsYXNzaWZ5UmlzayDihpAgW2RhdGE6IGNyZWRpdFNjb3JlXSBQdWxsQnVyZWF1YFxuICAgKiByZXNvbHZlIGVuZC10by1lbmQuIFdpdGhvdXQgdGhpcyBvcHRpb24gYmVoYXZpb3IgaXMgdW5jaGFuZ2VkLlxuICAgKi9cbiAgY29udHJvbERlcHM/OiBDb250cm9sRGVwTG9va3VwO1xuICAvKipcbiAgICogUkZDLTAwMyBENCDigJQgZWRnZSB3ZWlnaGVyLiBTdGFtcHMgYENhdXNhbEVkZ2Uud2VpZ2h0YCBhdCBlZGdlIGNyZWF0aW9uO1xuICAgKiBgdW5kZWZpbmVkYCAob3Igbm8gd2VpZ2hlcikg4oaSIDEuMC4gU2VlIHtAbGluayBFZGdlV2VpZ2hlcn0uXG4gICAqL1xuICB3ZWlnaD86IEVkZ2VXZWlnaGVyO1xuICAvKipcbiAgICogI1AxIOKAlCBob3cgYSBub2RlJ3MgZXhwYW5zaW9uIHJlYWQtc2V0IGlzIGRlcml2ZWQ6XG4gICAqXG4gICAqIC0gYCdzdGFnZSdgIChkZWZhdWx0LCBoaXN0b3JpY2FsKSDigJQgZXZlcnkgdmlzaXRlZCBub2RlIGV4cGFuZHMgdGhyb3VnaFxuICAgKiAgIEFMTCBvZiBpdHMgc3RhZ2UncyByZWFkcyAoYGdldEtleXNSZWFkYCkuIEEgc3RhZ2UgcmVhZGluZyBgYSxiYCBhbmRcbiAgICogICB3cml0aW5nIGB4LHlgIGxpbmtzIGJvdGggcmVhZHMgYXMgY2F1c2VzIG9mIGJvdGggd3JpdGVzIOKAlCBhIHNvdW5kIGJ1dFxuICAgKiAgIGNvYXJzZSBvdmVyLWFwcHJveGltYXRpb24uXG4gICAqIC0gYCdwZXItd3JpdGUnYCDigJQgd2hlbiB0aGUgY29tbWl0IGxvZyBjYXJyaWVzIHBlci13cml0ZSByZWFkIHByb3ZlbmFuY2VcbiAgICogICAoYFRyYWNlRW50cnkucmVhZEtleXNgLCByZWNvcmRlZCB1bmRlciB0aGUgZXhlY3V0b3Inc1xuICAgKiAgIGB3cml0ZVByb3ZlbmFuY2U6ICdyZWFkcy1wcmVmaXgnYCBkaWFsKSwgYSBub2RlIHJlYWNoZWQgdmlhIGtleSBga2BcbiAgICogICBleHBhbmRzIHRocm91Z2ggT05MWSB0aGUgcmVhZHMgdGhhdCBwcmVjZWRlZCBpdHMgd3JpdGUgb2YgYGtgXG4gICAqICAgKHRlbXBvcmFsIHByZWZpeCkuIE5vZGVzIGxpbmtlZCBsYXRlciB2aWEgYWRkaXRpb25hbCBrZXlzIGFyZVxuICAgKiAgIGluY3JlbWVudGFsbHkgcmUtZXhwYW5kZWQgd2l0aCBqdXN0IHRoZSBuZXcgcmVhZHMgKHdvcmtsaXN0IOKAlCB0aGVcbiAgICogICBzbGljZSBvbmx5IGV2ZXIgR1JPV1MgdG93YXJkIHRoZSBzdGFnZS1sZXZlbCBjZWlsaW5nKS4gSE9ORVNUXG4gICAqICAgRkFMTEJBQ0s6IGFueSBsaW5rIHdob3NlIHRyYWNlIGVudHJ5IGxhY2tzIGByZWFkS2V5c2AgZXhwYW5kcyB0aGF0XG4gICAqICAgbm9kZSBhdCBzdGFnZSBsZXZlbCDigJQgbWl4ZWQgb3IgZGlhbC1vZmYgbG9ncyBkZWdyYWRlIHRvIGAnc3RhZ2UnYFxuICAgKiAgIGJlaGF2aW9yIGV4YWN0bHksIG5ldmVyIHRvIHNpbGVuY2UuXG4gICAqL1xuICBlZGdlQXR0cmlidXRpb24/OiAnc3RhZ2UnIHwgJ3Blci13cml0ZSc7XG4gIC8qKlxuICAgKiAjUDEg4oCUIHRoZSB3cml0dGVuIGtleXMgdGhhdCBhbmNob3IgdGhlIFJPT1QncyBleHBhbnNpb24gdW5kZXJcbiAgICogYCdwZXItd3JpdGUnYCAoZS5nLiBgc2xpY2VGb3JLZXlgIHBhc3NlcyB0aGUgc2xpY2VkIGtleSwgc28gdGhlIHJvb3RcbiAgICogZXhwYW5kcyB0aHJvdWdoIHRoZSByZWFkcyB0aGF0IGZlZCBUSEFUIHdyaXRlLCBub3QgdGhlIHdob2xlIHN0YWdlKS5cbiAgICogSWdub3JlZCB1bmRlciBgJ3N0YWdlJ2AuIFVuc2V0IOKGkiByb290IGV4cGFuZHMgYXQgc3RhZ2UgbGV2ZWwuXG4gICAqL1xuICByb290TGlua0tleXM/OiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBDYWxsYmFjayB0aGF0IHJldHVybnMgdGhlIGtleXMgYSBzdGFnZSByZWFkIGR1cmluZyBleGVjdXRpb24uXG4gKiBUaGUgYmFja3RyYWNrZXIgY2FsbHMgdGhpcyBmb3IgZWFjaCB2aXNpdGVkIG5vZGUgdG8gZGV0ZXJtaW5lXG4gKiB3aGljaCByZWFk4oaSd3JpdGUgZWRnZXMgdG8gZm9sbG93LlxuICpcbiAqIEltcGxlbWVudG9yczogUXVhbGl0eVJlY29yZGVyIHRyYWNrcyBrZXlzUmVhZCBwZXIgc3RlcCxcbiAqIG9yIGJ1aWxkIGEgTWFwPHJ1bnRpbWVTdGFnZUlkLCBzdHJpbmdbXT4gZnJvbSBTY29wZVJlY29yZGVyLm9uUmVhZCBldmVudHMuXG4gKi9cbmV4cG9ydCB0eXBlIEtleXNSZWFkTG9va3VwID0gKHJ1bnRpbWVTdGFnZUlkOiBzdHJpbmcpID0+IHN0cmluZ1tdO1xuXG4vLyDilIDilIAgU3RhZ2VkIG9wdGltaXphdGlvbjogd3JpdGVyIGxvb2t1cCBzdHJhdGVnaWVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKipcbiAqIFRocmVzaG9sZCBmb3Igc3dpdGNoaW5nIGZyb20gbGluZWFyIHNjYW4gdG8gcmV2ZXJzZSBpbmRleC5cbiAqIEJlbG93IHRoaXMsIE8oTikgc2NhbiBpcyBmYXN0ZXIgKG5vIGluZGV4IGJ1aWxkIGNvc3QpLlxuICogQWJvdmUgdGhpcywgTyhsb2cgTikgYmluYXJ5IHNlYXJjaCB3aW5zLlxuICovXG5jb25zdCBSRVZFUlNFX0lOREVYX1RIUkVTSE9MRCA9IDI1NjtcblxuLyoqXG4gKiBXcml0ZXIgbG9va3VwIGZ1bmN0aW9uIHNpZ25hdHVyZS5cbiAqIFJldHVybnMgdGhlIENvbW1pdEJ1bmRsZSB0aGF0IGxhc3Qgd3JvdGUgYGtleWAgYmVmb3JlIHBvc2l0aW9uIGBiZWZvcmVJZHhgLlxuICovXG50eXBlIFdyaXRlckxvb2t1cCA9IChrZXk6IHN0cmluZywgYmVmb3JlSWR4OiBudW1iZXIpID0+IENvbW1pdEJ1bmRsZSB8IHVuZGVmaW5lZDtcblxuLyoqIFN0cmF0ZWd5IDE6IExpbmVhciBzY2FuIOKAlCBPKE4pIHBlciBsb29rdXAsIHplcm8gc2V0dXAgY29zdC4gKi9cbmZ1bmN0aW9uIGxpbmVhclNjYW5Mb29rdXAoY29tbWl0TG9nOiBDb21taXRCdW5kbGVbXSk6IFdyaXRlckxvb2t1cCB7XG4gIHJldHVybiAoa2V5LCBiZWZvcmVJZHgpID0+IGZpbmRMYXN0V3JpdGVyKGNvbW1pdExvZywga2V5LCBiZWZvcmVJZHgpO1xufVxuXG4vKipcbiAqIFN0cmF0ZWd5IDI6IFJldmVyc2UgaW5kZXgg4oCUIG9uZSBPKHJvd3MpIGJ1aWxkLCBPKGRlcHRoICsgbG9nIE4pIHBlciBsb29rdXAuXG4gKiBUaGUgbG9nJ3MgcmVhZCBtb2RlbCAoYGxvZ01vZGVsLnRzYDogYSBwYXRoIHRyaWUsIGVhY2ggdG9wLWxldmVsIGtleSBmb2xkZWQgYXRcbiAqIG1vc3Qgb25jZSkgYW5zd2VycyB0aGUgd3JpdGVyIHJ1bGUg4oCUIHJvd3Mgb24sIGluc2lkZSBvciBhcm91bmQgdGhlIGtleSDigJQgYnlcbiAqIGJpbmFyeSBzZWFyY2ggZm9yIHRoZSBsYXN0IHdyaXRlIG9uIG9yIGluc2lkZSBpdCwgdGhlbiBhIHZlcmRpY3Qgb25seSBmb3IgdGhlXG4gKiBhcm91bmQtY2FuZGlkYXRlcyBhZnRlciBpdC4gVGhlIHNhbWUgYW5zd2VyIGBmaW5kTGFzdFdyaXRlcmAgZ2l2ZXMsIHNvIHRoZVxuICogc3RyYXRlZ3kgc3dpdGNoIGJlbG93IG5ldmVyIGNoYW5nZXMgYSBzbGljZS5cbiAqL1xuZnVuY3Rpb24gcmV2ZXJzZUluZGV4TG9va3VwKGNvbW1pdExvZzogQ29tbWl0QnVuZGxlW10pOiBXcml0ZXJMb29rdXAge1xuICBjb25zdCBtb2RlbCA9IGxvZ01vZGVsKGNvbW1pdExvZyk7XG4gIHJldHVybiAoa2V5OiBzdHJpbmcsIGJlZm9yZUlkeDogbnVtYmVyKTogQ29tbWl0QnVuZGxlIHwgdW5kZWZpbmVkID0+IHtcbiAgICBjb25zdCBhdCA9IG1vZGVsLmxhc3RXcml0ZXJCZWZvcmUoa2V5LCBiZWZvcmVJZHgpO1xuICAgIHJldHVybiBhdCA+PSAwID8gY29tbWl0TG9nW2F0XSA6IHVuZGVmaW5lZDtcbiAgfTtcbn1cblxuLyoqXG4gKiBUaGUgdHJhY2UgZW50cmllcyBvZiBgY29tbWl0YCB0aGF0IG1ha2UgaXQgYSB3cml0ZXIgb2YgYGxpbmtLZXlgIOKAlCB0aGUgZW50cmllcyB3aG9zZSByZWFkXG4gKiBwcmVmaXggKGBUcmFjZUVudHJ5LnJlYWRLZXlzYCkgYSBwZXItd3JpdGUgZWRnZSBleHBhbmRzIHRocm91Z2guIFRoZSBGSVJTVCBlbnRyeSBvbiB0aGUgZXhhY3RcbiAqIHBhdGggd2hlbiB0aGVyZSBpcyBvbmUgKHRoZSAjUDEgYmVoYXZpb3VyLCB1bmNoYW5nZWQpOyBvdGhlcndpc2UgZXZlcnkgZW50cnkgaW5zaWRlIG9yIGFyb3VuZFxuICogdGhlIGtleSAoOS4zMy4wOiB0aGUgY29tbWl0IHdyb3RlIHRoZSBrZXkgdGhyb3VnaCBhIG5lc3RlZCByb3cg4oCUIGEgc3ViZmxvdyBzZWVkLCBhblxuICogb3V0cHV0TWFwcGVyIG1lcmdlLWJhY2sg4oCUIGFuZCBhbGwgb2YgdGhvc2Ugcm93cyB3cm90ZSBpdCkuXG4gKi9cbmZ1bmN0aW9uIGxpbmtpbmdFbnRyaWVzKGNvbW1pdDogQ29tbWl0QnVuZGxlLCBsaW5rS2V5OiBzdHJpbmcpOiBUcmFjZUVudHJ5W10ge1xuICBjb25zdCBleGFjdCA9IGNvbW1pdC50cmFjZS5maW5kKCh0KSA9PiB0LnBhdGggPT09IGxpbmtLZXkpO1xuICBpZiAoZXhhY3QgIT09IHVuZGVmaW5lZCkgcmV0dXJuIFtleGFjdF07XG4gIHJldHVybiBjb21taXQudHJhY2UuZmlsdGVyKCh0KSA9PiByZWxhdGlvbih0LnBhdGgsIGxpbmtLZXkpICE9PSB1bmRlZmluZWQpO1xufVxuXG4vKipcbiAqIFN0YWdlZCBvcHRpbWl6YXRpb246IHBpY2sgdGhlIHJpZ2h0IHdyaXRlci1sb29rdXAgc3RyYXRlZ3kgYmFzZWQgb24gZGF0YSBzaXplLlxuICpcbiAqIExpa2UgYSBkYXRhYmFzZSBxdWVyeSBvcHRpbWl6ZXIgY2hvb3NpbmcgYmV0d2VlbiBzZXF1ZW50aWFsIHNjYW4gYW5kIGluZGV4IHNjYW46XG4gKlxuICogLSAqKlNtYWxsIGxvZyAo4omkIDI1Nik6KiogTGluZWFyIHNjYW4gd2lucy4gWmVybyBzZXR1cCBjb3N0LCBnb29kIGNhY2hlIGxvY2FsaXR5LlxuICogICBUaGUgb3ZlcmhlYWQgb2YgYnVpbGRpbmcgYSByZXZlcnNlIGluZGV4IGlzbid0IHdvcnRoIGl0IGZvciBzaG9ydCBsb2dzLlxuICpcbiAqIC0gKipMYXJnZSBsb2cgKD4gMjU2KToqKiBSZXZlcnNlIGluZGV4IHdpbnMuIE8oTsOXVSkgdXBmcm9udCBidWlsZCBjb3N0IGlzIGFtb3J0aXplZFxuICogICBhY3Jvc3MgYWxsIEJGUyBob3BzLiBFYWNoIGxvb2t1cCBiZWNvbWVzIE8obG9nIE4pIHZpYSBiaW5hcnkgc2VhcmNoIGluc3RlYWQgb2YgTyhOKS5cbiAqICAgRm9yIGFuIGFnZW50IGxvb3Agd2l0aCA1MDAgaXRlcmF0aW9ucyBhbmQgNSBrZXlzIHBlciBob3AsIHRoaXMgaXMgNTAww5c1w5dsb2coNTAwKeKJiDIySyBvcHNcbiAqICAgdnMgNTAww5c1w5c1MDA9MS4yNU0gb3BzIHdpdGggbGluZWFyIHNjYW4uXG4gKlxuICogVGhlIGNhbGxlciBuZXZlciBzZWVzIHRoaXMg4oCUIGBjYXVzYWxDaGFpbigpYCBwaWNrcyBhdXRvbWF0aWNhbGx5LlxuICovXG5mdW5jdGlvbiBjcmVhdGVXcml0ZXJMb29rdXAoY29tbWl0TG9nOiBDb21taXRCdW5kbGVbXSk6IFdyaXRlckxvb2t1cCB7XG4gIGlmIChjb21taXRMb2cubGVuZ3RoIDw9IFJFVkVSU0VfSU5ERVhfVEhSRVNIT0xEKSB7XG4gICAgcmV0dXJuIGxpbmVhclNjYW5Mb29rdXAoY29tbWl0TG9nKTtcbiAgfVxuICByZXR1cm4gcmV2ZXJzZUluZGV4TG9va3VwKGNvbW1pdExvZyk7XG59XG5cbi8vIOKUgOKUgCBDb3JlIGFsZ29yaXRobSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqXG4gKiBSRkMtMDAzIEQyOiB0aGUgYGluY29tcGxldGVTb3VyY2VzYCBub2RlIGZyYWdtZW50IGZvciBhIGNvbW1pdCDigJQgYHt9YFxuICogd2hlbiB0aGUgc3RhZ2UgY29uc3VtZWQgbm8gdW50cmFja2VkIHJlYWQgcGF0aHMsIGtlZXBpbmcgdGhlIGZpZWxkXG4gKiBBQlNFTlQgKG5vdCBlbXB0eS1hcnJheS12YWx1ZWQpIGZvciBmdWxseS10cmFja2VkIHN0YWdlcy5cbiAqL1xuZnVuY3Rpb24gaW5jb21wbGV0ZVNvdXJjZXNGcmFnbWVudChjb21taXQ6IENvbW1pdEJ1bmRsZSk6IHsgaW5jb21wbGV0ZVNvdXJjZXM/OiBSZWFkb25seUFycmF5PFVudHJhY2tlZFNvdXJjZT4gfSB7XG4gIGlmICghY29tbWl0LnVudHJhY2tlZFNvdXJjZXMgfHwgY29tbWl0LnVudHJhY2tlZFNvdXJjZXMubGVuZ3RoID09PSAwKSByZXR1cm4ge307XG4gIHJldHVybiB7IGluY29tcGxldGVTb3VyY2VzOiBjb21taXQudW50cmFja2VkU291cmNlcyB9O1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBjYXVzYWwgREFHIHJvb3RlZCBhdCBgc3RhcnRJZGAgYnkgd2Fsa2luZyBiYWNrd2FyZHNcbiAqIHRocm91Z2ggcmVhZOKGkndyaXRlIGRlcGVuZGVuY2llcyBpbiB0aGUgY29tbWl0IGxvZy5cbiAqXG4gKiBBdXRvbWF0aWNhbGx5IHNlbGVjdHMgdGhlIG9wdGltYWwgd3JpdGVyIGxvb2t1cCBzdHJhdGVneTpcbiAqIC0gTGluZWFyIHNjYW4gZm9yIHNtYWxsIGxvZ3MgKOKJpCAyNTYgY29tbWl0cylcbiAqIC0gUmV2ZXJzZSBpbmRleCB3aXRoIGJpbmFyeSBzZWFyY2ggZm9yIGxhcmdlIGxvZ3MgKD4gMjU2IGNvbW1pdHMpXG4gKlxuICogUHJvZHVjZXMgYSBEQUcgKG5vdCBhIHRyZWUpOiBpZiB0d28gY2hpbGRyZW4gYm90aCByZWFkIGZyb20gdGhlIHNhbWVcbiAqIHBhcmVudCwgdGhlIHBhcmVudCBub2RlIGlzIHNoYXJlZCAoZGVkdXBlZCBieSBydW50aW1lU3RhZ2VJZCkuXG4gKlxuICogQHBhcmFtIGNvbW1pdExvZyAgIE9yZGVyZWQgY29tbWl0IGJ1bmRsZXMgZnJvbSBleGVjdXRvci5nZXRTbmFwc2hvdCgpLmNvbW1pdExvZ1xuICogQHBhcmFtIHN0YXJ0SWQgICAgIHJ1bnRpbWVTdGFnZUlkIHRvIHN0YXJ0IGJhY2t0cmFja2luZyBmcm9tXG4gKiBAcGFyYW0gZ2V0S2V5c1JlYWQgQ2FsbGJhY2sgcmV0dXJuaW5nIGtleXMgcmVhZCBieSBhIGdpdmVuIGV4ZWN1dGlvbiBzdGVwXG4gKiBAcGFyYW0gb3B0aW9ucyAgICAgRGVwdGggYW5kIG5vZGUgbGltaXRzXG4gKiBAcmV0dXJucyBSb290IENhdXNhbE5vZGUgd2l0aCAucGFyZW50cyBmb3JtaW5nIHRoZSBEQUcsIG9yIHVuZGVmaW5lZCBpZiBzdGFydElkIG5vdCBmb3VuZFxuICovXG5leHBvcnQgZnVuY3Rpb24gY2F1c2FsQ2hhaW4oXG4gIGNvbW1pdExvZzogQ29tbWl0QnVuZGxlW10sXG4gIHN0YXJ0SWQ6IHN0cmluZyxcbiAgZ2V0S2V5c1JlYWQ6IEtleXNSZWFkTG9va3VwLFxuICBvcHRpb25zPzogQ2F1c2FsQ2hhaW5PcHRpb25zLFxuKTogQ2F1c2FsTm9kZSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG1heERlcHRoID0gb3B0aW9ucz8ubWF4RGVwdGggPz8gMjA7XG4gIGNvbnN0IG1heE5vZGVzID0gb3B0aW9ucz8ubWF4Tm9kZXMgPz8gMTAwO1xuICBjb25zdCBjb250cm9sRGVwcyA9IG9wdGlvbnM/LmNvbnRyb2xEZXBzO1xuICBjb25zdCB3ZWlnaCA9IG9wdGlvbnM/LndlaWdoO1xuICBjb25zdCBwZXJXcml0ZSA9IG9wdGlvbnM/LmVkZ2VBdHRyaWJ1dGlvbiA9PT0gJ3Blci13cml0ZSc7XG5cbiAgLy8gUkZDLTAwMyBENCDigJQgdHJ1bmNhdGlvbiB2aXNpYmlsaXR5LiBTZXQgb25seSB3aGVuIGEgbGltaXQgYWN0dWFsbHlcbiAgLy8gY3V0cyB0aGUgc2xpY2U7IHN1cmZhY2VkIG9uIHRoZSByb290IGFzIGB0cnVuY2F0ZWRgIHNvIGEgY29uc3VtZXIgY2FuXG4gIC8vIG5ldmVyIG1pc3Rha2UgYSB0cnVuY2F0ZWQgc2xpY2UgZm9yIGEgY29tcGxldGUgb25lLlxuICBsZXQgdHJ1bmNhdGVkQnlEZXB0aCA9IGZhbHNlO1xuICBsZXQgdHJ1bmNhdGVkQnlOb2RlcyA9IGZhbHNlO1xuXG4gIC8vIEJ1aWxkIHBvc2l0aW9uIGluZGV4OiBydW50aW1lU3RhZ2VJZCDihpIgYXJyYXkgcG9zaXRpb24gKE8obikgb25jZSlcbiAgY29uc3QgaWR4TWFwID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb21taXRMb2cubGVuZ3RoOyBpKyspIHtcbiAgICBpZHhNYXAuc2V0KGNvbW1pdExvZ1tpXS5ydW50aW1lU3RhZ2VJZCwgaSk7XG4gIH1cbiAgcXVlcnlXb3JrLnVuaXRzICs9IGNvbW1pdExvZy5sZW5ndGg7XG5cbiAgY29uc3Qgc3RhcnRJZHggPSBpZHhNYXAuZ2V0KHN0YXJ0SWQpO1xuICBpZiAoc3RhcnRJZHggPT09IHVuZGVmaW5lZCkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICBjb25zdCBzdGFydENvbW1pdCA9IGNvbW1pdExvZ1tzdGFydElkeF07XG5cbiAgLy8gUGljayB3cml0ZXIgbG9va3VwIHN0cmF0ZWd5IGJhc2VkIG9uIGxvZyBzaXplXG4gIGNvbnN0IGZpbmRXcml0ZXIgPSBjcmVhdGVXcml0ZXJMb29rdXAoY29tbWl0TG9nKTtcblxuICAvLyBOb2RlIGRlZHVwIG1hcDogcnVudGltZVN0YWdlSWQg4oaSIENhdXNhbE5vZGUgKGVuc3VyZXMgREFHLCBub3QgdHJlZSlcbiAgY29uc3Qgbm9kZU1hcCA9IG5ldyBNYXA8c3RyaW5nLCBDYXVzYWxOb2RlPigpO1xuXG4gIGNvbnN0IHJvb3Q6IENhdXNhbE5vZGUgPSB7XG4gICAgcnVudGltZVN0YWdlSWQ6IHN0YXJ0SWQsXG4gICAgc3RhZ2VJZDogc3RhcnRDb21taXQuc3RhZ2VJZCxcbiAgICBzdGFnZU5hbWU6IHN0YXJ0Q29tbWl0LnN0YWdlLFxuICAgIGtleXNXcml0dGVuOiBzdGFydENvbW1pdC50cmFjZS5tYXAoKHQpID0+IHQucGF0aCksXG4gICAgbGlua2VkQnk6ICcnLFxuICAgIGRlcHRoOiAwLFxuICAgIHBhcmVudHM6IFtdLFxuICAgIHBhcmVudEVkZ2VzOiBbXSxcbiAgICAuLi5pbmNvbXBsZXRlU291cmNlc0ZyYWdtZW50KHN0YXJ0Q29tbWl0KSxcbiAgfTtcbiAgbm9kZU1hcC5zZXQoc3RhcnRJZCwgcm9vdCk7XG5cbiAgLy8g4pSA4pSAICNQMSBwZXItd3JpdGUgYXR0cmlidXRpb24gbWFjaGluZXJ5IChpbmVydCB1bmRlciAnc3RhZ2UnKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gZXhwYW5kZWRSZWFkczogcGVyIG5vZGUsIHRoZSByZWFkcyBhbHJlYWR5IHF1ZXVlZCBmb3IgZXhwYW5zaW9uIOKAlCBsYXRlXG4gIC8vIGxpbmtzIHZpYSBhZGRpdGlvbmFsIGtleXMgcmUtZW5xdWV1ZSBvbmx5IHRoZSBERUxUQSwgc28gdGhlIHNsaWNlIGdyb3dzXG4gIC8vIG1vbm90b25pY2FsbHkgdG93YXJkIHRoZSBzdGFnZS1sZXZlbCBjZWlsaW5nIGFuZCB0ZXJtaW5hdGVzIChlYWNoIGtleVxuICAvLyBleHBhbmRzIGF0IG1vc3Qgb25jZSBwZXIgbm9kZSkuIGZ1bGx5RXhwYW5kZWQ6IG5vZGVzIHRoYXQgZmVsbCBiYWNrIHRvXG4gIC8vIHN0YWdlIGxldmVsIChubyByZWFkS2V5cyBvbiBhIGxpbmtpbmcgZW50cnkpIOKAlCBub3RoaW5nIGxlZnQgdG8gYWRkLlxuICBjb25zdCBleHBhbmRlZFJlYWRzID0gbmV3IE1hcDxzdHJpbmcsIFNldDxzdHJpbmc+PigpO1xuICBjb25zdCBmdWxseUV4cGFuZGVkID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgLyoqXG4gICAqIFJlc29sdmUgYSBub2RlJ3MgZXhwYW5zaW9uIHJlYWQtc2V0IGZvciB0aGUgZ2l2ZW4gbGlua2luZyBXUklUVEVOIGtleXMuXG4gICAqIFBlci13cml0ZSBtb2RlIHdpdGggcHJvdmVuYW5jZSBwcmVzZW50IOKGkiB1bmlvbiBvZiB0aGUgbGlua2luZyB3cml0ZXMnXG4gICAqIHRlbXBvcmFsLXByZWZpeCBgcmVhZEtleXNgLiBBbnkgbGlua2luZyBlbnRyeSBXSVRIT1VUIGByZWFkS2V5c2AgKG9yIG5vXG4gICAqIGxpbmtLZXlzIGF0IGFsbCkg4oaSIGhvbmVzdCBzdGFnZS1sZXZlbCBmYWxsYmFjaywgZmxhZ2dlZCB2aWEgdGhlIHNlY29uZFxuICAgKiB0dXBsZSBtZW1iZXIgc28gdGhlIGNhbGxlciBtYXJrcyB0aGUgbm9kZSBmdWxseSBleHBhbmRlZC5cbiAgICovXG4gIGZ1bmN0aW9uIHJlYWRzRm9yTGlua3MoY29tbWl0OiBDb21taXRCdW5kbGUsIGxpbmtLZXlzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCk6IFtzdHJpbmdbXSwgYm9vbGVhbl0ge1xuICAgIGlmICghcGVyV3JpdGUgfHwgIWxpbmtLZXlzIHx8IGxpbmtLZXlzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIFtnZXRLZXlzUmVhZChjb21taXQucnVudGltZVN0YWdlSWQpLCB0cnVlXTtcbiAgICB9XG4gICAgY29uc3QgdW5pb24gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBmb3IgKGNvbnN0IGxpbmtLZXkgb2YgbGlua0tleXMpIHtcbiAgICAgIGNvbnN0IGVudHJpZXMgPSBsaW5raW5nRW50cmllcyhjb21taXQsIGxpbmtLZXkpO1xuICAgICAgaWYgKGVudHJpZXMubGVuZ3RoID09PSAwIHx8IGVudHJpZXMuc29tZSgoZSkgPT4gZS5yZWFkS2V5cyA9PT0gdW5kZWZpbmVkKSkge1xuICAgICAgICAvLyBNaXhlZC9kaWFsLW9mZiBsb2cg4oCUIGRlZ3JhZGUgVEhJUyBub2RlIHRvIHN0YWdlIGxldmVsLCBob25lc3RseS5cbiAgICAgICAgcmV0dXJuIFtnZXRLZXlzUmVhZChjb21taXQucnVudGltZVN0YWdlSWQpLCB0cnVlXTtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykgZm9yIChjb25zdCByayBvZiBlbnRyeS5yZWFkS2V5cyBhcyBzdHJpbmdbXSkgdW5pb24uYWRkKHJrKTtcbiAgICB9XG4gICAgcmV0dXJuIFtbLi4udW5pb25dLCBmYWxzZV07XG4gIH1cblxuICAvLyBCRlMvd29ya2xpc3QgcXVldWU6IFtub2RlLCBjb21taXRJZHgsIGRlcHRoLCBrZXlzVG9FeHBhbmRdXG4gIGNvbnN0IFtyb290UmVhZHMsIHJvb3RJc0Z1bGxdID0gcGVyV3JpdGVcbiAgICA/IHJlYWRzRm9yTGlua3Moc3RhcnRDb21taXQsIG9wdGlvbnM/LnJvb3RMaW5rS2V5cylcbiAgICA6IFtnZXRLZXlzUmVhZChzdGFydElkKSwgdHJ1ZV07XG4gIGV4cGFuZGVkUmVhZHMuc2V0KHN0YXJ0SWQsIG5ldyBTZXQocm9vdFJlYWRzKSk7XG4gIGlmIChyb290SXNGdWxsKSBmdWxseUV4cGFuZGVkLmFkZChzdGFydElkKTtcbiAgY29uc3QgcXVldWU6IEFycmF5PFtDYXVzYWxOb2RlLCBudW1iZXIsIG51bWJlciwgc3RyaW5nW11dPiA9IFtbcm9vdCwgc3RhcnRJZHgsIDAsIHJvb3RSZWFkc11dO1xuICBsZXQgdmlzaXRlZCA9IDE7XG5cbiAgLyoqXG4gICAqIExpbmsgYG5vZGUg4oaSIHBhcmVudGAgKGNyZWF0aW5nICsgZW5xdWV1ZWluZyB0aGUgcGFyZW50IHdoZW4gbmV3KS5cbiAgICogU2hhcmVkIGJ5IGRhdGEtZWRnZSBleHBhbnNpb24gKHJlYWTihpJ3cml0ZSkgYW5kIGNvbnRyb2wtZWRnZSBleHBhbnNpb25cbiAgICogKEQzKS4gT25lIENhdXNhbEVkZ2UgcGVyIGRpc3RpbmN0IChwYXJlbnQsIGtpbmQsIGtleSkgbGluazsgYHBhcmVudHNgXG4gICAqIGtlZXBzIGl0cyBoaXN0b3JpY2FsIG9uZS1lbnRyeS1wZXItcGFyZW50IGRlZHVwLlxuICAgKi9cbiAgZnVuY3Rpb24gbGlua1BhcmVudChcbiAgICBub2RlOiBDYXVzYWxOb2RlLFxuICAgIHBhcmVudENvbW1pdDogQ29tbWl0QnVuZGxlLFxuICAgIGtpbmQ6ICdkYXRhJyB8ICdjb250cm9sJyxcbiAgICBrZXk6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBkZXB0aDogbnVtYmVyLFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBwYXJlbnRJZCA9IHBhcmVudENvbW1pdC5ydW50aW1lU3RhZ2VJZDtcbiAgICAvLyB0aGUgZGVkdXAgc2NhbnMgYmVsb3csIGFuZCB0aGUgcGFyZW50J3MgdHJhY2Ugd2hlbiBpdCBpcyBuZXcg4oCUIGNvdW50ZWQgZm9yIHRoZSBzY2FsaW5nIHRlc3RcbiAgICBxdWVyeVdvcmsudW5pdHMgKz0gMSArIG5vZGUucGFyZW50cy5sZW5ndGggKyBub2RlLnBhcmVudEVkZ2VzLmxlbmd0aDtcbiAgICAvLyAjUDE6IHRoZSBwYXJlbnQncyBleHBhbnNpb24gcmVhZHMsIHJlc29sdmVkIExBWklMWSAob25seSBmb3IgbmV3IG5vZGVzXG4gICAgLy8gb3IgcGVyLXdyaXRlIHJlLWV4cGFuc2lvbiDigJQgZHVwbGljYXRlIGxpbmtzIHVuZGVyICdzdGFnZScgcGF5IG5vdGhpbmcpLlxuICAgIC8vIERhdGEgbGlua3MgZXhwYW5kIHRocm91Z2ggdGhlIHJlYWRzIHRoYXQgZmVkIHRoZSBwYXJlbnQncyB3cml0ZSBvZlxuICAgIC8vIGBrZXlgOyBjb250cm9sIGxpbmtzIGV4cGFuZCB0aGUgZGVjaWRlciBhdCBzdGFnZSBsZXZlbCAoYSBkZWNpc2lvblxuICAgIC8vIGRlcGVuZHMgb24gZXZlcnl0aGluZyBpdCByZWFkKS5cbiAgICBjb25zdCByZXNvbHZlTGlua1JlYWRzID0gKCk6IFtzdHJpbmdbXSwgYm9vbGVhbl0gPT5cbiAgICAgIGtpbmQgPT09ICdkYXRhJ1xuICAgICAgICA/IHJlYWRzRm9yTGlua3MocGFyZW50Q29tbWl0LCBrZXkgIT09IHVuZGVmaW5lZCA/IFtrZXldIDogdW5kZWZpbmVkKVxuICAgICAgICA6IFtnZXRLZXlzUmVhZChwYXJlbnRJZCksIHRydWVdO1xuXG4gICAgbGV0IHBhcmVudE5vZGUgPSBub2RlTWFwLmdldChwYXJlbnRJZCk7XG4gICAgaWYgKCFwYXJlbnROb2RlKSB7XG4gICAgICAvLyBOZXcgbm9kZSDigJQgY3JlYXRlIGFuZCBlbnF1ZXVlIChyZXNwZWN0aW5nIHRoZSBub2RlIGJ1ZGdldClcbiAgICAgIGlmICh2aXNpdGVkID49IG1heE5vZGVzKSB7XG4gICAgICAgIHRydW5jYXRlZEJ5Tm9kZXMgPSB0cnVlOyAvLyBENDogYSBkaXNjb3ZlcmVkIHBhcmVudCB3YXMgZHJvcHBlZFxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBhcmVudElkeCA9IGlkeE1hcC5nZXQocGFyZW50SWQpO1xuICAgICAgaWYgKHBhcmVudElkeCA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG5cbiAgICAgIHF1ZXJ5V29yay51bml0cyArPSBwYXJlbnRDb21taXQudHJhY2UubGVuZ3RoO1xuICAgICAgcGFyZW50Tm9kZSA9IHtcbiAgICAgICAgcnVudGltZVN0YWdlSWQ6IHBhcmVudElkLFxuICAgICAgICBzdGFnZUlkOiBwYXJlbnRDb21taXQuc3RhZ2VJZCxcbiAgICAgICAgc3RhZ2VOYW1lOiBwYXJlbnRDb21taXQuc3RhZ2UsXG4gICAgICAgIGtleXNXcml0dGVuOiBwYXJlbnRDb21taXQudHJhY2UubWFwKCh0KSA9PiB0LnBhdGgpLFxuICAgICAgICAvLyBsaW5rZWRCeSBzdGF5cyBhIERBVEEta2V5IGNvbmNlcHQgKGJhY2stY29tcGF0KSDigJQgY29udHJvbC1saW5rZWRcbiAgICAgICAgLy8gbm9kZXMgY2FycnkgdGhlaXIgbGFiZWwgb24gdGhlIGVkZ2UgaW5zdGVhZC5cbiAgICAgICAgbGlua2VkQnk6IGtpbmQgPT09ICdkYXRhJyA/IGtleSA/PyAnJyA6ICcnLFxuICAgICAgICBkZXB0aDogZGVwdGggKyAxLFxuICAgICAgICBwYXJlbnRzOiBbXSxcbiAgICAgICAgcGFyZW50RWRnZXM6IFtdLFxuICAgICAgICAuLi5pbmNvbXBsZXRlU291cmNlc0ZyYWdtZW50KHBhcmVudENvbW1pdCksXG4gICAgICB9O1xuICAgICAgbm9kZU1hcC5zZXQocGFyZW50SWQsIHBhcmVudE5vZGUpO1xuICAgICAgdmlzaXRlZCsrO1xuICAgICAgY29uc3QgW2xpbmtSZWFkcywgbGlua0lzRnVsbF0gPSByZXNvbHZlTGlua1JlYWRzKCk7XG4gICAgICBleHBhbmRlZFJlYWRzLnNldChwYXJlbnRJZCwgbmV3IFNldChsaW5rUmVhZHMpKTtcbiAgICAgIGlmIChsaW5rSXNGdWxsKSBmdWxseUV4cGFuZGVkLmFkZChwYXJlbnRJZCk7XG4gICAgICBxdWV1ZS5wdXNoKFtwYXJlbnROb2RlLCBwYXJlbnRJZHgsIGRlcHRoICsgMSwgbGlua1JlYWRzXSk7XG4gICAgfSBlbHNlIGlmIChwZXJXcml0ZSAmJiAhZnVsbHlFeHBhbmRlZC5oYXMocGFyZW50SWQpKSB7XG4gICAgICAvLyAjUDEgd29ya2xpc3Q6IGFuIEVYSVNUSU5HIG5vZGUgbGlua2VkIHZpYSBhbm90aGVyIGtleSBtYXkgb3dlIG1vcmVcbiAgICAgIC8vIGV4cGFuc2lvbiDigJQgZW5xdWV1ZSBvbmx5IHRoZSByZWFkcyBub3QgeWV0IGV4cGFuZGVkIChtb25vdG9uZTsgdGhlXG4gICAgICAvLyBub2RlIGJ1ZGdldCBpcyB1bnRvdWNoZWQsIG5vIG5vZGUgaXMgY3JlYXRlZCkuIFJlLWV4cGFuc2lvbiBrZWVwc1xuICAgICAgLy8gdGhlIG5vZGUncyBPUklHSU5BTCBkZXB0aCBzbyBpdHMgcGFyZW50cyBnZXQgYSBjb25zaXN0ZW50IGRlcHRoKzEuXG4gICAgICBjb25zdCBbbGlua1JlYWRzLCBsaW5rSXNGdWxsXSA9IHJlc29sdmVMaW5rUmVhZHMoKTtcbiAgICAgIGNvbnN0IGV4cGFuZGVkID0gZXhwYW5kZWRSZWFkcy5nZXQocGFyZW50SWQpITtcbiAgICAgIGNvbnN0IGRlbHRhID0gbGlua1JlYWRzLmZpbHRlcigoaykgPT4gIWV4cGFuZGVkLmhhcyhrKSk7XG4gICAgICBpZiAobGlua0lzRnVsbCkgZnVsbHlFeHBhbmRlZC5hZGQocGFyZW50SWQpO1xuICAgICAgaWYgKGRlbHRhLmxlbmd0aCA+IDApIHtcbiAgICAgICAgZm9yIChjb25zdCBrIG9mIGRlbHRhKSBleHBhbmRlZC5hZGQoayk7XG4gICAgICAgIGNvbnN0IHBhcmVudElkeCA9IGlkeE1hcC5nZXQocGFyZW50SWQpO1xuICAgICAgICBpZiAocGFyZW50SWR4ICE9PSB1bmRlZmluZWQpIHF1ZXVlLnB1c2goW3BhcmVudE5vZGUsIHBhcmVudElkeCwgcGFyZW50Tm9kZS5kZXB0aCwgZGVsdGFdKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBEQUcgbWVyZ2U6IG9uZSBwYXJlbnRzW10gZW50cnkgcGVyIGRpc3RpbmN0IHBhcmVudCAoaGlzdG9yaWNhbCBzaGFwZSlcbiAgICBpZiAoIW5vZGUucGFyZW50cy5zb21lKChwKSA9PiBwLnJ1bnRpbWVTdGFnZUlkID09PSBwYXJlbnRJZCkpIHtcbiAgICAgIG5vZGUucGFyZW50cy5wdXNoKHBhcmVudE5vZGUpO1xuICAgIH1cbiAgICAvLyBPbmUgZWRnZSBwZXIgZGlzdGluY3QgKHBhcmVudCwga2luZCwga2V5KSBsaW5rLiBUaGUgd2VpZ2hlciAoRDQpXG4gICAgLy8gc3RhbXBzIHRoZSB3ZWlnaHQgYXQgY3JlYXRpb247IGB1bmRlZmluZWRgIOKGkiAxLjAg4oCUIHRoZSBlbmdpbmUgbmV2ZXJcbiAgICAvLyBjb21wdXRlcyB3ZWlnaHRzIGl0c2VsZi5cbiAgICBpZiAoIW5vZGUucGFyZW50RWRnZXMuc29tZSgoZSkgPT4gZS5wYXJlbnQucnVudGltZVN0YWdlSWQgPT09IHBhcmVudElkICYmIGUua2luZCA9PT0ga2luZCAmJiBlLmtleSA9PT0ga2V5KSkge1xuICAgICAgLy8gRXJyb3IgaXNvbGF0aW9uIChyZXZpZXcgZmluZGluZyk6IGEgY29uc3VtZXIgd2VpZ2hlciB0aGF0IHRocm93c1xuICAgICAgLy8gbXVzdCBkZWdyYWRlIHRvIHRoZSBkZWZhdWx0IHdlaWdodCwgbmV2ZXIgY3Jhc2ggdGhlIHNsaWNlIOKAlCB0aGVcbiAgICAgIC8vIHNhbWUgY29udHJhY3QgZXZlcnkgb3RoZXIgY29uc3VtZXIgY2FsbGJhY2sgaW4gdGhlIGxpYnJhcnkgZ2V0cy5cbiAgICAgIGxldCB3ZWlnaHQgPSAxLjA7XG4gICAgICBpZiAod2VpZ2gpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB3ZWlnaHQgPSB3ZWlnaChub2RlLCBwYXJlbnROb2RlLCBrZXksIGtpbmQpID8/IDEuMDtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgLyogd2VpZ2hlciB0aHJldyDigJQga2VlcCAxLjAsIHRoZSBzbGljZSBzdGF5cyB1c2FibGUgKi9cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3QgbmVzdGVkID0ga2luZCA9PT0gJ2RhdGEnICYmIGtleSAhPT0gdW5kZWZpbmVkICYmIHdyaXRlc09ubHlJbnNpZGUocGFyZW50Q29tbWl0LCBrZXkpO1xuICAgICAgbm9kZS5wYXJlbnRFZGdlcy5wdXNoKHtcbiAgICAgICAgcGFyZW50OiBwYXJlbnROb2RlLFxuICAgICAgICBraW5kLFxuICAgICAgICBrZXksXG4gICAgICAgIHdlaWdodCxcbiAgICAgICAgLi4uKG5lc3RlZCAmJiB7IGJhc2lzOiAnbmVzdGVkLXJvd3MnIGFzIGNvbnN0IH0pLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgd2hpbGUgKHF1ZXVlLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBbbm9kZSwgY29tbWl0SWR4LCBkZXB0aCwga2V5c1RvRXhwYW5kXSA9IHF1ZXVlLnNoaWZ0KCkhO1xuICAgIHF1ZXJ5V29yay51bml0cyArPSAxICsga2V5c1RvRXhwYW5kLmxlbmd0aDtcblxuICAgIGlmIChkZXB0aCA+PSBtYXhEZXB0aCkge1xuICAgICAgLy8gRDQ6IG9ubHkgYSBub2RlIHRoYXQgc3RpbGwgSEFEIHNvbWV0aGluZyB0byBleHBhbmQgY291bnRzIGFzIGEgY3V0XG4gICAgICAvLyAoYSBsZWFmIGF0IHRoZSBob3Jpem9uIHRydW5jYXRlcyBub3RoaW5nKS5cbiAgICAgIGlmIChrZXlzVG9FeHBhbmQubGVuZ3RoID4gMCB8fCBjb250cm9sRGVwcz8uKG5vZGUucnVudGltZVN0YWdlSWQpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdHJ1bmNhdGVkQnlEZXB0aCA9IHRydWU7XG4gICAgICB9XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICAvLyBEYXRhIGVkZ2VzOiBmb3IgZWFjaCBrZXkgaW4gdGhpcyBleHBhbnNpb24ncyByZWFkLXNldCwgZmluZCB3aG8gd3JvdGVcbiAgICAvLyBpdC4gVW5kZXIgJ3N0YWdlJyB0aGlzIGlzIHRoZSBub2RlJ3MgZnVsbCByZWFkLXNldCAoaGlzdG9yaWNhbFxuICAgIC8vIGJlaGF2aW9yKTsgdW5kZXIgJ3Blci13cml0ZScgaXQgaXMgdGhlIGxpbmtpbmcgd3JpdGVzJyB0ZW1wb3JhbCBwcmVmaXhcbiAgICAvLyAob3IgYSB3b3JrbGlzdCBkZWx0YSBvbiByZS1leHBhbnNpb24pLlxuICAgIGNvbnN0IGtleXNSZWFkID0ga2V5c1RvRXhwYW5kO1xuICAgIGZvciAoY29uc3Qga2V5IG9mIGtleXNSZWFkKSB7XG4gICAgICBjb25zdCB3cml0ZXIgPSBmaW5kV3JpdGVyKGtleSwgY29tbWl0SWR4KTtcbiAgICAgIGlmICghd3JpdGVyKSB7XG4gICAgICAgIC8vIEY0Yjogc2F5IHdoeSB0aGVyZSBpcyBubyBlZGdlIOKAlCBubyBjb21taXQgYmVmb3JlIHRoaXMgbm9kZSB3cm90ZSB0aGUga2V5LlxuICAgICAgICBub2RlLnByZVJ1blJlYWRzID8/PSB7IGNvZGU6ICdwcmUtcnVuLW9yaWdpbicsIGtleXM6IFtdIH07XG4gICAgICAgIGlmICghbm9kZS5wcmVSdW5SZWFkcy5rZXlzLmluY2x1ZGVzKGtleSkpIG5vZGUucHJlUnVuUmVhZHMua2V5cy5wdXNoKGtleSk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgbGlua1BhcmVudChub2RlLCB3cml0ZXIsICdkYXRhJywga2V5LCBkZXB0aCk7XG4gICAgfVxuXG4gICAgLy8gQ29udHJvbCBlZGdlIChSRkMtMDAzIEQzKTogbGluayB0aGUgZ292ZXJuaW5nIGRlY2lkZXIsIGxhYmVsZWQgYnkgdGhlXG4gICAgLy8gZGVjaWRlKCkgcnVsZSBsYWJlbCB3aGVuIHByZXNlbnQuIFRoZSBkZWNpZGVyIG5vZGUgdGhlbiBleHBhbmRzXG4gICAgLy8gbm9ybWFsbHkgdGhyb3VnaCBpdHMgb3duIGRhdGEgcmVhZHMgKGFuZCBpdHMgb3duIGNvbnRyb2wgcGFyZW50KS5cbiAgICBpZiAoY29udHJvbERlcHMpIHtcbiAgICAgIGNvbnN0IGRlcCA9IGNvbnRyb2xEZXBzKG5vZGUucnVudGltZVN0YWdlSWQpO1xuICAgICAgaWYgKGRlcCkge1xuICAgICAgICBjb25zdCBkZWNpZGVySWR4ID0gaWR4TWFwLmdldChkZXAuZGVjaWRlcklkKTtcbiAgICAgICAgaWYgKGRlY2lkZXJJZHggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGxpbmtQYXJlbnQobm9kZSwgY29tbWl0TG9nW2RlY2lkZXJJZHhdLCAnY29udHJvbCcsIGRlcC5sYWJlbCwgZGVwdGgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUkZDLTAwMyBENCDigJQgdHJ1bmNhdGlvbiB2aXNpYmlsaXR5IG9uIHRoZSByb290IChhYnNlbnQgd2hlbiBjb21wbGV0ZSkuIEl0IGlzIERBVEEsIGFuZCBvbmx5XG4gIC8vIGRhdGE6IGEgcmVhZGVyIHJlYWRzIGByb290LnRydW5jYXRlZGAgKGFuZCBgZm9ybWF0Q2F1c2FsQ2hhaW5gIHByaW50cyBpdCk7IHRoZSByZWNvcmQgd3JpdGVzIG5vXG4gIC8vIGNvbnNvbGUgbGluZSAodGhlIGRldi1tb2RlIHdhcm5pbmcgd2VudCBpbiBDNiDigJQgdGhlIHJlY29yZCBpbXBvcnRzIG5vdGhpbmcgb3V0c2lkZSBpdHNlbGYpLlxuICBpZiAodHJ1bmNhdGVkQnlEZXB0aCB8fCB0cnVuY2F0ZWRCeU5vZGVzKSB7XG4gICAgcm9vdC50cnVuY2F0ZWQgPSB7IGJ5RGVwdGg6IHRydW5jYXRlZEJ5RGVwdGgsIGJ5Tm9kZXM6IHRydW5jYXRlZEJ5Tm9kZXMgfTtcbiAgfVxuXG4gIHJldHVybiByb290O1xufVxuXG4vLyDilIDilIAgVXRpbGl0aWVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKipcbiAqIEZsYXR0ZW4gdGhlIGNhdXNhbCBEQUcgaW50byBhIEJGUy1vcmRlcmVkIGxpc3Qgb2Ygbm9kZXMuXG4gKiBFYWNoIG5vZGUgYXBwZWFycyBleGFjdGx5IG9uY2UgKGZpcnN0IG9jY3VycmVuY2UgYnkgQkZTIG9yZGVyKS5cbiAqIFVzZWZ1bCBmb3IgbGluZWFyIGRpc3BsYXkgb3IgaXRlcmF0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZmxhdHRlbkNhdXNhbERBRyhyb290OiBDYXVzYWxOb2RlKTogQ2F1c2FsTm9kZVtdIHtcbiAgY29uc3QgcmVzdWx0OiBDYXVzYWxOb2RlW10gPSBbXTtcbiAgY29uc3QgdmlzaXRlZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBxdWV1ZTogQ2F1c2FsTm9kZVtdID0gW3Jvb3RdO1xuXG4gIHdoaWxlIChxdWV1ZS5sZW5ndGggPiAwKSB7XG4gICAgY29uc3Qgbm9kZSA9IHF1ZXVlLnNoaWZ0KCkhO1xuICAgIGlmICh2aXNpdGVkLmhhcyhub2RlLnJ1bnRpbWVTdGFnZUlkKSkgY29udGludWU7XG4gICAgdmlzaXRlZC5hZGQobm9kZS5ydW50aW1lU3RhZ2VJZCk7XG4gICAgcmVzdWx0LnB1c2gobm9kZSk7XG5cbiAgICBmb3IgKGNvbnN0IHBhcmVudCBvZiBub2RlLnBhcmVudHMpIHtcbiAgICAgIGlmICghdmlzaXRlZC5oYXMocGFyZW50LnJ1bnRpbWVTdGFnZUlkKSkge1xuICAgICAgICBxdWV1ZS5wdXNoKHBhcmVudCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBGb3JtYXQgYSBjYXVzYWwgREFHIGFzIGh1bWFuLXJlYWRhYmxlIGluZGVudGVkIHRleHQuXG4gKiBTaG93cyB0aGUgZGVwZW5kZW5jeSBjaGFpbiB3aXRoIGRlcHRoIGluZGVudGF0aW9uIGFuZCBsaW5rZWQtYnkga2V5cy5cbiAqXG4gKiBSRkMtMDAzIEQyOiBub2RlcyB0aGF0IGNvbnN1bWVkIHVudHJhY2tlZCByZWFkIHBhdGhzIHJlbmRlciBhbiBleHRyYVxuICogYOKaoCBhbHNvIGNvbnN1bWVkIOKApiDigJQgc2xpY2UgbWF5IGJlIGluY29tcGxldGUgaGVyZWAgbGluZSwgc28gYSBjb25zdW1lclxuICogKGh1bWFuIG9yIExMTSkgZGVidWdnaW5nIGZyb20gdGhlIHNsaWNlIGlzIFRPTEQgd2hlbiBpdCBpcyBpbmNvbXBsZXRlLlxuICpcbiAqIFJGQy0wMDMgRDM6IGNvbnRyb2wgZWRnZXMgcmVuZGVyIGFzIGDihpAgW2NvbnRyb2w6IDxydWxlIGxhYmVsPl1gXG4gKiAobGFiZWwgb21pdHRlZCB3aGVuIHRoZSBkZWNpc2lvbiBjYXJyaWVkIG5vbmUpLiBEYXRhIHJlbmRlcmluZyBpc1xuICogYnl0ZS1pZGVudGljYWwgdG8gdGhlIHByZS1EMyBvdXRwdXQg4oCUIGDihpAgdmlhIDxrZXk+YCBmcm9tIHRoZSBub2RlJ3NcbiAqIGRpc2NvdmVyeS10aW1lIGBsaW5rZWRCeWAuXG4gKlxuICogUkZDLTAwMyBENDogZWRnZSB3ZWlnaHRzIGZyb20gdGhlIGB3ZWlnaGAgaG9vayByZW5kZXIgYXMgYSBzdWZmaXgg4oCUXG4gKiBg4oaQIHZpYSBzeXN0ZW1Qcm9tcHQgKDAuMTgpYCDigJQgb25seSB3aGVuIOKJoCAxLjAsIHNvIHVud2VpZ2h0ZWQgb3V0cHV0IGlzXG4gKiB1bmNoYW5nZWQuIEEgdHJ1bmNhdGVkIHNsaWNlIChyb290LnRydW5jYXRlZCkgYXBwZW5kcyBhIGZpbmFsXG4gKiBg4pqgIHNsaWNlIHRydW5jYXRlZCDigKZgIGxpbmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRDYXVzYWxDaGFpbihyb290OiBDYXVzYWxOb2RlKTogc3RyaW5nIHtcbiAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IHZpc2l0ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuICBjb25zdCB3ZWlnaHRTdWZmaXggPSAoZWRnZTogQ2F1c2FsRWRnZSB8IHVuZGVmaW5lZCk6IHN0cmluZyA9PlxuICAgIGVkZ2UgIT09IHVuZGVmaW5lZCAmJiBlZGdlLndlaWdodCAhPT0gMSA/IGAgKCR7ZWRnZS53ZWlnaHR9KWAgOiAnJztcblxuICBmdW5jdGlvbiB3YWxrKG5vZGU6IENhdXNhbE5vZGUsIGluZGVudDogbnVtYmVyLCBlZGdlc0Zyb21DaGlsZD86IENhdXNhbEVkZ2VbXSk6IHZvaWQge1xuICAgIGlmICh2aXNpdGVkLmhhcyhub2RlLnJ1bnRpbWVTdGFnZUlkKSkge1xuICAgICAgbGluZXMucHVzaChgJHsnICAnLnJlcGVhdChpbmRlbnQpfeKGsyAke25vZGUucnVudGltZVN0YWdlSWR9IChzZWUgYWJvdmUpYCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHZpc2l0ZWQuYWRkKG5vZGUucnVudGltZVN0YWdlSWQpO1xuXG4gICAgY29uc3QgbGlua1BhcnRzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGlmIChub2RlLmxpbmtlZEJ5KSB7XG4gICAgICBjb25zdCBkYXRhRWRnZSA9IGVkZ2VzRnJvbUNoaWxkPy5maW5kKChlKSA9PiBlLmtpbmQgPT09ICdkYXRhJyk7XG4gICAgICBsaW5rUGFydHMucHVzaChgdmlhICR7bm9kZS5saW5rZWRCeX0ke3dlaWdodFN1ZmZpeChkYXRhRWRnZSl9YCk7XG4gICAgfVxuICAgIGNvbnN0IGNvbnRyb2xFZGdlID0gZWRnZXNGcm9tQ2hpbGQ/LmZpbmQoKGUpID0+IGUua2luZCA9PT0gJ2NvbnRyb2wnKTtcbiAgICBpZiAoY29udHJvbEVkZ2UpIHtcbiAgICAgIGxpbmtQYXJ0cy5wdXNoKGBbY29udHJvbCR7Y29udHJvbEVkZ2Uua2V5ID8gYDogJHtjb250cm9sRWRnZS5rZXl9YCA6ICcnfV0ke3dlaWdodFN1ZmZpeChjb250cm9sRWRnZSl9YCk7XG4gICAgfVxuICAgIGNvbnN0IGxpbmsgPSBsaW5rUGFydHMubGVuZ3RoID4gMCA/IGAg4oaQICR7bGlua1BhcnRzLmpvaW4oJyDihpAgJyl9YCA6ICcnO1xuXG4gICAgY29uc3Qgd3JpdGVzID0gbm9kZS5rZXlzV3JpdHRlbi5sZW5ndGggPiAwID8gYCBbd3JvdGU6ICR7bm9kZS5rZXlzV3JpdHRlbi5qb2luKCcsICcpfV1gIDogJyc7XG4gICAgbGluZXMucHVzaChgJHsnICAnLnJlcGVhdChpbmRlbnQpfSR7bm9kZS5zdGFnZU5hbWV9ICgke25vZGUucnVudGltZVN0YWdlSWR9KSR7bGlua30ke3dyaXRlc31gKTtcblxuICAgIGlmIChub2RlLmluY29tcGxldGVTb3VyY2VzICYmIG5vZGUuaW5jb21wbGV0ZVNvdXJjZXMubGVuZ3RoID4gMCkge1xuICAgICAgbGluZXMucHVzaChcbiAgICAgICAgYCR7JyAgJy5yZXBlYXQoaW5kZW50ICsgMSl94pqgIGFsc28gY29uc3VtZWQgJHtub2RlLmluY29tcGxldGVTb3VyY2VzLmpvaW4oJy8nKX0g4oCUIHNsaWNlIG1heSBiZSBpbmNvbXBsZXRlIGhlcmVgLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IHBhcmVudCBvZiBub2RlLnBhcmVudHMpIHtcbiAgICAgIHdhbGsoXG4gICAgICAgIHBhcmVudCxcbiAgICAgICAgaW5kZW50ICsgMSxcbiAgICAgICAgbm9kZS5wYXJlbnRFZGdlcy5maWx0ZXIoKGUpID0+IGUucGFyZW50ID09PSBwYXJlbnQpLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICB3YWxrKHJvb3QsIDApO1xuXG4gIGlmIChyb290LnRydW5jYXRlZCkge1xuICAgIGNvbnN0IGNhdXNlcyA9IFtyb290LnRydW5jYXRlZC5ieURlcHRoICYmICdtYXhEZXB0aCByZWFjaGVkJywgcm9vdC50cnVuY2F0ZWQuYnlOb2RlcyAmJiAnbWF4Tm9kZXMgcmVhY2hlZCddXG4gICAgICAuZmlsdGVyKEJvb2xlYW4pXG4gICAgICAuam9pbignLCAnKTtcbiAgICBsaW5lcy5wdXNoKGDimqAgc2xpY2UgdHJ1bmNhdGVkICgke2NhdXNlc30pIOKAlCBvbGRlciBjYXVzZXMgZXhpc3QgYmV5b25kIHRoaXMgaG9yaXpvbmApO1xuICB9XG5cbiAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xufVxuXG4vLyDilIDilIAgRXhwb3J0ZWQgZm9yIHRlc3RpbmcgKGludGVybmFsKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqIEBpbnRlcm5hbCBFeHBvc2VkIGZvciB0ZXN0aW5nIHRoZSBzdHJhdGVneSBzZWxlY3Rpb24uICovXG5leHBvcnQgY29uc3QgX1JFVkVSU0VfSU5ERVhfVEhSRVNIT0xEID0gUkVWRVJTRV9JTkRFWF9USFJFU0hPTEQ7XG4iXX0=
|