footprintjs 9.44.0 → 9.44.2
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/CLAUDE.md +6 -5
- package/dist/esm/lib/capture/freeze.d.ts +51 -7
- package/dist/esm/lib/capture/freeze.js +289 -24
- package/dist/esm/lib/capture/valueKinds.d.ts +57 -0
- package/dist/esm/lib/capture/valueKinds.js +142 -0
- package/dist/esm/lib/memory/EventLog.d.ts +24 -6
- package/dist/esm/lib/memory/EventLog.js +30 -10
- package/dist/esm/lib/memory/admission.js +4 -3
- package/dist/esm/lib/memory/borrowedMutation.js +2 -2
- package/dist/esm/lib/memory/equality.d.ts +55 -19
- package/dist/esm/lib/memory/equality.js +154 -51
- package/dist/esm/lib/memory/logModel.js +11 -4
- package/dist/esm/lib/memory/redaction.d.ts +21 -0
- package/dist/esm/lib/memory/redaction.js +64 -7
- package/dist/esm/lib/runner/ExecutionRuntime.d.ts +4 -1
- package/dist/esm/lib/runner/ExecutionRuntime.js +15 -10
- package/dist/esm/lib/runner/snapshot.js +17 -3
- package/dist/esm/lib/slice/elementProvenance.js +2 -2
- package/dist/esm/lib/time-travel/chain.js +28 -26
- package/dist/lib/capture/freeze.js +292 -25
- package/dist/lib/capture/valueKinds.js +146 -0
- package/dist/lib/memory/EventLog.js +29 -9
- package/dist/lib/memory/admission.js +4 -3
- package/dist/lib/memory/borrowedMutation.js +2 -2
- package/dist/lib/memory/equality.js +154 -51
- package/dist/lib/memory/logModel.js +11 -4
- package/dist/lib/memory/redaction.js +66 -8
- package/dist/lib/runner/ExecutionRuntime.js +14 -9
- package/dist/lib/runner/snapshot.js +16 -2
- package/dist/lib/slice/elementProvenance.js +2 -2
- package/dist/lib/time-travel/chain.js +27 -25
- package/dist/types/lib/capture/freeze.d.ts +51 -7
- package/dist/types/lib/capture/valueKinds.d.ts +57 -0
- package/dist/types/lib/memory/EventLog.d.ts +24 -6
- package/dist/types/lib/memory/equality.d.ts +55 -19
- package/dist/types/lib/memory/redaction.d.ts +21 -0
- package/dist/types/lib/runner/ExecutionRuntime.d.ts +4 -1
- package/package.json +2 -1
package/CLAUDE.md
CHANGED
|
@@ -8,7 +8,7 @@ Entry points: `footprintjs` (public API) · `/recorders` (factories) · `/trace`
|
|
|
8
8
|
|
|
9
9
|
| src/lib/ | one job |
|
|
10
10
|
|---|---|
|
|
11
|
-
| capture/ | retention policies + bounded payload summarization (leaf; shared by tracking dials AND deferred-observer capture) + the shared leaves `invokeHook` (the one recorder-hook invoker both delivery tiers use), `circular` (dev-mode cycle probe), `summarizeValue` (the narrative one-liner); `lib/devMode.ts` — the dev-mode flag — is its sibling leaf (all four moved out of scope/ and recorder/ in F0: they closed the one memory ⇄ scope ⇄ recorder module cycle) |
|
|
11
|
+
| capture/ | retention policies + bounded payload summarization (leaf; shared by tracking dials AND deferred-observer capture) + `valueKinds` (the ONE classifier of value kinds: `deepEqual`'s arms and what freezing seals, 9.44.2) + the shared leaves `invokeHook` (the one recorder-hook invoker both delivery tiers use), `circular` (dev-mode cycle probe), `summarizeValue` (the narrative one-liner); `lib/devMode.ts` — the dev-mode flag — is its sibling leaf (all four moved out of scope/ and recorder/ in F0: they closed the one memory ⇄ scope ⇄ recorder module cycle) |
|
|
12
12
|
| memory/ | transactional state: SharedMemory heap, StageContext frames, TransactionBuffer staging (+ admission.ts, the admitted record's check; deltaEncoding.ts, the delta encoder's helpers), EventLog commit log — PLUS the ONE verb law (`verbs.ts`, L1: `applyVerb`, `foldRows`, `foldKey`; leaves `paths.ts` / `equality.ts` / `merge.ts`; `utils.ts` re-exports them) and trace analysis (backtrack.ts causalChain, commitLogUtils.ts) |
|
|
13
13
|
| schema/ | duck-typed validation (`.safeParse/.parse` ⇒ 'parseable') |
|
|
14
14
|
| builder/ | fluent DSL → FlowChartSpec → StageNode graph; build-time StructureRecorder channel. NOT standalone: imports runner's makeRunnable (FlowChartBuilder.ts:18) |
|
|
@@ -55,9 +55,9 @@ Entry points: `footprintjs` (public API) · `/recorders` (factories) · `/trace`
|
|
|
55
55
|
## Change-impact map
|
|
56
56
|
- **Trace verbs** (`set|merge|append|delete`, memory/types.ts:42) → ONE law, `memory/verbs.ts` (L1) — F2 deleted the three replicas. `applyVerb` is the ONLY function with an arm per verb (a fifth verb in the union stops compiling there; `TRAITS` — `isTotal` / `recordsTail` — says what a verb IS, pinned against the step), `placeVerb` puts its value or removes the key (`ABSENT`), and two loops fold it: `foldRows` folds ONE bundle's rows into a state with the clone DISCIPLINE as a parameter (`'private'` = the PUBLIC `applySmartMerge`, which keeps its 9.28.0 contract: base deep-cloned, fully detached result — 9.29.0; `'pathCopy'` = the engine's `nextGeneration` — live commit + redacted mirror — and the folds' `applySmartMergeInto` — `stateAt`, `EventLog.materialise`; `'byReference'` = `dryFold`, the admitted record's comparison fold — 9.30.0), and `foldKey` folds ONE path's rows across a log — `commitLogUtils · commitValueAt` (anchored at the last total row) and `slice/elementProvenance · arrayProvenance` (an OBSERVER of that fold: it keeps the births and has no verb switch); causalChain/findLastWriter only match paths. A bundle's merge delta is detached ONCE per bundle (`RecordedPayload`): `deepSmartMerge` dedups an array union BY REFERENCE, so the merge rows of one bundle must see the same objects (a per-row clone made `commitValueAt` double the elements — the 9.29.0 reader bug, fixed here); `foldKey` narrows that copy to its one path. **An unknown verb is REFUSED** (`UnknownVerbError`, public on `/trace`; R2) by `foldRows` (so `applySmartMerge`), `commitValueAt`, `arrayProvenance` — they used to fold it as a `merge`; `time-travel/bundles · bundleRefusal` asks the same `isVerb` and makes it a GAP instead. Pinned: the three old replicas live on as the CONTROL in test/lib/memory/property/verb-law-differential.property.test.ts (kept for the packet's lifetime). The delta encoder keeps VOCABULARY only since 9.30.0 (it picks a verb; its values come from `dryFold` of the stage's 'full' rows — `TransactionBuffer · fullRowsValue`; `replayPathVerbs`/`replayFamilyVerbs` deleted). NOT a second loop (9.22.1): `verbs.ts · supersededByNextSet` — the ONE repeated-path skip (CONSECUTIVE same-path `set` rows: only the last is applied), asked by `foldRows` before its step; its commit-side twin is the last-materialised-path memo in `toChangeOnlyPayload`. Rows are never dropped from the log; a non-consecutive skip is WRONG (a descendant op in between coerces/shells the container) — pinned by test/lib/memory/scenario/repeated-path-byte-identity.test.ts. Since 9.23.0 the clone in that memo loop (and every `structuredClone` in `toDeltaPayload`) is THE clone — the patch trees hold references until commit; no verb switch was touched.
|
|
57
57
|
- **StageContext.commit / dials** → ONE owner since 9.35.0 (F5): `memory/runPolicy.ts` — a frozen `RunPolicy` (the four dials + the `RedactionRule` + the mirror flag) built ONCE by `FlowChartExecutor · createTraverser` (run AND resume), handed to `ExecutionRuntime`, held BY REFERENCE by every `StageContext` (`inheritRun` in createNext/createChild) and passed by `SubflowExecutor · executeSubflow` to the nested runtime BEFORE the seed. A fifth dial = the policy type + its consumer. The old per-dial `use*`/`get*` and `enableRedactedMirror` were removed in 9.36.0 (no compat shims — owner ruling). `commit()`'s FIRST act (9.23.0) is `materialiseWrites` — the `writeTracking` retained form is taken there, once per key, from `_pendingWrites` (bare references + the write-time verdict); anything that reads `_stageWrites` goes through `retainedWrites()` (a non-consuming fold, so a mid-run snapshot is honest), and `discardStaged` drops the pending map with the rest.
|
|
58
|
-
- **runtimeStageId format** (`#`/`/` delimiters) → ONE grammar owner since 9.37.0 (F7): `src/lib/ids/` (L0 leaf: `runtimeStageId.ts` — `parseRuntimeStageId`, `isExecutionKey`, `stageIdOf`, `subflowPathOf`, `refuseReservedId`; `branchSegment.ts` — the `~` grammar). Every parser (ScopeFacade subflow path, subflowResults dual-keying,
|
|
58
|
+
- **runtimeStageId format** (`#`/`/` delimiters) → ONE grammar owner since 9.37.0 (F7): `src/lib/ids/` (L0 leaf: `runtimeStageId.ts` — `parseRuntimeStageId`, `isExecutionKey`, `stageIdOf`, `subflowPathOf`, `refuseReservedId`; `branchSegment.ts` — the `~` grammar). Every parser (ScopeFacade subflow path, subflowResults dual-keying, narrative buffering, store keys) calls it; none re-derives the grammar. R5: every id door (22 at build, plus the run-time dynamic-StageNode door) refuses `#` and `/`; stage ids may contain `~`. `TraversalContext` has ONE constructor (`engine/traversalContext.ts`); `depth` = subflow nesting read off the runtimeStageId on every stamp. Brands `RuntimeStageId`/`ExecutionIndex`/`CommitIdx` on `/trace` (types only).
|
|
59
59
|
- **Subflow id prefixing** → ONE prefixer since 9.37.0: `engine/graph/prefixNodeTree.ts`, used by the builder AND the traverser (eager, lazy and `parallelForEach` mounts — lazy/branch roots were unprefixed before 9.37.0, so branch ids collided); change it + stageMap key composition + resume drilling; the builder's eager mounts all go through `FlowChartBuilder · _mountSubflow` (F10). test/lib/engine/branch-segment-prefixer-equivalence.test.ts stays as a guard.
|
|
60
|
-
- **Checkpoint shape** → `runner/checkpoint.ts · buildPauseCheckpoint` (
|
|
60
|
+
- **Checkpoint shape** (format 2 since 9.44.0, LEAN: only what resume reads + the pause's record — no `executionTree`/`subflowResults`; size independent of run length, pinned by test/lib/pause/checkpoint-size.test.ts; 9.39–9.43 refuse format 2, so upgrade readers before writers) → `runner/checkpoint.ts · buildPauseCheckpoint` ↔ `pause/record.ts · decodeCheckpoint` (one upcaster drops v0/v1 fields) ↔ `runner/resume.ts · planResume` (validation via `pause/record.ts · decodeCheckpoint`) ↔ `ResumeEntry.plan` (the path's mounts + captures + dispatcher continuations, the `pendingPauses` queue; refused up front when unwalkable, ambiguous, or a pending record is not a sibling) ↔ `SubflowExecutor · executeSubflow` resume hop (seed from the capture in place of the mapper's values — the mapper still runs, for the args — FIRST entry only) ↔ `ChildrenExecutor · raisePauses` (fills `pendingPauses`). 9.28.0 adds ONE optional field, `pendingPauses` (present only when parallel siblings wait); the redaction law adds `redactionMarks` (names only, present only when the run marked something); every stored checkpoint enters through `pause/record.ts · decodeCheckpoint` (`checkpointVersion: 1`, one upcaster from unversioned v0 which drops the legacy `continuationStageId`, one validator, one message set; 9.39.0). Pinned: a 9.27.0 checkpoint resumes, test/lib/pause/resume-real-chart-9.27.0-checkpoints.test.ts.
|
|
61
61
|
- **Committed-state writers** (copy-on-write, 9.29.0) → anything that writes into `SharedMemory`'s state, a fold's working copy or the buffer's working copy must copy before it writes: `pathOps · ownSpine` for the containers on the path, `ownedRootOf` for the root, `own`/`adopt` for what it created. An in-place edit of a container it did not create edits every generation sharing it — the counted guard stays green while the generations property fails. A new READ path through `TransactionBuffer` goes through `get` (private after the first write) unless it only compares (`peek`); a read the working copy cannot answer is served from LIVE state (`StageContext · readState`, as on 9.28.0) after `TransactionBuffer · detachBase` gives the diff base a private copy at that path — a private copy of the value handed out instead would change live state wherever 9.28.0 let an in-place edit in (a fork child's read of a parent key). `TransactionBuffer · merge` privatises its base first: `deepSmartMerge` dedups arrays BY REFERENCE, so the identity of the base is part of the bytes.
|
|
62
62
|
- **Redaction** (9.19.0; the law restored to owner ruling (a)) has ONE owner: `memory/redaction.ts` `RedactionRule` (verdict per user-level path: `clear | whole | fields`), carried on the run's `RunPolicy` with the four dials (F5). THE LAW: a policy covers EVERYTHING the library retains or serves — log (both encodings), mirror, stageReads/stageWrites, every recorder event inline and deferred (and the rows built from them), narrative, snapshots, diagnostics, pause payloads, boundary records, logger lines — and NEVER the live heap or the resume checkpoint. The two true exceptions are the caller's own values: the `run()` rejection and the live fork result. It selects by NAME, never by content: state by path (`verdict`); a record handed out whole (root input/output — `FlowchartTraverser.execute`; subflow seed/exit — `SubflowExecutor`; pause payload — `engine/handlers/servedPause.ts`; thrown value — `retainStageError`) by its keys at every depth plus declared `fields` under a key of that name (`retainBoundary` — one decision per PATH via `servedByPath`: copy-on-write per path, the visited set only the current path's ancestor stack, a cycle edge landing on the served copy; a path rule is exact under shared references, a key-NAME rule masks a shared node everywhere); a diagnostic entry as the record `{ [name]: value }` (`retainDiagnostic`; `policy.diagnostics` ADDS diagnostic-only selectors, the only ones that reach flow-message text); a subflow mapper's copy by TAINT (`MapperTaint`, asked by `SubflowInputMapper` for both mappers; the `parallelForEach` items selector counts selected reads via `StageContext · selectedReads` and marks `item`/`into`): a value passed under its own name keeps that name's verdict, an object by reference (or the whole handed record, as fields) keeps its source's, anything computed after a selected read is marked whole (conservative); never value equality across names. A mark is a NAME, run-wide, until the key is deleted — and a pause carries the marks (names only) to the resumed run (`FlowchartCheckpoint.redactionMarks`, checked by `pause/record.ts`). A thrown value is walked with its `cause`/`errors`; an object a mapper passes on by reference is scanned for the selected values it read (planted → fields). Name-only patterns (`needsPath` false — no `.`, lookaround, or escape/class that can match `.`) are decided per object, so the walk shares decisions per (object, targets) — linear on a DAG or a linked history; only a path-dependent pattern walks paths, and past 1,000,000 visits it serves the unvisited remainder as the placeholder (one dev-mode warning), never fails the run. Inside a stage, an OBJECT read under a selected name and written under another keeps its rule (`StageContext · stageWrite`, by identity); a primitive or a new object copied across names is selected by its own name only. `StageContext.stageWrite` is the ONE write funnel (facade writes, subflow seed, outputMapper merge-back, resume re-seed) and `getValue` retention asks the same rule; the facade asks it for read/write recorder payloads. An inert rule never enumerates a payload. `emitPatterns` is the one separate scrub (`$emit` payloads, by event name). Two placeholders, historical: log/mirror `'REDACTED'`, scope-tier `'[REDACTED]'`. See `docs/guides/scope.md` → "The one law". Capture the retained form at runtime; no second tree walk or recorder-local policy.
|
|
63
63
|
- **Diagnostic retention** → `DiagnosticCollector` asks the current run rule before merging/storing: a named entry maps to the state key of its name (the run's keys/patterns/marks/fields, at every depth of the value), then the opt-in `RedactionPolicy.diagnostics` selectors (same path algorithm, rooted at the channel). Its internal retained-write bridge supplies legacy facade emits. Existing writers stay void. Only flow-message description/rationale are payloads (no name — diagnostic selectors only); keys/topology/timing stay present. Dynamic capture uses a per-visit engine flag, not a diagnostic bag. A redacted `logs.deciderRationale` also reaches decision explanations. Checkpoints keep retained diagnostic bags but preserve operational state; no retroactive scrub. See the scope guide's diagnostic contract.
|
|
@@ -69,7 +69,7 @@ run: executor.run (FlowChartExecutor.ts:1455): re-entrancy guard → fresh runId
|
|
|
69
69
|
per stage: executeNodeStep stamps runtimeStageId (:818) → StageRunner.run: scopeFactory → onStageStart → stage fn (writes stage into TransactionBuffer via StageContext.setObject; onWrite fires live) → onStageEnd → traverser calls context.commit() (:1094) → onCommit → onStageExecuted (narrative flushes buffered ops here).
|
|
70
70
|
decider: DeciderHandler.prepareDispatch (:89) — runs stage, **commits BEFORE branch resolution** (:124), matches branchId, fires onDecision(+evidence) → onStageExecuted('decider') → flat hop with InvokerStamp.
|
|
71
71
|
loop: Phase 6 sees isLoopRef → ContinuationResolver.resolveTarget (:107): id-map lookup, iteration guard (max 1000), onLoop → hop; zero stack, state carries forward (never rewound). A decider WITH its own next runs its branch as a BRANCH FRAME (9.40.0): a `loop`-flagged hop leaves the frame only when an ENCLOSING driver already ran the target — the decider follows it flat and skips its next, which runs once after the non-looping pass; any other jump stays in the frame. A selector's own loopTo resolves the same way and fires onLoop.
|
|
72
|
-
end: onRunEnd (throw → onRunFailed; pause → neither) → deferred terminalFlush → getSnapshot() = {sharedState (LIVE view; dev-mode frozen clone), initialState (the fold base), commitLog (detached+frozen), executionTree, subflowResults (dual-keyed; `globalContext` = the subflow's LIVE heap, or under `redact: true` its own nested mirror — 9.20.0, `servedSubflowResults`), recorders}.
|
|
72
|
+
end: onRunEnd (throw → onRunFailed; pause → neither) → deferred terminalFlush → getSnapshot() = {sharedState (LIVE view; dev-mode frozen clone), initialState (the fold base), commitLog (detached+frozen; a bundle or base holding what freezing cannot seal — a Date, Map, buffer … — is served as a copy of its open paths, `runner/snapshot.ts · servedSnapshot` → `capture/freeze.ts · serveRecord`, 9.44.2), executionTree, subflowResults (dual-keyed; `globalContext` = the subflow's LIVE heap, or under `redact: true` its own nested mirror — 9.20.0, `servedSubflowResults`), recorders}.
|
|
73
73
|
|
|
74
74
|
## Backtracking
|
|
75
75
|
Seven mechanisms, no state rollback anywhere: **M1** TransactionBuffer staging + net-change commit — commit-on-error by design, explicitly NOT rollback (TransactionBuffer.ts:13-18; error path commits then rethrows). **M2** Pause/Resume checkpointing — the only resume-from-prior-point; TWO raise shapes, ONE checkpoint: `addPausableFunction` (resume runs `resumeFn`) and `interrupt(scope, payload)` (resume RE-RUNS THE STAGE FUNCTION FROM ITS TOP — stages are atomic; the answer returns out of the `interrupt()` call via a WeakMap keyed by the scope), discriminated by `checkpoint.pausedBy`; checkpoint is one detached structuredClone; resume rebuilds the cursor from pausedStageId+subflowPath and re-enters ONCE (9.28.0, `ResumeEntry`): the paused stage's stand-in (its own node, fn swapped — so a dispatcher that interrupted still dispatches) is only where the resumed traversal STARTS — never in a node map — and each subflow on the path takes its capture + entry point on its FIRST entry (a 2+-deep pause re-enters each outer subflow AT the next mount; no pre-mount stage re-runs); every level's entry carries its DISPATCHER's continuation, read from the chart (a branch/fork-child mount hands back to its parent's `next`/join at the parent's level); parallel siblings that paused together wait in `checkpoint.pendingPauses` and are asked in turn, the join after the last; the rest of the run walks the REAL chart (a loop back to the paused stage reaches it and it pauses again; later entries run the inputMapper). Not rebuilt (pinned in test/lib/pause/resume-known-limitations.test.ts): lazy-subflow / parallelForEach-branch pauses (refused), a parallel-branch STAGE's namespace on resume, fan-out error containment for the resumed child. **M3** commit-log replay (EventLog.materialise, commitValueAt — required under delta mode). **M4** loopTo re-entry — forward execution over accumulated state, bounded by maxIterations + dynamicNextHops. **M5** causalChain backward slicing (read-only analysis; honesty flags for untracked reads; `edgeAttribution: 'per-write'` refines edges via `TraceEntry.readKeys` when the writeProvenance dial recorded them — worklist, subset-of-ceiling safe). **M6 (query layer)** slice/ — variable-first triage: sliceForKey + append-fold element provenance + the ONLY safe serializations (sliceToJSON/formatSlice — never JSON.stringify a slice root). **M7 (read-time cursor)** time-travel/ — `timeTravel(snapshot)` walks stops over the finished log with `stateAt()` folding M3's replay at each one (base = `RuntimeSnapshot.initialState`, which now travels with the log); it is a READER, never a second live cursor, and `drill(mount)` opens a separate cursor over a subflow's own isolated log. 9.18.0: `timeTravel([paused, resumed])` chains a cross-executor M2 resume into ONE axis — the resumed leg's `initialState` (= the state at the pause) restarts the fold, commit indices stay run-local (`Stop.sourceIdx` names the leg), and the chain is refused unless the never-reset execution counter is monotonic across legs. Deep dive + step tables: [.claude/rules/backtracking.md](.claude/rules/backtracking.md).
|
|
@@ -78,6 +78,7 @@ Seven mechanisms, no state rollback anywhere: **M1** TransactionBuffer staging +
|
|
|
78
78
|
- **The admitted record (9.30.0)** — a commit's bundle, replayed onto the state its stage began from, gives back the stage's read-your-writes view (its working copy, by `deepEqual`, as a record can hold it — through `structuredClone`, so an `Error`'s dropped own fields never count) at every path it touched and at every container and array slot its writes made on the way there, below the stage's address (`runs/<id>` is where a namespaced stage writes, not a value it reads). VERIFIED for every commit that staged a `merge` or a nested op (`TransactionBuffer · admit` → `admission.ts · lossyFamilies`: one `dryFold`, no clone, families of TOUCHED paths compared at their roots); a family that does not fold back is re-encoded as `set` rows of the read-back at its last touch (`emitReadBack`). BY CONSTRUCTION for a stage of `set`/`delete` only, directly under its address (no fold). Every commit that already folded back keeps its bytes. NOT covered: an in-place edit of a value the stage read but never wrote at or above (M2 — still lost), and readers (`commitValueAt`) that disagree with the fold. Pinned by test/lib/memory/property/record-equals-read-back.property.test.ts (independent oracle) and, end to end on both engines, by the witness in property/copy-on-write-fixture.ts.
|
|
79
79
|
- Committed state immutable-after-swap — a generation is NEVER edited, and since 9.29.0 generations SHARE every untouched subtree (copy-on-write). First-touch views AND the transaction buffer's net-change diff base hold bare references on that guarantee — an in-place mutation of a committed container corrupts every generation that shares it and blinds the diff. Every writer copies before it writes (`pathOps · ownSpine` / `ownedRootOf`); pinned by the generations property in test/lib/memory/scenario/copy-on-write-commit.test.ts and the counted guard in test/lib/memory/boundary/commit-cost-independent-of-state.test.ts.
|
|
80
80
|
- Reads are borrowed live references (recorders get them un-cloned) — never mutate.
|
|
81
|
+
- The commit log is never the reader's to edit (9.44.2, `capture/freeze.ts`): `freezeRecord` freezes each bundle (`EventLog · record`) and the fold base, flags one holding a Date/Map/Set/RegExp/Error/buffer/view (what freezing cannot seal) and stores a view over a slice of a bigger buffer as its own bytes; `serveRecord` serves a sealed record as itself and an open one as a copy of its OPEN PATHS only (the containers on the way to each such value, mapped at the first serve — no spread, a throw leaves the record flagged; every other part shared; an own `"__proto__"` stays DATA via `putOwn`). Doors: `getSnapshot().commitLog` / `.initialState` (`runner/snapshot.ts · servedSnapshot`) and `EventLog.list()` (a new array per call). The engine's own snapshot (`ExecutionRuntime · getSnapshot` via `EventLog · recorded`, taken once per subflow mount) is NOT served — so the run path serves nothing; every walk iterative (pinned 20,000 deep). NOT yet covered — known open doors, follow-up: the served-surface law, designed with the record-frame clean-up (C3/C4): the engine's own snapshot on `/advanced` (its bundles and fold base; `executor.getRuntime()`, `EventLog.recorded()`), subflow results (`history`/`initialState`/`stageContexts`), the execution tree's `stageReads`/`stageWrites`/diagnostics/flow messages, recorder rows, `getCheckpoint()`, `getNarrativeEntries()`. Pinned: test/lib/memory/scenario/served-record-doors.test.ts + the property beside it.
|
|
81
82
|
- executionIndex globally monotonic per run; continues across resume. The FIRST CommitBundle per runtimeStageId is the stage's own: no `phase`, carries its tags. Only a later bundle of the same execution is a continuation, stamped by the WRITER (`phase: 'exit'` = a mount's exit after its merge-back; `phase: 'repeat'` = a fork child's fan-out settle), so a mount with no merge-back (lazy, `parallelForEach` branch, no `outputMapper`) is one bundle. Readers group by runtimeStageId and read `phase`, never the log's shape (9.39.0, F8); a pre-9.39.0 log is inferred only by `inferLegacyPhases` (on `/trace`), only without a tree; tree-less, a `subflowResults` entry marks a mount. Empty commits are deliberate cursor stops.
|
|
82
83
|
- runtimeStageId stamped BEFORE the stage runs — the entire event-correlation model rests on scope+flow events sharing it.
|
|
83
84
|
- One executor = one run at a time (_isExecuting guard). State values must survive structuredClone.
|
|
@@ -92,7 +93,7 @@ Seven mechanisms, no state rollback anywhere: **M1** TransactionBuffer staging +
|
|
|
92
93
|
1. **NOT a landmine any more (9.24.0), recorded because it was one for eight releases:** TypedScope's set trap used to JSON-round-trip the ASSIGNED VALUE of every object write (Date→string, Map→{}, own undefined dropped) while `$setValue` did not — two write paths, two byte shapes. The round-trip existed only to keep the scope's own Proxies out of the buffer; `reactive/handles.ts` recognises them now (O(1)), so `writeTraps.ts · sinkSetTrap`, `arrayTraps.ts` (index set, `MUTATING_METHODS` arguments, element-proxy leaf) and `createTypedScope · assignStateKey` hand the value to the sink AS ASSIGNED and the buffer's `structuredClone` at commit is the one detaching step — both doors store the same bytes (pinned: test/lib/reactive/scenario/assigned-value-only.test.ts, a fast-check property over `fc.jsonValue()`). Consequences to keep in mind: (a) a value nothing can clone — a function, a foreign Proxy such as a framework's reactive object — now fails the stage at COMMIT through the trap too (it always did through `$setValue`; the trap used to JSON-copy it silently, dropping the function); (b) `s.k = o; o.x = 1` commits `x: 1` — what the stage reads back — the same law 9.23.0 gave `$setValue`, and since 9.30.0 (owner ruling R1, the admitted record) so does `$update`: an in-place edit of a merged value within its stage is recorded; (c) the shape work the round-trip did for free stays explicit: `delete arr[i]`, a write past the end and `length` growth spell holes as `null` (`arrayTraps` · `fillHoles`). The surrounding state reaches the buffer by reference and is detached with `structuredClone` at commit (9.22.0 / 9.23.0).
|
|
93
94
|
2. Fork "parent breaks when ALL children broke" is implemented (ChildrenExecutor.ts:53) but **unwired** — every live call site passes parentBreakFlag=undefined; fork breaks do NOT propagate in real runs.
|
|
94
95
|
3. **First bite CLOSED (9.23.0 — clone once at commit):** `TransactionBuffer` · `set` now stores the REFERENCE in `overwritePatch` too (it always did in `workingCopy`) and the record's copy is taken ONCE per surviving path when the payload leaves the buffer (`toChangeOnlyPayload` / `toDeltaPayload`); `StageContext` · `trackWrite` holds the reference + verdict in `_pendingWrites` and `materialiseWrites` takes the retained form once per key at `commit()`. So `$setValue(k, o); o.x = 1` commits `x: 1` — what the stage read back — instead of a stale write-time snapshot (pinned: test/lib/memory/scenario/clone-once-at-commit.test.ts). The law "the record never aliases a caller's object" holds at the commit boundary; a mutation AFTER commit reaches nothing. Two things to keep in mind: (a) the engine's OWN nested ops (`set a` then `merge a.b` — the buffer driven directly; the proxy writes root keys) must not edit through a shared container, because only `workingCopy` receives a nested merge's result — `detachHeldAncestors` clones the held ancestor in `overwritePatch` first (the design page missed this; the `set-merge-interleaved` 9.22.0 reference pins it); (b) an UNCLONEABLE value (function, foreign Proxy) now fails at COMMIT, not at the write — the run still fails loudly with the `DataCloneError`, the stage cannot catch it, and none of that stage's writes land. The scope's OWN proxies are not uncloneable values at the boundaries the library owns (9.23.3, `reactive/handles.ts`): a handle handed to the fan-out selector, a subflow mapper or `$setValue` is swapped for the value behind it first — a handle buried inside a hand-built value elsewhere (an `interrupt` payload, a `$emit` payload) still fails at the clone. The element-write loop's other O(N)-per-write cost, the array commit callbacks' whole-array JSON round-trip, went in the same release (landmine 1, second moved behaviour); what remains per element write is the array proxy's own shallow copy-on-write (`arrayTraps` · `replaceInElement` / the traps' `[...getCurrent()]`, ~9 µs at N = 10k) — bench 1k 5.7 ms, 10k 104 ms. **Second bite — a raw element held past its stage:** (within ONE stage, 9.29.0: a raw read BEFORE the stage's first write is the committed object itself — edited in place and written back it records NO change, because the diff base is that object (M7; dev mode warns, `StageContext · warnOnCommittedMutation`); a raw read AFTER the first write is the stage's private copy, `TransactionBuffer · privatise` — option D, 9.28.0's behaviour; one the working copy cannot answer (a key the stage deleted) is LIVE state, as on 9.28.0, with the diff base detached there first, `TransactionBuffer · detachBase`, so a write-back is recorded as it was.) A value obtained through `find`/`filter`/`for…of`/`$getValue`/`$read`/`$toRaw` in stage A and mutated in stage B is the committed object itself, so the mutation edits committed state with no row, and the dev-mode guard (`StageContext` · `warnOnBorrowedMutation`) sees it only if B also READS that key. Cannot be trapped; documented in src/lib/reactive/README.md ("A handle is bound to its stage"). A PROXY held that long is refused at the write (`ScopeFacade` · `assertLive`, sealed by the commit observer — the refusal lives on the facade, not `stageWrite`, because the frame's post-commit re-use is what the engine's double-commit paths need).
|
|
95
|
-
4. **NOT a landmine any more (9.22.0), recorded because it was one:** an indexed array read (`arr[i]`) used to hand back the RAW element, and a nested array write committed with the `merge` verb whose array arm is a set UNION. Both are fixed at the root — `reactive/arrayTraps.ts` wraps elements, and a nested array commits as a `set` of its ROOT KEY (`createTypedScope` · nested array commit callback). Consequences to keep in mind: an array ASSIGNMENT now REPLACES at every depth (`$update` is still the append), and a nested array write appears in `bundle.overwrite`/verb `set`, not `bundle.updates`/verb `merge`. What the proxy still cannot see — an element reached via `find`/`filter`/`for…of`/`forEach` — is REPORTED loudly instead: `StageContext` · `warnOnBorrowedMutation` (a dev-mode WARNING at the frame's first commit, under `readTracking: 'full'` only — a report after the fact, not a refusal). `memory/
|
|
96
|
+
4. **NOT a landmine any more (9.22.0), recorded because it was one:** an indexed array read (`arr[i]`) used to hand back the RAW element, and a nested array write committed with the `merge` verb whose array arm is a set UNION. Both are fixed at the root — `reactive/arrayTraps.ts` wraps elements, and a nested array commits as a `set` of its ROOT KEY (`createTypedScope` · nested array commit callback). Consequences to keep in mind: an array ASSIGNMENT now REPLACES at every depth (`$update` is still the append), and a nested array write appears in `bundle.overwrite`/verb `set`, not `bundle.updates`/verb `merge`. What the proxy still cannot see — an element reached via `find`/`filter`/`for…of`/`forEach` — is REPORTED loudly instead: `StageContext` · `warnOnBorrowedMutation` (a dev-mode WARNING at the frame's first commit, under `readTracking: 'full'` only — a report after the fact, not a refusal). `memory/equality.ts` · `equalPairs` has one arm per value KIND (`capture/valueKinds.ts · kindOf`, the one classifier — every kind `structuredClone` keeps since 9.44.2; before it, a replaced RegExp/Error/boxed primitive/buffer/view/Blob was a no-op) so a `$setValue` of a new Date/Set/RegExp is a change, not a no-op; an opaque value (Blob) compares by identity in the replacement check and as equal between two COPIES of one record (`OpaqueRule`: the writer rule, element provenance, the borrowed-mutation guard, admission). Every proxy (nested/terminal/element) READS LIVE through `reactive/liveView.ts` — a held handle sees its own writes; it answers from the captured object only when the path is gone. See src/lib/reactive/README.md. **Named, not fixed (out of contract):** a cyclic self-reference reached through a terminal proxy commits array/element writes to the WRONG place (row recorded, fold agrees, value lands beside the cycle edge); a top-level key containing U+001F (the path separator) throws at the seed; an expando on an array (`arr.foo = 1`) is dropped by the array proxy's set trap (indices and `length` only).
|
|
96
97
|
|
|
97
98
|
## Pointers
|
|
98
99
|
- [.claude/rules/backtracking.md](.claude/rules/backtracking.md) — the 5 mechanisms with step tables + pseudocode
|
|
@@ -1,21 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* freeze.ts — the ONE deep-freeze walk (moved here from `scope/protection/readonlyInput.ts` in F3)
|
|
2
|
+
* freeze.ts — the ONE deep-freeze walk (moved here from `scope/protection/readonlyInput.ts` in F3),
|
|
3
|
+
* and the serve-time law for the commit log (9.44.2).
|
|
3
4
|
*
|
|
4
5
|
* WHY HERE. Saved trees freeze through this walk: the fold base served as
|
|
5
6
|
* `initialState` (`ExecutionRuntime · getFoldBase`), the
|
|
6
7
|
* dev-mode snapshot (`runner/snapshot.ts · servedSnapshot`), every state `stateAt` hands out
|
|
7
8
|
* (`time-travel/stateAt.ts`) and, since F3, every commit bundle (`EventLog · record`). `memory/` must
|
|
8
9
|
* not import `scope/` (that edge closed the memory ⇄ scope ⇄ recorder module cycle F0 removed), so the
|
|
9
|
-
* walk lives in this leaf, which imports nothing. Args use an ownership snapshot
|
|
10
|
-
* (`scope/protection/readonlyInput.ts · createFrozenArgs`): never freeze borrowed caller values.
|
|
10
|
+
* walk lives in this leaf folder, which imports nothing outside itself. Args use an ownership snapshot
|
|
11
|
+
* instead (`scope/protection/readonlyInput.ts · createFrozenArgs`): never freeze borrowed caller values.
|
|
12
|
+
*
|
|
13
|
+
* FREEZE WHAT CAN BE FROZEN, COPY WHAT CAN'T (9.44.2). `Object.freeze` cannot seal a Date's time, a
|
|
14
|
+
* Map's or Set's entries, a buffer's bytes, a RegExp (`compile()` rewrites a frozen one) or an Error
|
|
15
|
+
* (V8's own `stack` accessor writes through a frozen one). A fresh tree handed to one caller (a `stateAt`
|
|
16
|
+
* state, the dev-mode snapshot) is that caller's own, so freezing it is a guard and nothing more. The
|
|
17
|
+
* COMMIT LOG — each bundle, and the fold base — is served to every reader, so {@link freezeRecord}
|
|
18
|
+
* remembers that a record holds such a value, its first serve maps the containers on the way to each
|
|
19
|
+
* one (its open PATHS), and {@link serveRecord} hands a reader a copy of those paths only: a fresh copy
|
|
20
|
+
* of each such value, fresh frozen containers on the way to it, and every other part shared, frozen, as
|
|
21
|
+
* it is. Until 9.44.2 `snapshot.commitLog[i].overwrite.when.setTime(0)` rewrote every later snapshot,
|
|
22
|
+
* `stateAt`, `commitValueAt`, slice and cursor answer.
|
|
23
|
+
*
|
|
24
|
+
* Every walk here is ITERATIVE (an explicit stack): a record's depth is not bounded by the call stack.
|
|
11
25
|
*
|
|
12
26
|
* @example
|
|
13
27
|
* ```typescript
|
|
14
|
-
* import { deepFreeze } from './freeze.js';
|
|
28
|
+
* import { deepFreeze, freezeRecord, serveRecord } from './freeze.js';
|
|
15
29
|
*
|
|
16
30
|
* const args = deepFreeze({ order: { lines: [{ sku: 'A' }] }, bytes: new Uint8Array([1]) });
|
|
17
31
|
* Object.isFrozen(args.order.lines[0]); // true
|
|
18
32
|
* Object.isFrozen(args.bytes); // false — a typed array cannot be frozen; it is skipped
|
|
33
|
+
*
|
|
34
|
+
* const record = freezeRecord({ when: new Date(0), tags: ['a'] });
|
|
35
|
+
* const served = serveRecord(record);
|
|
36
|
+
* served.when.setTime(5); // changes the reader's copy
|
|
37
|
+
* serveRecord(record).when.getTime(); // 0 — every serve is the record as recorded
|
|
38
|
+
* served.tags === record.tags; // true — the sealed part is shared, not copied
|
|
39
|
+
* serveRecord(freezeRecord({ n: 1 })); // a record freezing sealed whole: served as itself
|
|
19
40
|
* ```
|
|
20
41
|
*/
|
|
21
42
|
/**
|
|
@@ -25,8 +46,8 @@
|
|
|
25
46
|
* AND any expando (`arr.note = { … }`). The dev-mode snapshot relies on this contract.
|
|
26
47
|
* - `'indices'` — the index elements only, so no key string is allocated per element; this is what
|
|
27
48
|
* keeps freezing a 10,000-element commit inside its budget (`bench/element-writes.ts`). An object
|
|
28
|
-
* hung on an array EXPANDO is then left unfrozen — the commit
|
|
29
|
-
* (`EventLog · record
|
|
49
|
+
* hung on an array EXPANDO is then left unfrozen, and unseen by {@link serveRecord} — the commit
|
|
50
|
+
* log's named hole (`EventLog · record`; an array expando is out of contract for state).
|
|
30
51
|
*/
|
|
31
52
|
export type ArrayWalk = 'every-key' | 'indices';
|
|
32
53
|
/**
|
|
@@ -41,7 +62,30 @@ export type ArrayWalk = 'every-key' | 'indices';
|
|
|
41
62
|
* snapshot here.
|
|
42
63
|
* - What `Object.freeze` cannot reach stays mutable — Map and Set contents, a Date's time, the
|
|
43
64
|
* bytes behind a buffer. A frozen RegExp's `lastIndex` is read-only, so a `/g` or `/y` regex
|
|
44
|
-
* taken from a frozen tree throws when `exec` or `replace` advance it.
|
|
65
|
+
* taken from a frozen tree throws when `exec` or `replace` advance it. The commit log goes through
|
|
66
|
+
* {@link freezeRecord} and {@link serveRecord} instead.
|
|
45
67
|
* - Functions are not descended (they are not values the engine stores).
|
|
46
68
|
*/
|
|
47
69
|
export declare function deepFreeze<T>(obj: T, arrays?: ArrayWalk): T;
|
|
70
|
+
/**
|
|
71
|
+
* {@link deepFreeze} for a record many readers are SERVED (a commit bundle, the fold base), and two more
|
|
72
|
+
* things on the same walk:
|
|
73
|
+
*
|
|
74
|
+
* - it remembers THAT the record holds a value freezing cannot seal — one flag; the record's first
|
|
75
|
+
* serve maps WHERE (the containers on the way to each such value, its open paths), so the run pays
|
|
76
|
+
* nothing more and {@link serveRecord} copies those paths and nothing else;
|
|
77
|
+
* - a typed array or `DataView` that views a SLICE of a bigger buffer (a Node `Buffer` views its
|
|
78
|
+
* shared pool) is replaced, in the record, by a copy of the bytes it views — the record keeps the
|
|
79
|
+
* view's bytes, never the rest of the buffer (a resizable or shared buffer is kept as it is).
|
|
80
|
+
*
|
|
81
|
+
* A part frozen before is not frozen past (deepFreeze's contract) but is looked through, so a value
|
|
82
|
+
* freezing cannot seal inside it still opens the record. Returns `record`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function freezeRecord<T extends object>(record: T, arrays?: ArrayWalk): T;
|
|
85
|
+
/**
|
|
86
|
+
* The record as a reader may hold it — THE serve-time law: a record freezing sealed whole is served as
|
|
87
|
+
* itself (shared, no cost); any other as a copy of its open paths ({@link freezeRecord}): fresh frozen
|
|
88
|
+
* containers down to each value freezing cannot seal, a fresh copy of that value, and every other part
|
|
89
|
+
* shared, frozen, as it is. A copy is served the same way again.
|
|
90
|
+
*/
|
|
91
|
+
export declare function serveRecord<T>(record: T): T;
|
|
@@ -1,23 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* freeze.ts — the ONE deep-freeze walk (moved here from `scope/protection/readonlyInput.ts` in F3)
|
|
2
|
+
* freeze.ts — the ONE deep-freeze walk (moved here from `scope/protection/readonlyInput.ts` in F3),
|
|
3
|
+
* and the serve-time law for the commit log (9.44.2).
|
|
3
4
|
*
|
|
4
5
|
* WHY HERE. Saved trees freeze through this walk: the fold base served as
|
|
5
6
|
* `initialState` (`ExecutionRuntime · getFoldBase`), the
|
|
6
7
|
* dev-mode snapshot (`runner/snapshot.ts · servedSnapshot`), every state `stateAt` hands out
|
|
7
8
|
* (`time-travel/stateAt.ts`) and, since F3, every commit bundle (`EventLog · record`). `memory/` must
|
|
8
9
|
* not import `scope/` (that edge closed the memory ⇄ scope ⇄ recorder module cycle F0 removed), so the
|
|
9
|
-
* walk lives in this leaf, which imports nothing. Args use an ownership snapshot
|
|
10
|
-
* (`scope/protection/readonlyInput.ts · createFrozenArgs`): never freeze borrowed caller values.
|
|
10
|
+
* walk lives in this leaf folder, which imports nothing outside itself. Args use an ownership snapshot
|
|
11
|
+
* instead (`scope/protection/readonlyInput.ts · createFrozenArgs`): never freeze borrowed caller values.
|
|
12
|
+
*
|
|
13
|
+
* FREEZE WHAT CAN BE FROZEN, COPY WHAT CAN'T (9.44.2). `Object.freeze` cannot seal a Date's time, a
|
|
14
|
+
* Map's or Set's entries, a buffer's bytes, a RegExp (`compile()` rewrites a frozen one) or an Error
|
|
15
|
+
* (V8's own `stack` accessor writes through a frozen one). A fresh tree handed to one caller (a `stateAt`
|
|
16
|
+
* state, the dev-mode snapshot) is that caller's own, so freezing it is a guard and nothing more. The
|
|
17
|
+
* COMMIT LOG — each bundle, and the fold base — is served to every reader, so {@link freezeRecord}
|
|
18
|
+
* remembers that a record holds such a value, its first serve maps the containers on the way to each
|
|
19
|
+
* one (its open PATHS), and {@link serveRecord} hands a reader a copy of those paths only: a fresh copy
|
|
20
|
+
* of each such value, fresh frozen containers on the way to it, and every other part shared, frozen, as
|
|
21
|
+
* it is. Until 9.44.2 `snapshot.commitLog[i].overwrite.when.setTime(0)` rewrote every later snapshot,
|
|
22
|
+
* `stateAt`, `commitValueAt`, slice and cursor answer.
|
|
23
|
+
*
|
|
24
|
+
* Every walk here is ITERATIVE (an explicit stack): a record's depth is not bounded by the call stack.
|
|
11
25
|
*
|
|
12
26
|
* @example
|
|
13
27
|
* ```typescript
|
|
14
|
-
* import { deepFreeze } from './freeze.js';
|
|
28
|
+
* import { deepFreeze, freezeRecord, serveRecord } from './freeze.js';
|
|
15
29
|
*
|
|
16
30
|
* const args = deepFreeze({ order: { lines: [{ sku: 'A' }] }, bytes: new Uint8Array([1]) });
|
|
17
31
|
* Object.isFrozen(args.order.lines[0]); // true
|
|
18
32
|
* Object.isFrozen(args.bytes); // false — a typed array cannot be frozen; it is skipped
|
|
33
|
+
*
|
|
34
|
+
* const record = freezeRecord({ when: new Date(0), tags: ['a'] });
|
|
35
|
+
* const served = serveRecord(record);
|
|
36
|
+
* served.when.setTime(5); // changes the reader's copy
|
|
37
|
+
* serveRecord(record).when.getTime(); // 0 — every serve is the record as recorded
|
|
38
|
+
* served.tags === record.tags; // true — the sealed part is shared, not copied
|
|
39
|
+
* serveRecord(freezeRecord({ n: 1 })); // a record freezing sealed whole: served as itself
|
|
19
40
|
* ```
|
|
20
41
|
*/
|
|
42
|
+
import { kindOf, SEALABLE } from './valueKinds.js';
|
|
21
43
|
/**
|
|
22
44
|
* Freezes `obj` and every object reachable through its own properties, and returns `obj`.
|
|
23
45
|
*
|
|
@@ -30,32 +52,275 @@
|
|
|
30
52
|
* snapshot here.
|
|
31
53
|
* - What `Object.freeze` cannot reach stays mutable — Map and Set contents, a Date's time, the
|
|
32
54
|
* bytes behind a buffer. A frozen RegExp's `lastIndex` is read-only, so a `/g` or `/y` regex
|
|
33
|
-
* taken from a frozen tree throws when `exec` or `replace` advance it.
|
|
55
|
+
* taken from a frozen tree throws when `exec` or `replace` advance it. The commit log goes through
|
|
56
|
+
* {@link freezeRecord} and {@link serveRecord} instead.
|
|
34
57
|
* - Functions are not descended (they are not values the engine stores).
|
|
35
58
|
*/
|
|
36
59
|
export function deepFreeze(obj, arrays = 'every-key') {
|
|
37
|
-
|
|
60
|
+
if (obj !== null && typeof obj === 'object')
|
|
61
|
+
walkAndFreeze(obj, arrays === 'indices', false);
|
|
38
62
|
return obj;
|
|
39
63
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Containers of a record that hold — on some path below them — a value freezing cannot seal: `true` once
|
|
66
|
+
* mapped (the container is on an open path), `false` for a record {@link freezeRecord} found open whose
|
|
67
|
+
* paths no serve has mapped yet. A container absent here is sealed whole.
|
|
68
|
+
*/
|
|
69
|
+
const OPEN = new WeakMap();
|
|
70
|
+
/**
|
|
71
|
+
* {@link deepFreeze} for a record many readers are SERVED (a commit bundle, the fold base), and two more
|
|
72
|
+
* things on the same walk:
|
|
73
|
+
*
|
|
74
|
+
* - it remembers THAT the record holds a value freezing cannot seal — one flag; the record's first
|
|
75
|
+
* serve maps WHERE (the containers on the way to each such value, its open paths), so the run pays
|
|
76
|
+
* nothing more and {@link serveRecord} copies those paths and nothing else;
|
|
77
|
+
* - a typed array or `DataView` that views a SLICE of a bigger buffer (a Node `Buffer` views its
|
|
78
|
+
* shared pool) is replaced, in the record, by a copy of the bytes it views — the record keeps the
|
|
79
|
+
* view's bytes, never the rest of the buffer (a resizable or shared buffer is kept as it is).
|
|
80
|
+
*
|
|
81
|
+
* A part frozen before is not frozen past (deepFreeze's contract) but is looked through, so a value
|
|
82
|
+
* freezing cannot seal inside it still opens the record. Returns `record`.
|
|
83
|
+
*/
|
|
84
|
+
export function freezeRecord(record, arrays = 'every-key') {
|
|
85
|
+
if (!OPEN.has(record) && walkAndFreeze(record, arrays === 'indices', true))
|
|
86
|
+
OPEN.set(record, false);
|
|
87
|
+
return record;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The record as a reader may hold it — THE serve-time law: a record freezing sealed whole is served as
|
|
91
|
+
* itself (shared, no cost); any other as a copy of its open paths ({@link freezeRecord}): fresh frozen
|
|
92
|
+
* containers down to each value freezing cannot seal, a fresh copy of that value, and every other part
|
|
93
|
+
* shared, frozen, as it is. A copy is served the same way again.
|
|
94
|
+
*/
|
|
95
|
+
export function serveRecord(record) {
|
|
96
|
+
if (record === null || typeof record !== 'object')
|
|
97
|
+
return record;
|
|
98
|
+
const mapped = OPEN.get(record);
|
|
99
|
+
if (mapped === undefined)
|
|
100
|
+
return record;
|
|
101
|
+
if (!mapped)
|
|
102
|
+
mapOpenPaths(record);
|
|
103
|
+
return OPEN.get(record) === true ? copyOpenPaths(record) : record;
|
|
104
|
+
}
|
|
105
|
+
/** A value freezing cannot seal — a view, or a kind `SEALABLE` says no to (a Date, a Map, an Error …). */
|
|
106
|
+
function isUnsealable(value) {
|
|
107
|
+
return ArrayBuffer.isView(value) || !SEALABLE[kindOf(value)];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Freeze `root` and every container under it, iteratively; `record` adds the look-through of parts
|
|
111
|
+
* frozen before and the compaction of views over a slice. `true` when something under `root` (or `root`
|
|
112
|
+
* itself) cannot be sealed.
|
|
113
|
+
*/
|
|
114
|
+
function walkAndFreeze(root, indices, record) {
|
|
115
|
+
let open = false;
|
|
116
|
+
let lookedThrough;
|
|
117
|
+
const stack = [root];
|
|
118
|
+
while (stack.length > 0) {
|
|
119
|
+
const node = stack.pop();
|
|
120
|
+
if (ArrayBuffer.isView(node)) {
|
|
121
|
+
open = true; // its bytes — and a non-empty one cannot be frozen at all
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const frozenBefore = Object.isFrozen(node);
|
|
125
|
+
if (frozenBefore) {
|
|
126
|
+
if (!record || OPEN.has(node)) {
|
|
127
|
+
open ||= record;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if ((lookedThrough ??= new Set()).has(node))
|
|
131
|
+
continue;
|
|
132
|
+
lookedThrough.add(node); // a part frozen before: looked through, never frozen past
|
|
133
|
+
}
|
|
134
|
+
if (record && !open && !SEALABLE[kindOf(node)])
|
|
135
|
+
open = true;
|
|
136
|
+
// Children first, while `node` is still open to the compaction below; then the freeze.
|
|
137
|
+
const compacting = record && !frozenBefore;
|
|
138
|
+
if (indices && Array.isArray(node)) {
|
|
139
|
+
for (let i = 0; i < node.length; i++) {
|
|
140
|
+
const child = node[i];
|
|
141
|
+
if (child === null || typeof child !== 'object')
|
|
142
|
+
continue;
|
|
143
|
+
stack.push(compacting && ArrayBuffer.isView(child) ? compact(node, i, child) : child);
|
|
144
|
+
}
|
|
51
145
|
}
|
|
52
|
-
|
|
146
|
+
else {
|
|
147
|
+
const names = Object.getOwnPropertyNames(node);
|
|
148
|
+
for (let i = 0; i < names.length; i++) {
|
|
149
|
+
const child = node[names[i]];
|
|
150
|
+
if (child === null || typeof child !== 'object')
|
|
151
|
+
continue;
|
|
152
|
+
stack.push(compacting && ArrayBuffer.isView(child) ? compact(node, names[i], child) : child);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (!frozenBefore)
|
|
156
|
+
Object.freeze(node);
|
|
157
|
+
}
|
|
158
|
+
return open;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* A view over a SLICE of a bigger buffer, replaced in `container` by a copy of the bytes it views
|
|
162
|
+
* (the type it is — a Node `Buffer` comes out a `Uint8Array`, as a clone of it does). Anything else is
|
|
163
|
+
* returned as it is. A resizable or shared buffer is kept: a copy would change what it is.
|
|
164
|
+
*/
|
|
165
|
+
function compact(container, key, child) {
|
|
166
|
+
const buffer = child.buffer;
|
|
167
|
+
if (child.byteOffset === 0 && child.byteLength === buffer.byteLength)
|
|
168
|
+
return child;
|
|
169
|
+
if (buffer.resizable === true || !(buffer instanceof ArrayBuffer))
|
|
170
|
+
return child;
|
|
171
|
+
const bytes = buffer.slice(child.byteOffset, child.byteOffset + child.byteLength);
|
|
172
|
+
const tag = Object.prototype.toString.call(child).slice(8, -1);
|
|
173
|
+
const Ctor = globalThis[tag];
|
|
174
|
+
if (typeof Ctor !== 'function')
|
|
175
|
+
return child;
|
|
176
|
+
const copy = new Ctor(bytes);
|
|
177
|
+
try {
|
|
178
|
+
container[key] = copy;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return child; // a property the record does not let be replaced (a hand-built bundle)
|
|
182
|
+
}
|
|
183
|
+
return copy;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Map the open paths of `root` — mark every container that reaches a value freezing cannot seal, so a
|
|
187
|
+
* serve copies exactly those (DAGs and cycles included: the marks run UP the reverse edges from each
|
|
188
|
+
* such value). Runs once per open record, at its first serve. A node's first holder is kept in one map;
|
|
189
|
+
* any other holder (a shared part, a cycle) in a second, made only when there is one.
|
|
190
|
+
*/
|
|
191
|
+
function mapOpenPaths(root) {
|
|
192
|
+
const holder = new Map();
|
|
193
|
+
let moreHolders;
|
|
194
|
+
const leaves = [];
|
|
195
|
+
const stack = [root];
|
|
196
|
+
while (stack.length > 0) {
|
|
197
|
+
const node = stack.pop();
|
|
198
|
+
if (isUnsealable(node)) {
|
|
199
|
+
leaves.push(node); // a leaf: its contents are copied with it
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const names = Object.keys(node);
|
|
203
|
+
for (let i = 0; i < names.length; i++) {
|
|
204
|
+
const child = node[names[i]];
|
|
205
|
+
if (child === null || typeof child !== 'object')
|
|
206
|
+
continue;
|
|
207
|
+
if (child !== root && !holder.has(child)) {
|
|
208
|
+
holder.set(child, node);
|
|
209
|
+
stack.push(child);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const more = (moreHolders ??= new Map()).get(child);
|
|
213
|
+
if (more === undefined)
|
|
214
|
+
moreHolders.set(child, [node]);
|
|
215
|
+
else
|
|
216
|
+
more.push(node);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Marked in THIS map, not by an earlier one: a part another record already mapped still opens
|
|
220
|
+
// every container of this record on the way to it.
|
|
221
|
+
const marked = new Set();
|
|
222
|
+
const up = [];
|
|
223
|
+
const holdersOf = (node) => {
|
|
224
|
+
const first = holder.get(node);
|
|
225
|
+
if (first !== undefined)
|
|
226
|
+
up.push(first);
|
|
227
|
+
const more = moreHolders?.get(node);
|
|
228
|
+
// One push per holder: a spread passes every holder as a call argument, and one object held by
|
|
229
|
+
// 120,000 containers overflowed the stack.
|
|
230
|
+
if (more !== undefined)
|
|
231
|
+
for (let i = 0; i < more.length; i++)
|
|
232
|
+
up.push(more[i]);
|
|
233
|
+
};
|
|
234
|
+
for (const leaf of leaves) {
|
|
235
|
+
if (leaf === root)
|
|
236
|
+
marked.add(root);
|
|
237
|
+
holdersOf(leaf);
|
|
238
|
+
}
|
|
239
|
+
while (up.length > 0) {
|
|
240
|
+
const node = up.pop();
|
|
241
|
+
if (marked.has(node))
|
|
242
|
+
continue;
|
|
243
|
+
marked.add(node);
|
|
244
|
+
holdersOf(node);
|
|
245
|
+
}
|
|
246
|
+
// Only now, the walk done, does the record's flag give way to its map: a mapping that throws leaves
|
|
247
|
+
// the record flagged, so the next serve maps again — it never hands out the record itself.
|
|
248
|
+
if (!marked.has(root))
|
|
249
|
+
OPEN.delete(root);
|
|
250
|
+
for (const node of marked)
|
|
251
|
+
OPEN.set(node, true);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The served copy of an open record: its open containers copied (fresh, then frozen, and themselves
|
|
255
|
+
* open — a copy is served by copy again), each value freezing cannot seal copied, every sealed part
|
|
256
|
+
* shared. Iterative; one copy per original, so containers shared or cyclic stay shared in the copy. The
|
|
257
|
+
* values freezing cannot seal are copied ONE BY ONE: two of them that share a part (an `ArrayBuffer`
|
|
258
|
+
* and a view of it, an error whose `cause` is another key's Date) come out as separate copies — equal
|
|
259
|
+
* values, the sharing between them not kept.
|
|
260
|
+
*/
|
|
261
|
+
function copyOpenPaths(root) {
|
|
262
|
+
const copies = new Map();
|
|
263
|
+
const shells = [];
|
|
264
|
+
const copyOf = (value, pending) => {
|
|
265
|
+
const done = copies.get(value);
|
|
266
|
+
if (done !== undefined)
|
|
267
|
+
return done;
|
|
268
|
+
let copy;
|
|
269
|
+
if (isUnsealable(value)) {
|
|
270
|
+
copy = copyLeaf(value);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
copy = Array.isArray(value) ? new Array(value.length) : {};
|
|
274
|
+
shells.push(copy);
|
|
275
|
+
pending.push(value);
|
|
276
|
+
}
|
|
277
|
+
copies.set(value, copy);
|
|
278
|
+
return copy;
|
|
279
|
+
};
|
|
280
|
+
const pending = [];
|
|
281
|
+
const out = copyOf(root, pending);
|
|
282
|
+
while (pending.length > 0) {
|
|
283
|
+
const node = pending.pop();
|
|
284
|
+
const copy = copies.get(node);
|
|
285
|
+
for (const name of Object.keys(node)) {
|
|
286
|
+
const child = node[name];
|
|
287
|
+
putOwn(copy, name, child !== null && typeof child === 'object' && (OPEN.has(child) || isUnsealable(child))
|
|
288
|
+
? copyOf(child, pending)
|
|
289
|
+
: child);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
for (const shell of shells) {
|
|
293
|
+
Object.freeze(shell);
|
|
294
|
+
OPEN.set(shell, true);
|
|
295
|
+
}
|
|
296
|
+
// A leaf copy is the reader's own; frozen where freezing reaches, as the record's parts are.
|
|
297
|
+
for (const copy of copies.values())
|
|
298
|
+
if (!ArrayBuffer.isView(copy))
|
|
299
|
+
Object.freeze(copy);
|
|
300
|
+
return out;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* `target[name] = value`, as an OWN data property. A key the shell only inherits — an own `"__proto__"`
|
|
304
|
+
* of the record (`JSON.parse` makes one) — would call the inherited setter and re-parent the copy; it is
|
|
305
|
+
* defined as data instead, as `memory/merge.ts · mergeGuarded` keeps it.
|
|
306
|
+
*/
|
|
307
|
+
function putOwn(target, name, value) {
|
|
308
|
+
if (!Object.prototype.hasOwnProperty.call(target, name) && Reflect.has(target, name)) {
|
|
309
|
+
Object.defineProperty(target, name, { value, enumerable: true, writable: true, configurable: true });
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
target[name] = value;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/** A fresh copy of a value freezing cannot seal. One the clone refuses (hand-built) is served as it is. */
|
|
316
|
+
function copyLeaf(value) {
|
|
317
|
+
if (kindOf(value) === 'date')
|
|
318
|
+
return new Date(Date.prototype.getTime.call(value));
|
|
319
|
+
try {
|
|
320
|
+
return structuredClone(value);
|
|
53
321
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const child = value[names[i]];
|
|
57
|
-
if (child !== null && typeof child === 'object')
|
|
58
|
-
freezeValue(child, indices);
|
|
322
|
+
catch {
|
|
323
|
+
return value;
|
|
59
324
|
}
|
|
60
325
|
}
|
|
61
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJlZXplLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9jYXB0dXJlL2ZyZWV6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQWNIOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxVQUFVLFVBQVUsQ0FBSSxHQUFNLEVBQUUsU0FBb0IsV0FBVztJQUNuRSxXQUFXLENBQUMsR0FBRyxFQUFFLE1BQU0sS0FBSyxTQUFTLENBQUMsQ0FBQztJQUN2QyxPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FBQyxLQUFjLEVBQUUsT0FBZ0I7SUFDbkQsSUFBSSxLQUFLLEtBQUssSUFBSSxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO1FBQUUsT0FBTztJQUMvRyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3JCLG9HQUFvRztJQUNwRyx3REFBd0Q7SUFDeEQsSUFBSSxPQUFPLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3BDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDdEMsTUFBTSxLQUFLLEdBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2hDLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRO2dCQUFFLFdBQVcsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDL0UsQ0FBQztRQUNELE9BQU87SUFDVCxDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2hELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDdEMsTUFBTSxLQUFLLEdBQUksS0FBaUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMzRCxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTtZQUFFLFdBQVcsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDL0UsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGZyZWV6ZS50cyDigJQgdGhlIE9ORSBkZWVwLWZyZWV6ZSB3YWxrIChtb3ZlZCBoZXJlIGZyb20gYHNjb3BlL3Byb3RlY3Rpb24vcmVhZG9ubHlJbnB1dC50c2AgaW4gRjMpLlxuICpcbiAqIFdIWSBIRVJFLiBTYXZlZCB0cmVlcyBmcmVlemUgdGhyb3VnaCB0aGlzIHdhbGs6IHRoZSBmb2xkIGJhc2Ugc2VydmVkIGFzXG4gKiBgaW5pdGlhbFN0YXRlYCAoYEV4ZWN1dGlvblJ1bnRpbWUgwrcgZ2V0Rm9sZEJhc2VgKSwgdGhlXG4gKiBkZXYtbW9kZSBzbmFwc2hvdCAoYHJ1bm5lci9zbmFwc2hvdC50cyDCtyBzZXJ2ZWRTbmFwc2hvdGApLCBldmVyeSBzdGF0ZSBgc3RhdGVBdGAgaGFuZHMgb3V0XG4gKiAoYHRpbWUtdHJhdmVsL3N0YXRlQXQudHNgKSBhbmQsIHNpbmNlIEYzLCBldmVyeSBjb21taXQgYnVuZGxlIChgRXZlbnRMb2cgwrcgcmVjb3JkYCkuIGBtZW1vcnkvYCBtdXN0XG4gKiBub3QgaW1wb3J0IGBzY29wZS9gICh0aGF0IGVkZ2UgY2xvc2VkIHRoZSBtZW1vcnkg4oeEIHNjb3BlIOKHhCByZWNvcmRlciBtb2R1bGUgY3ljbGUgRjAgcmVtb3ZlZCksIHNvIHRoZVxuICogd2FsayBsaXZlcyBpbiB0aGlzIGxlYWYsIHdoaWNoIGltcG9ydHMgbm90aGluZy4gQXJncyB1c2UgYW4gb3duZXJzaGlwIHNuYXBzaG90IGluc3RlYWRcbiAqIChgc2NvcGUvcHJvdGVjdGlvbi9yZWFkb25seUlucHV0LnRzIMK3IGNyZWF0ZUZyb3plbkFyZ3NgKTogbmV2ZXIgZnJlZXplIGJvcnJvd2VkIGNhbGxlciB2YWx1ZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGRlZXBGcmVlemUgfSBmcm9tICcuL2ZyZWV6ZS5qcyc7XG4gKlxuICogY29uc3QgYXJncyA9IGRlZXBGcmVlemUoeyBvcmRlcjogeyBsaW5lczogW3sgc2t1OiAnQScgfV0gfSwgYnl0ZXM6IG5ldyBVaW50OEFycmF5KFsxXSkgfSk7XG4gKiBPYmplY3QuaXNGcm96ZW4oYXJncy5vcmRlci5saW5lc1swXSk7IC8vIHRydWVcbiAqIE9iamVjdC5pc0Zyb3plbihhcmdzLmJ5dGVzKTsgLy8gZmFsc2Ug4oCUIGEgdHlwZWQgYXJyYXkgY2Fubm90IGJlIGZyb3plbjsgaXQgaXMgc2tpcHBlZFxuICogYGBgXG4gKi9cblxuLyoqXG4gKiBIb3cge0BsaW5rIGRlZXBGcmVlemV9IHdhbGtzIGFuIEFSUkFZLlxuICpcbiAqIC0gYCdldmVyeS1rZXknYCAodGhlIGRlZmF1bHQpIOKAlCBldmVyeSBvd24gcHJvcGVydHksIGFzIGZvciBhbnkgb3RoZXIgb2JqZWN0OiB0aGUgaW5kZXggZWxlbWVudHNcbiAqICAgQU5EIGFueSBleHBhbmRvIChgYXJyLm5vdGUgPSB7IOKApiB9YCkuIFRoZSBkZXYtbW9kZSBzbmFwc2hvdCByZWxpZXMgb24gdGhpcyBjb250cmFjdC5cbiAqIC0gYCdpbmRpY2VzJ2Ag4oCUIHRoZSBpbmRleCBlbGVtZW50cyBvbmx5LCBzbyBubyBrZXkgc3RyaW5nIGlzIGFsbG9jYXRlZCBwZXIgZWxlbWVudDsgdGhpcyBpcyB3aGF0XG4gKiAgIGtlZXBzIGZyZWV6aW5nIGEgMTAsMDAwLWVsZW1lbnQgY29tbWl0IGluc2lkZSBpdHMgYnVkZ2V0IChgYmVuY2gvZWxlbWVudC13cml0ZXMudHNgKS4gQW4gb2JqZWN0XG4gKiAgIGh1bmcgb24gYW4gYXJyYXkgRVhQQU5ETyBpcyB0aGVuIGxlZnQgdW5mcm96ZW4g4oCUIHRoZSBjb21taXQgbG9nJ3MgbmFtZWQgaG9sZVxuICogICAoYEV2ZW50TG9nIMK3IHJlY29yZGApLlxuICovXG5leHBvcnQgdHlwZSBBcnJheVdhbGsgPSAnZXZlcnkta2V5JyB8ICdpbmRpY2VzJztcblxuLyoqXG4gKiBGcmVlemVzIGBvYmpgIGFuZCBldmVyeSBvYmplY3QgcmVhY2hhYmxlIHRocm91Z2ggaXRzIG93biBwcm9wZXJ0aWVzLCBhbmQgcmV0dXJucyBgb2JqYC5cbiAqXG4gKiAtIEFuIG9iamVjdCB0aGF0IGlzIEFMUkVBRFkgZnJvemVuIGlzIGxlZnQgYXMgaXQgaXMsIGFuZCBub3QgZGVzY2VuZGVkIOKAlCA5LjMyLjAncyBjb250cmFjdCwga2VwdDpcbiAqICAgYXJncyBtYXkgaG9sZCBhIGNhbGxlcidzIGZyb3plbiBvYmplY3Qgd2l0aCBsaXZlIHBhcnRzIGluc2lkZSAoYSBjbGFzcyBpbnN0YW5jZSBhIHN0YWdlIGNhbGxzKSxcbiAqICAgYW5kIGZyZWV6aW5nIHBhc3QgaXQgd291bGQgYnJlYWsgdGhlbS4gSXQgaXMgYWxzbyB3aGF0IGVuZHMgYSBjeWNsZS4gVGhlIGNvbW1pdCBsb2cgbmV2ZXIgbWVldHNcbiAqICAgb25lOiBpdHMgcGF5bG9hZHMgYXJlIGZyZXNoIGBzdHJ1Y3R1cmVkQ2xvbmVgcy5cbiAqIC0gQXJyYXlCdWZmZXIgdmlld3MgKHR5cGVkIGFycmF5cywgYERhdGFWaWV3YCkgYXJlIHNraXBwZWQ6IGBPYmplY3QuZnJlZXplYCB0aHJvd3Mgb24gYSBub24tZW1wdHlcbiAqICAgdHlwZWQgYXJyYXksIHNvIGEgYFVpbnQ4QXJyYXlgIGluIHN0YXRlLCBhcmdzIG9yIHRoZSBmb2xkIGJhc2UgdXNlZCB0byBmYWlsIHRoZSBydW4gb3IgdGhlXG4gKiAgIHNuYXBzaG90IGhlcmUuXG4gKiAtIFdoYXQgYE9iamVjdC5mcmVlemVgIGNhbm5vdCByZWFjaCBzdGF5cyBtdXRhYmxlIOKAlCBNYXAgYW5kIFNldCBjb250ZW50cywgYSBEYXRlJ3MgdGltZSwgdGhlXG4gKiAgIGJ5dGVzIGJlaGluZCBhIGJ1ZmZlci4gQSBmcm96ZW4gUmVnRXhwJ3MgYGxhc3RJbmRleGAgaXMgcmVhZC1vbmx5LCBzbyBhIGAvZ2Agb3IgYC95YCByZWdleFxuICogICB0YWtlbiBmcm9tIGEgZnJvemVuIHRyZWUgdGhyb3dzIHdoZW4gYGV4ZWNgIG9yIGByZXBsYWNlYCBhZHZhbmNlIGl0LlxuICogLSBGdW5jdGlvbnMgYXJlIG5vdCBkZXNjZW5kZWQgKHRoZXkgYXJlIG5vdCB2YWx1ZXMgdGhlIGVuZ2luZSBzdG9yZXMpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVlcEZyZWV6ZTxUPihvYmo6IFQsIGFycmF5czogQXJyYXlXYWxrID0gJ2V2ZXJ5LWtleScpOiBUIHtcbiAgZnJlZXplVmFsdWUob2JqLCBhcnJheXMgPT09ICdpbmRpY2VzJyk7XG4gIHJldHVybiBvYmo7XG59XG5cbmZ1bmN0aW9uIGZyZWV6ZVZhbHVlKHZhbHVlOiB1bmtub3duLCBpbmRpY2VzOiBib29sZWFuKTogdm9pZCB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgIT09ICdvYmplY3QnIHx8IEFycmF5QnVmZmVyLmlzVmlldyh2YWx1ZSkgfHwgT2JqZWN0LmlzRnJvemVuKHZhbHVlKSkgcmV0dXJuO1xuICBPYmplY3QuZnJlZXplKHZhbHVlKTtcbiAgLy8gVGhlIHR3byBsb29wcyBhcmUgd3JpdHRlbiBvdXQgcmF0aGVyIHRoYW4gc2hhcmVkIHRocm91Z2ggYSBjYWxsYmFjazogdGhpcyBydW5zIG9uY2UgcGVyIG9iamVjdCBvZlxuICAvLyBldmVyeSBjb21taXQsIGFuZCBhIGNsb3N1cmUgcGVyIG9iamVjdCBpcyBtZWFzdXJhYmxlLlxuICBpZiAoaW5kaWNlcyAmJiBBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdmFsdWUubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGNoaWxkOiB1bmtub3duID0gdmFsdWVbaV07XG4gICAgICBpZiAoY2hpbGQgIT09IG51bGwgJiYgdHlwZW9mIGNoaWxkID09PSAnb2JqZWN0JykgZnJlZXplVmFsdWUoY2hpbGQsIGluZGljZXMpO1xuICAgIH1cbiAgICByZXR1cm47XG4gIH1cbiAgY29uc3QgbmFtZXMgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyh2YWx1ZSk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbmFtZXMubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBjaGlsZCA9ICh2YWx1ZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilbbmFtZXNbaV1dO1xuICAgIGlmIChjaGlsZCAhPT0gbnVsbCAmJiB0eXBlb2YgY2hpbGQgPT09ICdvYmplY3QnKSBmcmVlemVWYWx1ZShjaGlsZCwgaW5kaWNlcyk7XG4gIH1cbn1cbiJdfQ==
|
|
326
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJlZXplLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9jYXB0dXJlL2ZyZWV6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXdDRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFjbkQ7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsTUFBTSxVQUFVLFVBQVUsQ0FBSSxHQUFNLEVBQUUsU0FBb0IsV0FBVztJQUNuRSxJQUFJLEdBQUcsS0FBSyxJQUFJLElBQUksT0FBTyxHQUFHLEtBQUssUUFBUTtRQUFFLGFBQWEsQ0FBQyxHQUFHLEVBQUUsTUFBTSxLQUFLLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUM3RixPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxJQUFJLEdBQUcsSUFBSSxPQUFPLEVBQW1CLENBQUM7QUFFNUM7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQW1CLE1BQVMsRUFBRSxTQUFvQixXQUFXO0lBQ3ZGLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLGFBQWEsQ0FBQyxNQUFNLEVBQUUsTUFBTSxLQUFLLFNBQVMsRUFBRSxJQUFJLENBQUM7UUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNwRyxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsV0FBVyxDQUFJLE1BQVM7SUFDdEMsSUFBSSxNQUFNLEtBQUssSUFBSSxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVE7UUFBRSxPQUFPLE1BQU0sQ0FBQztJQUNqRSxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFD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Q0FBQztBQUNILENBQUM7QUFFRCwyR0FBMkc7QUFDM0csU0FBUyxRQUFRLENBQUMsS0FBYTtJQUM3QixJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxNQUFNO1FBQUUsT0FBTyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNsRixJQUFJLENBQUM7UUFDSCxPQUFPLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogZnJlZXplLnRzIOKAlCB0aGUgT05FIGRlZXAtZnJlZXplIHdhbGsgKG1vdmVkIGhlcmUgZnJvbSBgc2NvcGUvcHJvdGVjdGlvbi9yZWFkb25seUlucHV0LnRzYCBpbiBGMyksXG4gKiBhbmQgdGhlIHNlcnZlLXRpbWUgbGF3IGZvciB0aGUgY29tbWl0IGxvZyAoOS40NC4yKS5cbiAqXG4gKiBXSFkgSEVSRS4gU2F2ZWQgdHJlZXMgZnJlZXplIHRocm91Z2ggdGhpcyB3YWxrOiB0aGUgZm9sZCBiYXNlIHNlcnZlZCBhc1xuICogYGluaXRpYWxTdGF0ZWAgKGBFeGVjdXRpb25SdW50aW1lIMK3IGdldEZvbGRCYXNlYCksIHRoZVxuICogZGV2LW1vZGUgc25hcHNob3QgKGBydW5uZXIvc25hcHNob3QudHMgwrcgc2VydmVkU25hcHNob3RgKSwgZXZlcnkgc3RhdGUgYHN0YXRlQXRgIGhhbmRzIG91dFxuICogKGB0aW1lLXRyYXZlbC9zdGF0ZUF0LnRzYCkgYW5kLCBzaW5jZSBGMywgZXZlcnkgY29tbWl0IGJ1bmRsZSAoYEV2ZW50TG9nIMK3IHJlY29yZGApLiBgbWVtb3J5L2AgbXVzdFxuICogbm90IGltcG9ydCBgc2NvcGUvYCAodGhhdCBlZGdlIGNsb3NlZCB0aGUgbWVtb3J5IOKHhCBzY29wZSDih4QgcmVjb3JkZXIgbW9kdWxlIGN5Y2xlIEYwIHJlbW92ZWQpLCBzbyB0aGVcbiAqIHdhbGsgbGl2ZXMgaW4gdGhpcyBsZWFmIGZvbGRlciwgd2hpY2ggaW1wb3J0cyBub3RoaW5nIG91dHNpZGUgaXRzZWxmLiBBcmdzIHVzZSBhbiBvd25lcnNoaXAgc25hcHNob3RcbiAqIGluc3RlYWQgKGBzY29wZS9wcm90ZWN0aW9uL3JlYWRvbmx5SW5wdXQudHMgwrcgY3JlYXRlRnJvemVuQXJnc2ApOiBuZXZlciBmcmVlemUgYm9ycm93ZWQgY2FsbGVyIHZhbHVlcy5cbiAqXG4gKiBGUkVFWkUgV0hBVCBDQU4gQkUgRlJPWkVOLCBDT1BZIFdIQVQgQ0FOJ1QgKDkuNDQuMikuIGBPYmplY3QuZnJlZXplYCBjYW5ub3Qgc2VhbCBhIERhdGUncyB0aW1lLCBhXG4gKiBNYXAncyBvciBTZXQncyBlbnRyaWVzLCBhIGJ1ZmZlcidzIGJ5dGVzLCBhIFJlZ0V4cCAoYGNvbXBpbGUoKWAgcmV3cml0ZXMgYSBmcm96ZW4gb25lKSBvciBhbiBFcnJvclxuICogKFY4J3Mgb3duIGBzdGFja2AgYWNjZXNzb3Igd3JpdGVzIHRocm91Z2ggYSBmcm96ZW4gb25lKS4gQSBmcmVzaCB0cmVlIGhhbmRlZCB0byBvbmUgY2FsbGVyIChhIGBzdGF0ZUF0YFxuICogc3RhdGUsIHRoZSBkZXYtbW9kZSBzbmFwc2hvdCkgaXMgdGhhdCBjYWxsZXIncyBvd24sIHNvIGZyZWV6aW5nIGl0IGlzIGEgZ3VhcmQgYW5kIG5vdGhpbmcgbW9yZS4gVGhlXG4gKiBDT01NSVQgTE9HIOKAlCBlYWNoIGJ1bmRsZSwgYW5kIHRoZSBmb2xkIGJhc2Ug4oCUIGlzIHNlcnZlZCB0byBldmVyeSByZWFkZXIsIHNvIHtAbGluayBmcmVlemVSZWNvcmR9XG4gKiByZW1lbWJlcnMgdGhhdCBhIHJlY29yZCBob2xkcyBzdWNoIGEgdmFsdWUsIGl0cyBmaXJzdCBzZXJ2ZSBtYXBzIHRoZSBjb250YWluZXJzIG9uIHRoZSB3YXkgdG8gZWFjaFxuICogb25lIChpdHMgb3BlbiBQQVRIUyksIGFuZCB7QGxpbmsgc2VydmVSZWNvcmR9IGhhbmRzIGEgcmVhZGVyIGEgY29weSBvZiB0aG9zZSBwYXRocyBvbmx5OiBhIGZyZXNoIGNvcHlcbiAqIG9mIGVhY2ggc3VjaCB2YWx1ZSwgZnJlc2ggZnJvemVuIGNvbnRhaW5lcnMgb24gdGhlIHdheSB0byBpdCwgYW5kIGV2ZXJ5IG90aGVyIHBhcnQgc2hhcmVkLCBmcm96ZW4sIGFzXG4gKiBpdCBpcy4gVW50aWwgOS40NC4yIGBzbmFwc2hvdC5jb21taXRMb2dbaV0ub3ZlcndyaXRlLndoZW4uc2V0VGltZSgwKWAgcmV3cm90ZSBldmVyeSBsYXRlciBzbmFwc2hvdCxcbiAqIGBzdGF0ZUF0YCwgYGNvbW1pdFZhbHVlQXRgLCBzbGljZSBhbmQgY3Vyc29yIGFuc3dlci5cbiAqXG4gKiBFdmVyeSB3YWxrIGhlcmUgaXMgSVRFUkFUSVZFIChhbiBleHBsaWNpdCBzdGFjayk6IGEgcmVjb3JkJ3MgZGVwdGggaXMgbm90IGJvdW5kZWQgYnkgdGhlIGNhbGwgc3RhY2suXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGRlZXBGcmVlemUsIGZyZWV6ZVJlY29yZCwgc2VydmVSZWNvcmQgfSBmcm9tICcuL2ZyZWV6ZS5qcyc7XG4gKlxuICogY29uc3QgYXJncyA9IGRlZXBGcmVlemUoeyBvcmRlcjogeyBsaW5lczogW3sgc2t1OiAnQScgfV0gfSwgYnl0ZXM6IG5ldyBVaW50OEFycmF5KFsxXSkgfSk7XG4gKiBPYmplY3QuaXNGcm96ZW4oYXJncy5vcmRlci5saW5lc1swXSk7IC8vIHRydWVcbiAqIE9iamVjdC5pc0Zyb3plbihhcmdzLmJ5dGVzKTsgLy8gZmFsc2Ug4oCUIGEgdHlwZWQgYXJyYXkgY2Fubm90IGJlIGZyb3plbjsgaXQgaXMgc2tpcHBlZFxuICpcbiAqIGNvbnN0IHJlY29yZCA9IGZyZWV6ZVJlY29yZCh7IHdoZW46IG5ldyBEYXRlKDApLCB0YWdzOiBbJ2EnXSB9KTtcbiAqIGNvbnN0IHNlcnZlZCA9IHNlcnZlUmVjb3JkKHJlY29yZCk7XG4gKiBzZXJ2ZWQud2hlbi5zZXRUaW1lKDUpOyAvLyBjaGFuZ2VzIHRoZSByZWFkZXIncyBjb3B5XG4gKiBzZXJ2ZVJlY29yZChyZWNvcmQpLndoZW4uZ2V0VGltZSgpOyAvLyAwIOKAlCBldmVyeSBzZXJ2ZSBpcyB0aGUgcmVjb3JkIGFzIHJlY29yZGVkXG4gKiBzZXJ2ZWQudGFncyA9PT0gcmVjb3JkLnRhZ3M7IC8vIHRydWUg4oCUIHRoZSBzZWFsZWQgcGFydCBpcyBzaGFyZWQsIG5vdCBjb3BpZWRcbiAqIHNlcnZlUmVjb3JkKGZyZWV6ZVJlY29yZCh7IG46IDEgfSkpOyAvLyBhIHJlY29yZCBmcmVlemluZyBzZWFsZWQgd2hvbGU6IHNlcnZlZCBhcyBpdHNlbGZcbiAqIGBgYFxuICovXG5cbmltcG9ydCB7IGtpbmRPZiwgU0VBTEFCTEUgfSBmcm9tICcuL3ZhbHVlS2luZHMuanMnO1xuXG4vKipcbiAqIEhvdyB7QGxpbmsgZGVlcEZyZWV6ZX0gd2Fsa3MgYW4gQVJSQVkuXG4gKlxuICogLSBgJ2V2ZXJ5LWtleSdgICh0aGUgZGVmYXVsdCkg4oCUIGV2ZXJ5IG93biBwcm9wZXJ0eSwgYXMgZm9yIGFueSBvdGhlciBvYmplY3Q6IHRoZSBpbmRleCBlbGVtZW50c1xuICogICBBTkQgYW55IGV4cGFuZG8gKGBhcnIubm90ZSA9IHsg4oCmIH1gKS4gVGhlIGRldi1tb2RlIHNuYXBzaG90IHJlbGllcyBvbiB0aGlzIGNvbnRyYWN0LlxuICogLSBgJ2luZGljZXMnYCDigJQgdGhlIGluZGV4IGVsZW1lbnRzIG9ubHksIHNvIG5vIGtleSBzdHJpbmcgaXMgYWxsb2NhdGVkIHBlciBlbGVtZW50OyB0aGlzIGlzIHdoYXRcbiAqICAga2VlcHMgZnJlZXppbmcgYSAxMCwwMDAtZWxlbWVudCBjb21taXQgaW5zaWRlIGl0cyBidWRnZXQgKGBiZW5jaC9lbGVtZW50LXdyaXRlcy50c2ApLiBBbiBvYmplY3RcbiAqICAgaHVuZyBvbiBhbiBhcnJheSBFWFBBTkRPIGlzIHRoZW4gbGVmdCB1bmZyb3plbiwgYW5kIHVuc2VlbiBieSB7QGxpbmsgc2VydmVSZWNvcmR9IOKAlCB0aGUgY29tbWl0XG4gKiAgIGxvZydzIG5hbWVkIGhvbGUgKGBFdmVudExvZyDCtyByZWNvcmRgOyBhbiBhcnJheSBleHBhbmRvIGlzIG91dCBvZiBjb250cmFjdCBmb3Igc3RhdGUpLlxuICovXG5leHBvcnQgdHlwZSBBcnJheVdhbGsgPSAnZXZlcnkta2V5JyB8ICdpbmRpY2VzJztcblxuLyoqXG4gKiBGcmVlemVzIGBvYmpgIGFuZCBldmVyeSBvYmplY3QgcmVhY2hhYmxlIHRocm91Z2ggaXRzIG93biBwcm9wZXJ0aWVzLCBhbmQgcmV0dXJucyBgb2JqYC5cbiAqXG4gKiAtIEFuIG9iamVjdCB0aGF0IGlzIEFMUkVBRFkgZnJvemVuIGlzIGxlZnQgYXMgaXQgaXMsIGFuZCBub3QgZGVzY2VuZGVkIOKAlCA5LjMyLjAncyBjb250cmFjdCwga2VwdDpcbiAqICAgYXJncyBtYXkgaG9sZCBhIGNhbGxlcidzIGZyb3plbiBvYmplY3Qgd2l0aCBsaXZlIHBhcnRzIGluc2lkZSAoYSBjbGFzcyBpbnN0YW5jZSBhIHN0YWdlIGNhbGxzKSxcbiAqICAgYW5kIGZyZWV6aW5nIHBhc3QgaXQgd291bGQgYnJlYWsgdGhlbS4gSXQgaXMgYWxzbyB3aGF0IGVuZHMgYSBjeWNsZS4gVGhlIGNvbW1pdCBsb2cgbmV2ZXIgbWVldHNcbiAqICAgb25lOiBpdHMgcGF5bG9hZHMgYXJlIGZyZXNoIGBzdHJ1Y3R1cmVkQ2xvbmVgcy5cbiAqIC0gQXJyYXlCdWZmZXIgdmlld3MgKHR5cGVkIGFycmF5cywgYERhdGFWaWV3YCkgYXJlIHNraXBwZWQ6IGBPYmplY3QuZnJlZXplYCB0aHJvd3Mgb24gYSBub24tZW1wdHlcbiAqICAgdHlwZWQgYXJyYXksIHNvIGEgYFVpbnQ4QXJyYXlgIGluIHN0YXRlLCBhcmdzIG9yIHRoZSBmb2xkIGJhc2UgdXNlZCB0byBmYWlsIHRoZSBydW4gb3IgdGhlXG4gKiAgIHNuYXBzaG90IGhlcmUuXG4gKiAtIFdoYXQgYE9iamVjdC5mcmVlemVgIGNhbm5vdCByZWFjaCBzdGF5cyBtdXRhYmxlIOKAlCBNYXAgYW5kIFNldCBjb250ZW50cywgYSBEYXRlJ3MgdGltZSwgdGhlXG4gKiAgIGJ5dGVzIGJlaGluZCBhIGJ1ZmZlci4gQSBmcm96ZW4gUmVnRXhwJ3MgYGxhc3RJbmRleGAgaXMgcmVhZC1vbmx5LCBzbyBhIGAvZ2Agb3IgYC95YCByZWdleFxuICogICB0YWtlbiBmcm9tIGEgZnJvemVuIHRyZWUgdGhyb3dzIHdoZW4gYGV4ZWNgIG9yIGByZXBsYWNlYCBhZHZhbmNlIGl0LiBUaGUgY29tbWl0IGxvZyBnb2VzIHRocm91Z2hcbiAqICAge0BsaW5rIGZyZWV6ZVJlY29yZH0gYW5kIHtAbGluayBzZXJ2ZVJlY29yZH0gaW5zdGVhZC5cbiAqIC0gRnVuY3Rpb25zIGFyZSBub3QgZGVzY2VuZGVkICh0aGV5IGFyZSBub3QgdmFsdWVzIHRoZSBlbmdpbmUgc3RvcmVzKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlZXBGcmVlemU8VD4ob2JqOiBULCBhcnJheXM6IEFycmF5V2FsayA9ICdldmVyeS1rZXknKTogVCB7XG4gIGlmIChvYmogIT09IG51bGwgJiYgdHlwZW9mIG9iaiA9PT0gJ29iamVjdCcpIHdhbGtBbmRGcmVlemUob2JqLCBhcnJheXMgPT09ICdpbmRpY2VzJywgZmFsc2UpO1xuICByZXR1cm4gb2JqO1xufVxuXG4vKipcbiAqIENvbnRhaW5lcnMgb2YgYSByZWNvcmQgdGhhdCBob2xkIOKAlCBvbiBzb21lIHBhdGggYmVsb3cgdGhlbSDigJQgYSB2YWx1ZSBmcmVlemluZyBjYW5ub3Qgc2VhbDogYHRydWVgIG9uY2VcbiAqIG1hcHBlZCAodGhlIGNvbnRhaW5lciBpcyBvbiBhbiBvcGVuIHBhdGgpLCBgZmFsc2VgIGZvciBhIHJlY29yZCB7QGxpbmsgZnJlZXplUmVjb3JkfSBmb3VuZCBvcGVuIHdob3NlXG4gKiBwYXRocyBubyBzZXJ2ZSBoYXMgbWFwcGVkIHlldC4gQSBjb250YWluZXIgYWJzZW50IGhlcmUgaXMgc2VhbGVkIHdob2xlLlxuICovXG5jb25zdCBPUEVOID0gbmV3IFdlYWtNYXA8b2JqZWN0LCBib29sZWFuPigpO1xuXG4vKipcbiAqIHtAbGluayBkZWVwRnJlZXplfSBmb3IgYSByZWNvcmQgbWFueSByZWFkZXJzIGFyZSBTRVJWRUQgKGEgY29tbWl0IGJ1bmRsZSwgdGhlIGZvbGQgYmFzZSksIGFuZCB0d28gbW9yZVxuICogdGhpbmdzIG9uIHRoZSBzYW1lIHdhbGs6XG4gKlxuICogICAtIGl0IHJlbWVtYmVycyBUSEFUIHRoZSByZWNvcmQgaG9sZHMgYSB2YWx1ZSBmcmVlemluZyBjYW5ub3Qgc2VhbCDigJQgb25lIGZsYWc7IHRoZSByZWNvcmQncyBmaXJzdFxuICogICAgIHNlcnZlIG1hcHMgV0hFUkUgKHRoZSBjb250YWluZXJzIG9uIHRoZSB3YXkgdG8gZWFjaCBzdWNoIHZhbHVlLCBpdHMgb3BlbiBwYXRocyksIHNvIHRoZSBydW4gcGF5c1xuICogICAgIG5vdGhpbmcgbW9yZSBhbmQge0BsaW5rIHNlcnZlUmVjb3JkfSBjb3BpZXMgdGhvc2UgcGF0aHMgYW5kIG5vdGhpbmcgZWxzZTtcbiAqICAgLSBhIHR5cGVkIGFycmF5IG9yIGBEYXRhVmlld2AgdGhhdCB2aWV3cyBhIFNMSUNFIG9mIGEgYmlnZ2VyIGJ1ZmZlciAoYSBOb2RlIGBCdWZmZXJgIHZpZXdzIGl0c1xuICogICAgIHNoYXJlZCBwb29sKSBpcyByZXBsYWNlZCwgaW4gdGhlIHJlY29yZCwgYnkgYSBjb3B5IG9mIHRoZSBieXRlcyBpdCB2aWV3cyDigJQgdGhlIHJlY29yZCBrZWVwcyB0aGVcbiAqICAgICB2aWV3J3MgYnl0ZXMsIG5ldmVyIHRoZSByZXN0IG9mIHRoZSBidWZmZXIgKGEgcmVzaXphYmxlIG9yIHNoYXJlZCBidWZmZXIgaXMga2VwdCBhcyBpdCBpcykuXG4gKlxuICogQSBwYXJ0IGZyb3plbiBiZWZvcmUgaXMgbm90IGZyb3plbiBwYXN0IChkZWVwRnJlZXplJ3MgY29udHJhY3QpIGJ1dCBpcyBsb29rZWQgdGhyb3VnaCwgc28gYSB2YWx1ZVxuICogZnJlZXppbmcgY2Fubm90IHNlYWwgaW5zaWRlIGl0IHN0aWxsIG9wZW5zIHRoZSByZWNvcmQuIFJldHVybnMgYHJlY29yZGAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmcmVlemVSZWNvcmQ8VCBleHRlbmRzIG9iamVjdD4ocmVjb3JkOiBULCBhcnJheXM6IEFycmF5V2FsayA9ICdldmVyeS1rZXknKTogVCB7XG4gIGlmICghT1BFTi5oYXMocmVjb3JkKSAmJiB3YWxrQW5kRnJlZXplKHJlY29yZCwgYXJyYXlzID09PSAnaW5kaWNlcycsIHRydWUpKSBPUEVOLnNldChyZWNvcmQsIGZhbHNlKTtcbiAgcmV0dXJuIHJlY29yZDtcbn1cblxuLyoqXG4gKiBUaGUgcmVjb3JkIGFzIGEgcmVhZGVyIG1heSBob2xkIGl0IOKAlCBUSEUgc2VydmUtdGltZSBsYXc6IGEgcmVjb3JkIGZyZWV6aW5nIHNlYWxlZCB3aG9sZSBpcyBzZXJ2ZWQgYXNcbiAqIGl0c2VsZiAoc2hhcmVkLCBubyBjb3N0KTsgYW55IG90aGVyIGFzIGEgY29weSBvZiBpdHMgb3BlbiBwYXRocyAoe0BsaW5rIGZyZWV6ZVJlY29yZH0pOiBmcmVzaCBmcm96ZW5cbiAqIGNvbnRhaW5lcnMgZG93biB0byBlYWNoIHZhbHVlIGZyZWV6aW5nIGNhbm5vdCBzZWFsLCBhIGZyZXNoIGNvcHkgb2YgdGhhdCB2YWx1ZSwgYW5kIGV2ZXJ5IG90aGVyIHBhcnRcbiAqIHNoYXJlZCwgZnJvemVuLCBhcyBpdCBpcy4gQSBjb3B5IGlzIHNlcnZlZCB0aGUgc2FtZSB3YXkgYWdhaW4uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXJ2ZVJlY29yZDxUPihyZWNvcmQ6IFQpOiBUIHtcbiAgaWYgKHJlY29yZCA9PT0gbnVsbCB8fCB0eXBlb2YgcmVjb3JkICE9PSAnb2JqZWN0JykgcmV0dXJuIHJlY29yZDtcbiAgY29uc3QgbWFwcGVkID0gT1BFTi5nZXQocmVjb3JkKTtcbiAgaWYgKG1hcHBlZCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gcmVjb3JkO1xuICBpZiAoIW1hcHBlZCkgbWFwT3BlblBhdGhzKHJlY29yZCk7XG4gIHJldHVybiBPUEVOLmdldChyZWNvcmQpID09PSB0cnVlID8gKGNvcHlPcGVuUGF0aHMocmVjb3JkKSBhcyBUKSA6IHJlY29yZDtcbn1cblxuLyoqIEEgdmFsdWUgZnJlZXppbmcgY2Fubm90IHNlYWwg4oCUIGEgdmlldywgb3IgYSBraW5kIGBTRUFMQUJMRWAgc2F5cyBubyB0byAoYSBEYXRlLCBhIE1hcCwgYW4gRXJyb3Ig4oCmKS4gKi9cbmZ1bmN0aW9uIGlzVW5zZWFsYWJsZSh2YWx1ZTogb2JqZWN0KTogYm9vbGVhbiB7XG4gIHJldHVybiBBcnJheUJ1ZmZlci5pc1ZpZXcodmFsdWUpIHx8ICFTRUFMQUJMRVtraW5kT2YodmFsdWUpXTtcbn1cblxuLyoqXG4gKiBGcmVlemUgYHJvb3RgIGFuZCBldmVyeSBjb250YWluZXIgdW5kZXIgaXQsIGl0ZXJhdGl2ZWx5OyBgcmVjb3JkYCBhZGRzIHRoZSBsb29rLXRocm91Z2ggb2YgcGFydHNcbiAqIGZyb3plbiBiZWZvcmUgYW5kIHRoZSBjb21wYWN0aW9uIG9mIHZpZXdzIG92ZXIgYSBzbGljZS4gYHRydWVgIHdoZW4gc29tZXRoaW5nIHVuZGVyIGByb290YCAob3IgYHJvb3RgXG4gKiBpdHNlbGYpIGNhbm5vdCBiZSBzZWFsZWQuXG4gKi9cbmZ1bmN0aW9uIHdhbGtBbmRGcmVlemUocm9vdDogb2JqZWN0LCBpbmRpY2VzOiBib29sZWFuLCByZWNvcmQ6IGJvb2xlYW4pOiBib29sZWFuIHtcbiAgbGV0IG9wZW4gPSBmYWxzZTtcbiAgbGV0IGxvb2tlZFRocm91Z2g6IFNldDxvYmplY3Q+IHwgdW5kZWZpbmVkO1xuICBjb25zdCBzdGFjazogb2JqZWN0W10gPSBbcm9vdF07XG4gIHdoaWxlIChzdGFjay5sZW5ndGggPiAwKSB7XG4gICAgY29uc3Qgbm9kZSA9IHN0YWNrLnBvcCgpITtcbiAgICBpZiAoQXJyYXlCdWZmZXIuaXNWaWV3KG5vZGUpKSB7XG4gICAgICBvcGVuID0gdHJ1ZTsgLy8gaXRzIGJ5dGVzIOKAlCBhbmQgYSBub24tZW1wdHkgb25lIGNhbm5vdCBiZSBmcm96ZW4gYXQgYWxsXG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3QgZnJvemVuQmVmb3JlID0gT2JqZWN0LmlzRnJvemVuKG5vZGUpO1xuICAgIGlmIChmcm96ZW5CZWZvcmUpIHtcbiAgICAgIGlmICghcmVjb3JkIHx8IE9QRU4uaGFzKG5vZGUpKSB7XG4gICAgICAgIG9wZW4gfHw9IHJlY29yZDtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAoKGxvb2tlZFRocm91Z2ggPz89IG5ldyBTZXQoKSkuaGFzKG5vZGUpKSBjb250aW51ZTtcbiAgICAgIGxvb2tlZFRocm91Z2guYWRkKG5vZGUpOyAvLyBhIHBhcnQgZnJvemVuIGJlZm9yZTogbG9va2VkIHRocm91Z2gsIG5ldmVyIGZyb3plbiBwYXN0XG4gICAgfVxuICAgIGlmIChyZWNvcmQgJiYgIW9wZW4gJiYgIVNFQUxBQkxFW2tpbmRPZihub2RlKV0pIG9wZW4gPSB0cnVlO1xuICAgIC8vIENoaWxkcmVuIGZpcnN0LCB3aGlsZSBgbm9kZWAgaXMgc3RpbGwgb3BlbiB0byB0aGUgY29tcGFjdGlvbiBiZWxvdzsgdGhlbiB0aGUgZnJlZXplLlxuICAgIGNvbnN0IGNvbXBhY3RpbmcgPSByZWNvcmQgJiYgIWZyb3plbkJlZm9yZTtcbiAgICBpZiAoaW5kaWNlcyAmJiBBcnJheS5pc0FycmF5KG5vZGUpKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5vZGUubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3QgY2hpbGQ6IHVua25vd24gPSBub2RlW2ldO1xuICAgICAgICBpZiAoY2hpbGQgPT09IG51bGwgfHwgdHlwZW9mIGNoaWxkICE9PSAnb2JqZWN0JykgY29udGludWU7XG4gICAgICAgIHN0YWNrLnB1c2goY29tcGFjdGluZyAmJiBBcnJheUJ1ZmZlci5pc1ZpZXcoY2hpbGQpID8gY29tcGFjdChub2RlLCBpLCBjaGlsZCkgOiBjaGlsZCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG5hbWVzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMobm9kZSk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5hbWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGNoaWxkID0gKG5vZGUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW25hbWVzW2ldXTtcbiAgICAgICAgaWYgKGNoaWxkID09PSBudWxsIHx8IHR5cGVvZiBjaGlsZCAhPT0gJ29iamVjdCcpIGNvbnRpbnVlO1xuICAgICAgICBzdGFjay5wdXNoKGNvbXBhY3RpbmcgJiYgQXJyYXlCdWZmZXIuaXNWaWV3KGNoaWxkKSA/IGNvbXBhY3Qobm9kZSwgbmFtZXNbaV0sIGNoaWxkKSA6IGNoaWxkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCFmcm96ZW5CZWZvcmUpIE9iamVjdC5mcmVlemUobm9kZSk7XG4gIH1cbiAgcmV0dXJuIG9wZW47XG59XG5cbi8qKlxuICogQSB2aWV3IG92ZXIgYSBTTElDRSBvZiBhIGJpZ2dlciBidWZmZXIsIHJlcGxhY2VkIGluIGBjb250YWluZXJgIGJ5IGEgY29weSBvZiB0aGUgYnl0ZXMgaXQgdmlld3NcbiAqICh0aGUgdHlwZSBpdCBpcyDigJQgYSBOb2RlIGBCdWZmZXJgIGNvbWVzIG91dCBhIGBVaW50OEFycmF5YCwgYXMgYSBjbG9uZSBvZiBpdCBkb2VzKS4gQW55dGhpbmcgZWxzZSBpc1xuICogcmV0dXJuZWQgYXMgaXQgaXMuIEEgcmVzaXphYmxlIG9yIHNoYXJlZCBidWZmZXIgaXMga2VwdDogYSBjb3B5IHdvdWxkIGNoYW5nZSB3aGF0IGl0IGlzLlxuICovXG5mdW5jdGlvbiBjb21wYWN0KGNvbnRhaW5lcjogb2JqZWN0LCBrZXk6IHN0cmluZyB8IG51bWJlciwgY2hpbGQ6IEFycmF5QnVmZmVyVmlldyk6IG9iamVjdCB7XG4gIGNvbnN0IGJ1ZmZlciA9IGNoaWxkLmJ1ZmZlciBhcyBBcnJheUJ1ZmZlciAmIHsgcmVzaXphYmxlPzogYm9vbGVhbiB9O1xuICBpZiAoY2hpbGQuYnl0ZU9mZnNldCA9PT0gMCAmJiBjaGlsZC5ieXRlTGVuZ3RoID09PSBidWZmZXIuYnl0ZUxlbmd0aCkgcmV0dXJuIGNoaWxkO1xuICBpZiAoYnVmZmVyLnJlc2l6YWJsZSA9PT0gdHJ1ZSB8fCAhKGJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSkgcmV0dXJuIGNoaWxkO1xuICBjb25zdCBieXRlcyA9IGJ1ZmZlci5zbGljZShjaGlsZC5ieXRlT2Zmc2V0LCBjaGlsZC5ieXRlT2Zmc2V0ICsgY2hpbGQuYnl0ZUxlbmd0aCk7XG4gIGNvbnN0IHRhZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChjaGlsZCkuc2xpY2UoOCwgLTEpO1xuICBjb25zdCBDdG9yID0gKGdsb2JhbFRoaXMgYXMgdW5rbm93biBhcyBSZWNvcmQ8c3RyaW5nLCBuZXcgKGJ1ZmZlcjogQXJyYXlCdWZmZXIpID0+IEFycmF5QnVmZmVyVmlldz4pW3RhZ107XG4gIGlmICh0eXBlb2YgQ3RvciAhPT0gJ2Z1bmN0aW9uJykgcmV0dXJuIGNoaWxkO1xuICBjb25zdCBjb3B5ID0gbmV3IEN0b3IoYnl0ZXMpO1xuICB0cnkge1xuICAgIChjb250YWluZXIgYXMgUmVjb3JkPHN0cmluZyB8IG51bWJlciwgdW5rbm93bj4pW2tleV0gPSBjb3B5O1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gY2hpbGQ7IC8vIGEgcHJvcGVydHkgdGhlIHJlY29yZCBkb2VzIG5vdCBsZXQgYmUgcmVwbGFjZWQgKGEgaGFuZC1idWlsdCBidW5kbGUpXG4gIH1cbiAgcmV0dXJuIGNvcHk7XG59XG5cbi8qKlxuICogTWFwIHRoZSBvcGVuIHBhdGhzIG9mIGByb290YCDigJQgbWFyayBldmVyeSBjb250YWluZXIgdGhhdCByZWFjaGVzIGEgdmFsdWUgZnJlZXppbmcgY2Fubm90IHNlYWwsIHNvIGFcbiAqIHNlcnZlIGNvcGllcyBleGFjdGx5IHRob3NlIChEQUdzIGFuZCBjeWNsZXMgaW5jbHVkZWQ6IHRoZSBtYXJrcyBydW4gVVAgdGhlIHJldmVyc2UgZWRnZXMgZnJvbSBlYWNoXG4gKiBzdWNoIHZhbHVlKS4gUnVucyBvbmNlIHBlciBvcGVuIHJlY29yZCwgYXQgaXRzIGZpcnN0IHNlcnZlLiBBIG5vZGUncyBmaXJzdCBob2xkZXIgaXMga2VwdCBpbiBvbmUgbWFwO1xuICogYW55IG90aGVyIGhvbGRlciAoYSBzaGFyZWQgcGFydCwgYSBjeWNsZSkgaW4gYSBzZWNvbmQsIG1hZGUgb25seSB3aGVuIHRoZXJlIGlzIG9uZS5cbiAqL1xuZnVuY3Rpb24gbWFwT3BlblBhdGhzKHJvb3Q6IG9iamVjdCk6IHZvaWQge1xuICBjb25zdCBob2xkZXIgPSBuZXcgTWFwPG9iamVjdCwgb2JqZWN0PigpO1xuICBsZXQgbW9yZUhvbGRlcnM6IE1hcDxvYmplY3QsIG9iamVjdFtdPiB8IHVuZGVmaW5lZDtcbiAgY29uc3QgbGVhdmVzOiBvYmplY3RbXSA9IFtdO1xuICBjb25zdCBzdGFjazogb2JqZWN0W10gPSBbcm9vdF07XG4gIHdoaWxlIChzdGFjay5sZW5ndGggPiAwKSB7XG4gICAgY29uc3Qgbm9kZSA9IHN0YWNrLnBvcCgpITtcbiAgICBpZiAoaXNVbnNlYWxhYmxlKG5vZGUpKSB7XG4gICAgICBsZWF2ZXMucHVzaChub2RlKTsgLy8gYSBsZWFmOiBpdHMgY29udGVudHMgYXJlIGNvcGllZCB3aXRoIGl0XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3QgbmFtZXMgPSBPYmplY3Qua2V5cyhub2RlKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5hbWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjaGlsZCA9IChub2RlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVtuYW1lc1tpXV07XG4gICAgICBpZiAoY2hpbGQgPT09IG51bGwgfHwgdHlwZW9mIGNoaWxkICE9PSAnb2JqZWN0JykgY29udGludWU7XG4gICAgICBpZiAoY2hpbGQgIT09IHJvb3QgJiYgIWhvbGRlci5oYXMoY2hpbGQpKSB7XG4gICAgICAgIGhvbGRlci5zZXQoY2hpbGQsIG5vZGUpO1xuICAgICAgICBzdGFjay5wdXNoKGNoaWxkKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBtb3JlID0gKG1vcmVIb2xkZXJzID8/PSBuZXcgTWFwKCkpLmdldChjaGlsZCk7XG4gICAgICBpZiAobW9yZSA9PT0gdW5kZWZpbmVkKSBtb3JlSG9sZGVycy5zZXQoY2hpbGQsIFtub2RlXSk7XG4gICAgICBlbHNlIG1vcmUucHVzaChub2RlKTtcbiAgICB9XG4gIH1cbiAgLy8gTWFya2VkIGluIFRISVMgbWFwLCBub3QgYnkgYW4gZWFybGllciBvbmU6IGEgcGFydCBhbm90aGVyIHJlY29yZCBhbHJlYWR5IG1hcHBlZCBzdGlsbCBvcGVuc1xuICAvLyBldmVyeSBjb250YWluZXIgb2YgdGhpcyByZWNvcmQgb24gdGhlIHdheSB0byBpdC5cbiAgY29uc3QgbWFya2VkID0gbmV3IFNldDxvYmplY3Q+KCk7XG4gIGNvbnN0IHVwOiBvYmplY3RbXSA9IFtdO1xuICBjb25zdCBob2xkZXJzT2YgPSAobm9kZTogb2JqZWN0KTogdm9pZCA9PiB7XG4gICAgY29uc3QgZmlyc3QgPSBob2xkZXIuZ2V0KG5vZGUpO1xuICAgIGlmIChmaXJzdCAhPT0gdW5kZWZpbmVkKSB1cC5wdXNoKGZpcnN0KTtcbiAgICBjb25zdCBtb3JlID0gbW9yZUhvbGRlcnM/LmdldChub2RlKTtcbiAgICAvLyBPbmUgcHVzaCBwZXIgaG9sZGVyOiBhIHNwcmVhZCBwYXNzZXMgZXZlcnkgaG9sZGVyIGFzIGEgY2FsbCBhcmd1bWVudCwgYW5kIG9uZSBvYmplY3QgaGVsZCBieVxuICAgIC8vIDEyMCwwMDAgY29udGFpbmVycyBvdmVyZmxvd2VkIHRoZSBzdGFjay5cbiAgICBpZiAobW9yZSAhPT0gdW5kZWZpbmVkKSBmb3IgKGxldCBpID0gMDsgaSA8IG1vcmUubGVuZ3RoOyBpKyspIHVwLnB1c2gobW9yZVtpXSk7XG4gIH07XG4gIGZvciAoY29uc3QgbGVhZiBvZiBsZWF2ZXMpIHtcbiAgICBpZiAobGVhZiA9PT0gcm9vdCkgbWFya2VkLmFkZChyb290KTtcbiAgICBob2xkZXJzT2YobGVhZik7XG4gIH1cbiAgd2hpbGUgKHVwLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBub2RlID0gdXAucG9wKCkhO1xuICAgIGlmIChtYXJrZWQuaGFzKG5vZGUpKSBjb250aW51ZTtcbiAgICBtYXJrZWQuYWRkKG5vZGUpO1xuICAgIGhvbGRlcnNPZihub2RlKTtcbiAgfVxuICAvLyBPbmx5IG5vdywgdGhlIHdhbGsgZG9uZSwgZG9lcyB0aGUgcmVjb3JkJ3MgZmxhZyBnaXZlIHdheSB0byBpdHMgbWFwOiBhIG1hcHBpbmcgdGhhdCB0aHJvd3MgbGVhdmVzXG4gIC8vIHRoZSByZWNvcmQgZmxhZ2dlZCwgc28gdGhlIG5leHQgc2VydmUgbWFwcyBhZ2FpbiDigJQgaXQgbmV2ZXIgaGFuZHMgb3V0IHRoZSByZWNvcmQgaXRzZWxmLlxuICBpZiAoIW1hcmtlZC5oYXMocm9vdCkpIE9QRU4uZGVsZXRlKHJvb3QpO1xuICBmb3IgKGNvbnN0IG5vZGUgb2YgbWFya2VkKSBPUEVOLnNldChub2RlLCB0cnVlKTtcbn1cblxuLyoqXG4gKiBUaGUgc2VydmVkIGNvcHkgb2YgYW4gb3BlbiByZWNvcmQ6IGl0cyBvcGVuIGNvbnRhaW5lcnMgY29waWVkIChmcmVzaCwgdGhlbiBmcm96ZW4sIGFuZCB0aGVtc2VsdmVzXG4gKiBvcGVuIOKAlCBhIGNvcHkgaXMgc2VydmVkIGJ5IGNvcHkgYWdhaW4pLCBlYWNoIHZhbHVlIGZyZWV6aW5nIGNhbm5vdCBzZWFsIGNvcGllZCwgZXZlcnkgc2VhbGVkIHBhcnRcbiAqIHNoYXJlZC4gSXRlcmF0aXZlOyBvbmUgY29weSBwZXIgb3JpZ2luYWwsIHNvIGNvbnRhaW5lcnMgc2hhcmVkIG9yIGN5Y2xpYyBzdGF5IHNoYXJlZCBpbiB0aGUgY29weS4gVGhlXG4gKiB2YWx1ZXMgZnJlZXppbmcgY2Fubm90IHNlYWwgYXJlIGNvcGllZCBPTkUgQlkgT05FOiB0d28gb2YgdGhlbSB0aGF0IHNoYXJlIGEgcGFydCAoYW4gYEFycmF5QnVmZmVyYFxuICogYW5kIGEgdmlldyBvZiBpdCwgYW4gZXJyb3Igd2hvc2UgYGNhdXNlYCBpcyBhbm90aGVyIGtleSdzIERhdGUpIGNvbWUgb3V0IGFzIHNlcGFyYXRlIGNvcGllcyDigJQgZXF1YWxcbiAqIHZhbHVlcywgdGhlIHNoYXJpbmcgYmV0d2VlbiB0aGVtIG5vdCBrZXB0LlxuICovXG5mdW5jdGlvbiBjb3B5T3BlblBhdGhzKHJvb3Q6IG9iamVjdCk6IG9iamVjdCB7XG4gIGNvbnN0IGNvcGllcyA9IG5ldyBNYXA8b2JqZWN0LCBvYmplY3Q+KCk7XG4gIGNvbnN0IHNoZWxsczogb2JqZWN0W10gPSBbXTtcbiAgY29uc3QgY29weU9mID0gKHZhbHVlOiBvYmplY3QsIHBlbmRpbmc6IG9iamVjdFtdKTogb2JqZWN0ID0+IHtcbiAgICBjb25zdCBkb25lID0gY29waWVzLmdldCh2YWx1ZSk7XG4gICAgaWYgKGRvbmUgIT09IHVuZGVmaW5lZCkgcmV0dXJuIGRvbmU7XG4gICAgbGV0IGNvcHk6IG9iamVjdDtcbiAgICBpZiAoaXNVbnNlYWxhYmxlKHZhbHVlKSkge1xuICAgICAgY29weSA9IGNvcHlMZWFmKHZhbHVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29weSA9IEFycmF5LmlzQXJyYXkodmFsdWUpID8gbmV3IEFycmF5KHZhbHVlLmxlbmd0aCkgOiB7fTtcbiAgICAgIHNoZWxscy5wdXNoKGNvcHkpO1xuICAgICAgcGVuZGluZy5wdXNoKHZhbHVlKTtcbiAgICB9XG4gICAgY29waWVzLnNldCh2YWx1ZSwgY29weSk7XG4gICAgcmV0dXJuIGNvcHk7XG4gIH07XG4gIGNvbnN0IHBlbmRpbmc6IG9iamVjdFtdID0gW107XG4gIGNvbnN0IG91dCA9IGNvcHlPZihyb290LCBwZW5kaW5nKTtcbiAgd2hpbGUgKHBlbmRpbmcubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IG5vZGUgPSBwZW5kaW5nLnBvcCgpITtcbiAgICBjb25zdCBjb3B5ID0gY29waWVzLmdldChub2RlKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBmb3IgKGNvbnN0IG5hbWUgb2YgT2JqZWN0LmtleXMobm9kZSkpIHtcbiAgICAgIGNvbnN0IGNoaWxkID0gKG5vZGUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW25hbWVdO1xuICAgICAgcHV0T3duKFxuICAgICAgICBjb3B5LFxuICAgICAgICBuYW1lLFxuICAgICAgICBjaGlsZCAhPT0gbnVsbCAmJiB0eXBlb2YgY2hpbGQgPT09ICdvYmplY3QnICYmIChPUEVOLmhhcyhjaGlsZCkgfHwgaXNVbnNlYWxhYmxlKGNoaWxkKSlcbiAgICAgICAgICA/IGNvcHlPZihjaGlsZCwgcGVuZGluZylcbiAgICAgICAgICA6IGNoaWxkLFxuICAgICAgKTtcbiAgICB9XG4gIH1cbiAgZm9yIChjb25zdCBzaGVsbCBvZiBzaGVsbHMpIHtcbiAgICBPYmplY3QuZnJlZXplKHNoZWxsKTtcbiAgICBPUEVOLnNldChzaGVsbCwgdHJ1ZSk7XG4gIH1cbiAgLy8gQSBsZWFmIGNvcHkgaXMgdGhlIHJlYWRlcidzIG93bjsgZnJvemVuIHdoZXJlIGZyZWV6aW5nIHJlYWNoZXMsIGFzIHRoZSByZWNvcmQncyBwYXJ0cyBhcmUuXG4gIGZvciAoY29uc3QgY29weSBvZiBjb3BpZXMudmFsdWVzKCkpIGlmICghQXJyYXlCdWZmZXIuaXNWaWV3KGNvcHkpKSBPYmplY3QuZnJlZXplKGNvcHkpO1xuICByZXR1cm4gb3V0O1xufVxuXG4vKipcbiAqIGB0YXJnZXRbbmFtZV0gPSB2YWx1ZWAsIGFzIGFuIE9XTiBkYXRhIHByb3BlcnR5LiBBIGtleSB0aGUgc2hlbGwgb25seSBpbmhlcml0cyDigJQgYW4gb3duIGBcIl9fcHJvdG9fX1wiYFxuICogb2YgdGhlIHJlY29yZCAoYEpTT04ucGFyc2VgIG1ha2VzIG9uZSkg4oCUIHdvdWxkIGNhbGwgdGhlIGluaGVyaXRlZCBzZXR0ZXIgYW5kIHJlLXBhcmVudCB0aGUgY29weTsgaXQgaXNcbiAqIGRlZmluZWQgYXMgZGF0YSBpbnN0ZWFkLCBhcyBgbWVtb3J5L21lcmdlLnRzIMK3IG1lcmdlR3VhcmRlZGAga2VlcHMgaXQuXG4gKi9cbmZ1bmN0aW9uIHB1dE93bih0YXJnZXQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBuYW1lOiBzdHJpbmcsIHZhbHVlOiB1bmtub3duKTogdm9pZCB7XG4gIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRhcmdldCwgbmFtZSkgJiYgUmVmbGVjdC5oYXModGFyZ2V0LCBuYW1lKSkge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIG5hbWUsIHsgdmFsdWUsIGVudW1lcmFibGU6IHRydWUsIHdyaXRhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUgfSk7XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0W25hbWVdID0gdmFsdWU7XG4gIH1cbn1cblxuLyoqIEEgZnJlc2ggY29weSBvZiBhIHZhbHVlIGZyZWV6aW5nIGNhbm5vdCBzZWFsLiBPbmUgdGhlIGNsb25lIHJlZnVzZXMgKGhhbmQtYnVpbHQpIGlzIHNlcnZlZCBhcyBpdCBpcy4gKi9cbmZ1bmN0aW9uIGNvcHlMZWFmKHZhbHVlOiBvYmplY3QpOiBvYmplY3Qge1xuICBpZiAoa2luZE9mKHZhbHVlKSA9PT0gJ2RhdGUnKSByZXR1cm4gbmV3IERhdGUoRGF0ZS5wcm90b3R5cGUuZ2V0VGltZS5jYWxsKHZhbHVlKSk7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHN0cnVjdHVyZWRDbG9uZSh2YWx1ZSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxufVxuIl19
|