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