@mooloo-ai/eutaxy 0.1.0 → 0.2.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/README.md +1 -1
- package/dist/aws.d.mts +15464 -0
- package/dist/aws.d.mts.map +1 -0
- package/dist/aws.mjs +24057 -0
- package/dist/aws.mjs.map +1 -0
- package/dist/bin.mjs +2 -2
- package/dist/checksum-DhS6ofSm.mjs +6049 -0
- package/dist/checksum-DhS6ofSm.mjs.map +1 -0
- package/dist/cli-DnPkIL8h.mjs +2 -0
- package/dist/cli.mjs +2 -2
- package/dist/cloudflare.d.mts +17 -1
- package/dist/cloudflare.d.mts.map +1 -1
- package/dist/cloudflare.mjs +41 -9
- package/dist/cloudflare.mjs.map +1 -1
- package/dist/es5-DtZuPEgt.mjs +1721 -0
- package/dist/es5-DtZuPEgt.mjs.map +1 -0
- package/dist/event-streams-BANyO9xt.mjs +801 -0
- package/dist/event-streams-BANyO9xt.mjs.map +1 -0
- package/dist/explore-C5fDFOoY.d.mts +63 -0
- package/dist/explore-C5fDFOoY.d.mts.map +1 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -2
- package/dist/{explore-BB77_V0x.d.mts → platform-CGVkTa16.d.mts} +30 -65
- package/dist/platform-CGVkTa16.d.mts.map +1 -0
- package/dist/rolldown-runtime-C1I3wEg2.mjs +43 -0
- package/dist/{src-dP-0Apun.mjs → src-B66we2mG.mjs} +3 -2
- package/dist/{src-dP-0Apun.mjs.map → src-B66we2mG.mjs.map} +1 -1
- package/dist/{src-Bef00JwK.mjs → src-BP6Iqc_9.mjs} +3 -88
- package/dist/src-BP6Iqc_9.mjs.map +1 -0
- package/dist/{src-Dn3Lm5Us.mjs → src-BrCsF5RZ.mjs} +223 -28
- package/dist/src-BrCsF5RZ.mjs.map +1 -0
- package/dist/src-s6uYyC0B.mjs +89 -0
- package/dist/src-s6uYyC0B.mjs.map +1 -0
- package/dist/verdict-evEM5Gxx.mjs +12 -0
- package/dist/verdict-evEM5Gxx.mjs.map +1 -0
- package/package.json +20 -3
- package/dist/cli-DTuDOgGM.mjs +0 -2
- package/dist/explore-BB77_V0x.d.mts.map +0 -1
- package/dist/src-Bef00JwK.mjs.map +0 -1
- package/dist/src-Dn3Lm5Us.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"src-BP6Iqc_9.mjs","names":[],"sources":["../../report/src/regression.ts","../../report/src/render.ts"],"sourcesContent":["/**\n * The Vitest regression emitter. Given a violation, produce a test file that\n * replays its shrunk schedule on the restricted scenario. By default the\n * test expects the invariants to hold, so it fails while the bug exists and\n * passes once it is fixed. With `expect: \"violates\"` it asserts the recorded\n * violation instead, which is how Eutaxy's own corpus exercises the emitter.\n *\n * The emitter knows nothing about any platform: the caller supplies the\n * import lines and the expression that builds the platform.\n */\n\nimport { canonicalJson, type JsonValue, type Violated } from \"@eutaxy/core\";\n\nexport interface RegressionTestOptions {\n /** Import lines for the scenario, the platform's dependencies, and anything the platform expression needs. */\n readonly imports: readonly string[];\n /** An expression evaluating to the `Platform` (may reference the imports). */\n readonly platform: string;\n /** An expression evaluating to the `ScenarioSpec`. */\n readonly scenario: string;\n /** Module that exports `replay`, `restrictSpec` and `checkInvariants`; the public facade by default. */\n readonly engineModule?: string;\n readonly expect?: \"holds\" | \"violates\";\n}\n\nexport function emitRegressionTest(verdict: Violated, options: RegressionTestOptions): string {\n const engineModule = options.engineModule ?? \"@mooloo-ai/eutaxy\";\n const mode = options.expect ?? \"holds\";\n const schedule = canonicalJson(verdict.schedule as unknown as JsonValue);\n const kept = canonicalJson([...verdict.keptEvents]);\n const keys = canonicalJson([...verdict.violation.keys]);\n const title =\n mode === \"holds\"\n ? `${verdict.scenario}: ${verdict.violation.invariant} holds on the recorded schedule`\n : `${verdict.scenario}: ${verdict.violation.invariant} is still violated on the recorded schedule`;\n const assertion =\n mode === \"holds\"\n ? ` expect(violations.map((v) => \\`\\${v.invariant}: \\${v.message}\\`)).toEqual([]);`\n : ` expect(violations.map((v) => [v.invariant, v.keys])).toContainEqual([${JSON.stringify(verdict.violation.invariant)}, ${keys}]);`;\n const lines = [\n \"// Generated by Eutaxy. Replays a recorded violation; regenerate rather than edit.\",\n `// Scenario ${verdict.scenario}, seed ${String(verdict.seed)}: ${verdict.violation.message}`,\n `import { checkInvariants, replay, restrictSpec } from ${JSON.stringify(engineModule)};`,\n ...options.imports,\n 'import { expect, test } from \"vitest\";',\n \"\",\n `const schedule = ${schedule} as const;`,\n `const keptEvents = ${kept} as const;`,\n \"\",\n `test(${JSON.stringify(title)}, async () => {`,\n ` const platform = ${options.platform};`,\n ` const spec = restrictSpec(platform, ${options.scenario}, keptEvents);`,\n \" const log = await replay(spec, platform, schedule);\",\n \" const violations = checkInvariants(log, spec.invariants);\",\n assertion,\n \"});\",\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n","/**\n * Rendering verdicts: a text form for people and a versioned JSON form for\n * CI and coding agents. Both are pure functions over the verdict data.\n */\n\nimport { canonicalJson, type EffectLog, type JsonValue, type ScenarioVerdict } from \"@eutaxy/core\";\n\nexport const reportSchemaVersion = 1;\n\n/** The JSON report: one object, canonical, with a schema version at the top. */\nexport function renderJson(verdict: ScenarioVerdict): string {\n return canonicalJson({\n schemaVersion: reportSchemaVersion,\n generator: \"eutaxy\",\n verdict: verdict as unknown as JsonValue,\n });\n}\n\nfunction clip(s: string, max: number): string {\n return s.length <= max ? s : `${s.slice(0, max - 1)}…`;\n}\n\nfunction pad(s: string, width: number): string {\n return s.length >= width ? s : s + \" \".repeat(width - s.length);\n}\n\n/** The trace as a fixed-width table; evidence rows are marked with `*`. */\nexport function renderTrace(log: EffectLog, evidence: readonly number[] = []): string {\n const rows = log.entries.map((e) => [\n evidence.includes(e.seq) ? \"*\" : \" \",\n String(e.seq),\n e.invocation,\n e.kind,\n e.target,\n e.op,\n clip(canonicalJson(e.payload), 72),\n ]);\n const header = [\" \", \"seq\", \"invocation\", \"kind\", \"target\", \"op\", \"payload\"];\n const widths = header.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => (r[i] as string).length)),\n );\n const line = (cells: readonly string[]) =>\n cells\n .map((c, i) => (i === cells.length - 1 ? c : pad(c, widths[i] as number)))\n .join(\" \")\n .trimEnd();\n return [line(header), ...rows.map(line)].join(\"\\n\");\n}\n\n/** A readable report: verdict, what it rests on, and for a violation the schedule and trace. */\nexport function renderText(verdict: ScenarioVerdict): string {\n const out: string[] = [];\n const r = verdict.reached;\n out.push(`${verdict.kind} ${verdict.scenario} (seed ${String(verdict.seed)})`);\n switch (verdict.kind) {\n case \"VIOLATED\": {\n out.push(\"\");\n out.push(\n `Invariant ${verdict.violation.invariant} is violated: ${verdict.violation.message}`,\n );\n out.push(`Keys: ${verdict.violation.keys.join(\", \")}`);\n out.push(\"\");\n out.push(\n `Schedule (run seed ${verdict.schedule.seed}), events kept: ${verdict.keptEvents.join(\", \")}`,\n );\n if (verdict.schedule.faults.length === 0) out.push(\" no injected faults\");\n for (const f of verdict.schedule.faults) {\n out.push(` ${f.fault} at ${f.invocation} effect #${f.ordinal} (${f.target} ${f.op})`);\n }\n out.push(\n `Shrunk: ${verdict.shrunk.eventsRemoved} event(s) and ${verdict.shrunk.faultsRemoved} fault(s) removed in ${verdict.shrunk.runs} run(s)`,\n );\n out.push(\"\");\n out.push(\"Trace:\");\n out.push(renderTrace(verdict.trace, verdict.violation.evidence));\n break;\n }\n case \"BOUNDED\": {\n const b = verdict.bounds;\n out.push(\"\");\n out.push(\"No violation found within the stated bounds. This is not a proof.\");\n out.push(\n `Bounds: faults per run ≤ ${b.maxFaultsPerRun}, redeliveries ≤ ${b.maxRedeliveries}, concurrent invocations ≤ ${b.maxConcurrentInvocations}, budget ${b.budgetMs} ms`,\n );\n break;\n }\n case \"UNSUPPORTED\": {\n out.push(\"\");\n out.push(`Eutaxy could not decide this scenario (${verdict.cause}): ${verdict.reason}`);\n break;\n }\n }\n out.push(\"\");\n out.push(\n `Explored: ${r.runs} run(s), ${r.effectPoints} effect point(s), ${r.faultsInjected} fault(s) injected, ${r.elapsedMs} ms`,\n );\n out.push(\"Assumptions:\");\n for (const a of verdict.assumptions) out.push(` - ${a}`);\n return out.join(\"\\n\");\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as canonicalJson, n as digestLog, r as emptyLog, t as appendEffect } from "./src-s6uYyC0B.mjs";
|
|
2
2
|
// packages/core/src/prng.ts
|
|
3
3
|
function rotl(x, k) {
|
|
4
4
|
return (x << k | x >>> 32 - k) >>> 0;
|
|
@@ -311,6 +311,7 @@ function validateScenario(spec) {
|
|
|
311
311
|
const errors = [];
|
|
312
312
|
if (spec.version !== 1) errors.push(`version must be 1, got ${String(spec.version)}`);
|
|
313
313
|
if (!spec.name.trim()) errors.push("name must not be empty");
|
|
314
|
+
if (spec.platform !== void 0 && !spec.platform) errors.push("platform must not be empty when given");
|
|
314
315
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(spec.name)) errors.push(`name must be lowercase letters, digits and dashes: ${JSON.stringify(spec.name)}`);
|
|
315
316
|
if (!spec.worker.entry) errors.push("worker.entry must not be empty");
|
|
316
317
|
if (!spec.worker.config) errors.push("worker.config must not be empty");
|
|
@@ -327,8 +328,13 @@ function validateScenario(spec) {
|
|
|
327
328
|
}
|
|
328
329
|
const ext = /* @__PURE__ */ new Set();
|
|
329
330
|
for (const e of spec.externals) {
|
|
331
|
+
if (!e.name) errors.push("every external needs a name");
|
|
330
332
|
if (ext.has(e.name)) errors.push(`duplicate external ${JSON.stringify(e.name)}`);
|
|
331
333
|
ext.add(e.name);
|
|
334
|
+
if (!e.host) errors.push(`external ${JSON.stringify(e.name)} needs a host`);
|
|
335
|
+
(e.responses ?? []).forEach((r, i) => {
|
|
336
|
+
if (!(Number.isInteger(r.status) && r.status >= 100 && r.status <= 599)) errors.push(`external ${JSON.stringify(e.name)} responses[${i}].status must be an HTTP status`);
|
|
337
|
+
});
|
|
332
338
|
}
|
|
333
339
|
for (const k of [
|
|
334
340
|
"maxFaultsPerRun",
|
|
@@ -365,15 +371,6 @@ function shrinkCandidates(state) {
|
|
|
365
371
|
});
|
|
366
372
|
return out;
|
|
367
373
|
}
|
|
368
|
-
// packages/core/src/verdict.ts
|
|
369
|
-
/** One line per verdict, for error messages; full rendering lives in `report`. */
|
|
370
|
-
function describeVerdict(v) {
|
|
371
|
-
switch (v.kind) {
|
|
372
|
-
case "VIOLATED": return `VIOLATED ${v.scenario}: ${v.violation.message} (seed ${v.schedule.seed}, ${v.reached.runs} run(s))`;
|
|
373
|
-
case "BOUNDED": return `BOUNDED ${v.scenario}: no violation in ${v.reached.runs} run(s), ${v.reached.effectPoints} effect point(s), ${v.reached.faultsInjected} fault(s)`;
|
|
374
|
-
case "UNSUPPORTED": return `UNSUPPORTED ${v.scenario}: ${v.cause}: ${v.reason}`;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
374
|
// packages/engine/src/clock.ts
|
|
378
375
|
/**
|
|
379
376
|
* The virtual clock and the globals patch. Within a run, Date, Math.random,
|
|
@@ -387,6 +384,13 @@ function describeVerdict(v) {
|
|
|
387
384
|
/** 2026-01-01T00:00:00.000Z. Every run starts here. */
|
|
388
385
|
const virtualEpoch = Date.UTC(2026, 0, 1);
|
|
389
386
|
const realSetTimeout = globalThis.setTimeout.bind(globalThis);
|
|
387
|
+
const realSetInterval = globalThis.setInterval.bind(globalThis);
|
|
388
|
+
const realClearTimeout = globalThis.clearTimeout.bind(globalThis);
|
|
389
|
+
const realClearInterval = globalThis.clearInterval.bind(globalThis);
|
|
390
|
+
const libraryScope = (() => {
|
|
391
|
+
const mod = typeof process !== "undefined" ? process?.getBuiltinModule?.("node:async_hooks") : void 0;
|
|
392
|
+
return mod?.AsyncLocalStorage ? new mod.AsyncLocalStorage() : null;
|
|
393
|
+
})();
|
|
390
394
|
var VirtualClock = class {
|
|
391
395
|
time = virtualEpoch;
|
|
392
396
|
timers = [];
|
|
@@ -421,6 +425,10 @@ var VirtualClock = class {
|
|
|
421
425
|
clear(id) {
|
|
422
426
|
this.timers = this.timers.filter((t) => t.id !== id);
|
|
423
427
|
}
|
|
428
|
+
/** Whether this clock issued the handle (and the timer is still pending). */
|
|
429
|
+
owns(id) {
|
|
430
|
+
return typeof id === "number" && this.timers.some((t) => t.id === id);
|
|
431
|
+
}
|
|
424
432
|
pendingTimers() {
|
|
425
433
|
return this.timers.length;
|
|
426
434
|
}
|
|
@@ -509,10 +517,17 @@ function patchGlobals(seed) {
|
|
|
509
517
|
Object.defineProperty(VirtualDate, "name", { value: "Date" });
|
|
510
518
|
define(g, "Date", VirtualDate);
|
|
511
519
|
define(Math, "random", () => random.float());
|
|
512
|
-
|
|
513
|
-
define(g, "
|
|
514
|
-
define(g, "
|
|
515
|
-
define(g, "
|
|
520
|
+
const inLibrary = () => libraryScope?.getStore() === true;
|
|
521
|
+
define(g, "setTimeout", (cb, ms, ...args) => inLibrary() ? realSetTimeout(cb, ms, ...args) : clock.setTimeout(cb, ms, ...args));
|
|
522
|
+
define(g, "setInterval", (cb, ms, ...args) => inLibrary() ? realSetInterval(cb, ms, ...args) : clock.setInterval(cb, ms, ...args));
|
|
523
|
+
define(g, "clearTimeout", (id) => {
|
|
524
|
+
if (clock.owns(id)) clock.clear(id);
|
|
525
|
+
else realClearTimeout(id);
|
|
526
|
+
});
|
|
527
|
+
define(g, "clearInterval", (id) => {
|
|
528
|
+
if (clock.owns(id)) clock.clear(id);
|
|
529
|
+
else realClearInterval(id);
|
|
530
|
+
});
|
|
516
531
|
const perf = g["performance"];
|
|
517
532
|
if (perf && typeof perf === "object") define(perf, "now", () => clock.now() - virtualEpoch);
|
|
518
533
|
const cryptoObj = g["crypto"];
|
|
@@ -537,6 +552,9 @@ function patchGlobals(seed) {
|
|
|
537
552
|
return {
|
|
538
553
|
clock,
|
|
539
554
|
random,
|
|
555
|
+
libraryIo(perform) {
|
|
556
|
+
return libraryScope ? libraryScope.run(true, perform) : perform();
|
|
557
|
+
},
|
|
540
558
|
restore() {
|
|
541
559
|
if (restored) return;
|
|
542
560
|
restored = true;
|
|
@@ -582,6 +600,166 @@ async function settleOn(promise, ctx) {
|
|
|
582
600
|
return new Promise(() => {});
|
|
583
601
|
}
|
|
584
602
|
}
|
|
603
|
+
// packages/engine/src/fetch.ts
|
|
604
|
+
const FAULTS = [
|
|
605
|
+
"crash_before",
|
|
606
|
+
"crash_after",
|
|
607
|
+
"ambiguous",
|
|
608
|
+
"error"
|
|
609
|
+
];
|
|
610
|
+
/** Match a host against an exact host or a "*.suffix" pattern. */
|
|
611
|
+
function hostMatches(pattern, host) {
|
|
612
|
+
if (pattern.startsWith("*.")) {
|
|
613
|
+
const suffix = pattern.slice(1);
|
|
614
|
+
return host.endsWith(suffix) && host.length > suffix.length;
|
|
615
|
+
}
|
|
616
|
+
return pattern === host;
|
|
617
|
+
}
|
|
618
|
+
function findExternal(externals, host) {
|
|
619
|
+
return externals.find((e) => hostMatches(e.host, host));
|
|
620
|
+
}
|
|
621
|
+
function findResponse(external, method, path) {
|
|
622
|
+
if (!external.responses) return null;
|
|
623
|
+
return external.responses.find((r) => {
|
|
624
|
+
if (r.method && r.method.toUpperCase() !== method) return false;
|
|
625
|
+
if (r.path === void 0) return true;
|
|
626
|
+
return r.path.endsWith("*") ? path.startsWith(r.path.slice(0, -1)) : r.path === path;
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
const REDIRECTS = /* @__PURE__ */ new Set([
|
|
630
|
+
301,
|
|
631
|
+
302,
|
|
632
|
+
303,
|
|
633
|
+
307,
|
|
634
|
+
308
|
|
635
|
+
]);
|
|
636
|
+
function replyOf(r) {
|
|
637
|
+
if (r === null) return {
|
|
638
|
+
status: 200,
|
|
639
|
+
headers: {},
|
|
640
|
+
body: ""
|
|
641
|
+
};
|
|
642
|
+
const json = r.body !== void 0 && typeof r.body !== "string";
|
|
643
|
+
const headers = {};
|
|
644
|
+
for (const [name, value] of Object.entries(r.headers ?? {})) headers[name.toLowerCase()] = value;
|
|
645
|
+
if (json && !("content-type" in headers)) headers["content-type"] = "application/json";
|
|
646
|
+
const body = r.body === void 0 ? "" : json ? JSON.stringify(r.body) : r.body;
|
|
647
|
+
return {
|
|
648
|
+
status: r.status,
|
|
649
|
+
headers,
|
|
650
|
+
body
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function toResponse(reply) {
|
|
654
|
+
return new Response(reply.body === "" ? null : reply.body, {
|
|
655
|
+
status: reply.status,
|
|
656
|
+
headers: reply.headers
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
function parseBody(text) {
|
|
660
|
+
if (text === "") return null;
|
|
661
|
+
try {
|
|
662
|
+
return JSON.parse(text);
|
|
663
|
+
} catch {
|
|
664
|
+
return text;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Build the replacement `fetch`. With `hooks`, every request is an effect
|
|
669
|
+
* point recorded as `Fetch:<external>` with the method as op; the result
|
|
670
|
+
* summary carries `status`, `effective` and the dedupe key.
|
|
671
|
+
*/
|
|
672
|
+
function createScriptedFetch(externals, hooks, unsupported, afterRequest = () => {}) {
|
|
673
|
+
const dedupe = /* @__PURE__ */ new Map();
|
|
674
|
+
const scripted = (async (input, init) => {
|
|
675
|
+
const request = new Request(input, init);
|
|
676
|
+
const url = new URL(request.url);
|
|
677
|
+
const method = request.method.toUpperCase();
|
|
678
|
+
const external = findExternal(externals, url.host);
|
|
679
|
+
if (!external) {
|
|
680
|
+
unsupported(`fetch to undeclared host ${url.host}; declare it as an external in the scenario`);
|
|
681
|
+
throw new TypeError(`fetch failed: ${url.host} is not a declared external`);
|
|
682
|
+
}
|
|
683
|
+
const headers = {};
|
|
684
|
+
request.headers.forEach((value, name) => {
|
|
685
|
+
headers[name.toLowerCase()] = value;
|
|
686
|
+
});
|
|
687
|
+
const dedupeHeader = external.guarantees.dedupeBy?.toLowerCase();
|
|
688
|
+
const dedupeKey = dedupeHeader ? headers[dedupeHeader] ?? null : null;
|
|
689
|
+
const body = parseBody(await request.text());
|
|
690
|
+
const args = {
|
|
691
|
+
url: request.url,
|
|
692
|
+
method,
|
|
693
|
+
headers,
|
|
694
|
+
body,
|
|
695
|
+
dedupeKey
|
|
696
|
+
};
|
|
697
|
+
const perform = async () => {
|
|
698
|
+
const memo = dedupeKey === null ? null : `${external.name}\u0000${dedupeKey}`;
|
|
699
|
+
if (memo !== null) {
|
|
700
|
+
const earlier = dedupe.get(memo);
|
|
701
|
+
if (earlier) return {
|
|
702
|
+
reply: earlier,
|
|
703
|
+
effective: false
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
const script = findResponse(external, method, url.pathname);
|
|
707
|
+
if (script === void 0) {
|
|
708
|
+
unsupported(`no scripted response in external ${external.name} for ${method} ${url.pathname}`);
|
|
709
|
+
throw new TypeError(`fetch failed: no scripted response for ${method} ${url.pathname}`);
|
|
710
|
+
}
|
|
711
|
+
const reply = replyOf(script);
|
|
712
|
+
if (REDIRECTS.has(reply.status) && request.redirect !== "manual") {
|
|
713
|
+
unsupported(`external ${external.name} answers ${method} ${url.pathname} with a ${reply.status} redirect; script the final reply or fetch with redirect: "manual"`);
|
|
714
|
+
throw new TypeError(`fetch failed: redirects are not modelled (${reply.status} from ${url.host})`);
|
|
715
|
+
}
|
|
716
|
+
if (memo !== null) dedupe.set(memo, reply);
|
|
717
|
+
return {
|
|
718
|
+
reply,
|
|
719
|
+
effective: true
|
|
720
|
+
};
|
|
721
|
+
};
|
|
722
|
+
if (!hooks) {
|
|
723
|
+
const { reply } = await perform();
|
|
724
|
+
afterRequest();
|
|
725
|
+
return toResponse(reply);
|
|
726
|
+
}
|
|
727
|
+
const { reply } = await hooks.hooks.effect({
|
|
728
|
+
invocation: hooks.invocation(),
|
|
729
|
+
target: `Fetch:${external.name}`,
|
|
730
|
+
op: method,
|
|
731
|
+
args,
|
|
732
|
+
allowed: FAULTS
|
|
733
|
+
}, perform, (r) => ({
|
|
734
|
+
status: r.reply.status,
|
|
735
|
+
effective: r.effective,
|
|
736
|
+
dedupeKey
|
|
737
|
+
}));
|
|
738
|
+
return toResponse(reply);
|
|
739
|
+
});
|
|
740
|
+
return {
|
|
741
|
+
fetch: scripted,
|
|
742
|
+
dedupe
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
/** Replace the global `fetch` for a run; returns the function that restores it. */
|
|
746
|
+
function installScriptedFetch(externals, hooks, unsupported, afterRequest) {
|
|
747
|
+
const g = globalThis;
|
|
748
|
+
const saved = Object.getOwnPropertyDescriptor(globalThis, "fetch");
|
|
749
|
+
const { fetch: scripted } = createScriptedFetch(externals, hooks, unsupported, afterRequest);
|
|
750
|
+
Object.defineProperty(globalThis, "fetch", {
|
|
751
|
+
value: scripted,
|
|
752
|
+
configurable: true,
|
|
753
|
+
writable: true
|
|
754
|
+
});
|
|
755
|
+
let restored = false;
|
|
756
|
+
return () => {
|
|
757
|
+
if (restored) return;
|
|
758
|
+
restored = true;
|
|
759
|
+
if (saved) Object.defineProperty(globalThis, "fetch", saved);
|
|
760
|
+
else delete g.fetch;
|
|
761
|
+
};
|
|
762
|
+
}
|
|
585
763
|
// packages/engine/src/run.ts
|
|
586
764
|
/**
|
|
587
765
|
* One run of a scenario: the effect log being built, the fault decisions
|
|
@@ -647,6 +825,9 @@ var Run = class {
|
|
|
647
825
|
reasons = [];
|
|
648
826
|
inFlight = 0;
|
|
649
827
|
patched = null;
|
|
828
|
+
restoreFetch = null;
|
|
829
|
+
/** The invocation whose code is running (one at a time); outbound fetches are attributed to it. */
|
|
830
|
+
current = "";
|
|
650
831
|
options;
|
|
651
832
|
constructor(options) {
|
|
652
833
|
this.options = options;
|
|
@@ -671,11 +852,17 @@ var Run = class {
|
|
|
671
852
|
get unsupportedReasons() {
|
|
672
853
|
return this.reasons;
|
|
673
854
|
}
|
|
674
|
-
/** Replace the nondeterministic globals for this run. Call `uninstall` in a finally. */
|
|
675
|
-
install() {
|
|
855
|
+
/** Replace the nondeterministic globals and `fetch` for this run. Call `uninstall` in a finally. */
|
|
856
|
+
install(externals = []) {
|
|
676
857
|
if (!this.patched) this.patched = patchGlobals(this.options.schedule.seed);
|
|
858
|
+
if (!this.restoreFetch) this.restoreFetch = installScriptedFetch(externals, {
|
|
859
|
+
hooks: this,
|
|
860
|
+
invocation: () => this.current
|
|
861
|
+
}, (reason) => this.unsupported(reason));
|
|
677
862
|
}
|
|
678
863
|
uninstall() {
|
|
864
|
+
this.restoreFetch?.();
|
|
865
|
+
this.restoreFetch = null;
|
|
679
866
|
this.patched?.restore();
|
|
680
867
|
this.patched = null;
|
|
681
868
|
}
|
|
@@ -692,6 +879,7 @@ var Run = class {
|
|
|
692
879
|
const inv = new InvocationState(id, () => this.patched?.clock.cancelOwner(id));
|
|
693
880
|
this.invocations.set(id, inv);
|
|
694
881
|
if (this.patched) this.patched.clock.owner = id;
|
|
882
|
+
this.current = id;
|
|
695
883
|
return inv;
|
|
696
884
|
}
|
|
697
885
|
invocation(id) {
|
|
@@ -757,7 +945,7 @@ var Run = class {
|
|
|
757
945
|
let value;
|
|
758
946
|
this.inFlight++;
|
|
759
947
|
try {
|
|
760
|
-
value = await perform();
|
|
948
|
+
value = await (this.patched ? this.patched.libraryIo(perform) : perform());
|
|
761
949
|
} catch (err) {
|
|
762
950
|
this.record(point, "result", {
|
|
763
951
|
args: point.args,
|
|
@@ -849,6 +1037,7 @@ var Run = class {
|
|
|
849
1037
|
const inv = this.invocation(invocation);
|
|
850
1038
|
const patched = this.patched;
|
|
851
1039
|
if (patched) patched.clock.owner = invocation;
|
|
1040
|
+
this.current = invocation;
|
|
852
1041
|
if (!patched) return Promise.race([promise, inv.crashed.then(() => new Promise(() => {}))]);
|
|
853
1042
|
return settleOn(promise, {
|
|
854
1043
|
clock: patched.clock,
|
|
@@ -941,22 +1130,28 @@ const engineAssumptions = [
|
|
|
941
1130
|
"one invocation at a time (maxConcurrentInvocations = 1)",
|
|
942
1131
|
"Date, Math.random, crypto.randomUUID, crypto.getRandomValues, performance.now and timers are virtualised per run from the seed; time starts at 2026-01-01T00:00:00Z and advances 1 ms per effect and to each timer's due time",
|
|
943
1132
|
"timers fire only while the invocation is idle (no effect in flight), in due order; an invocation waiting on something outside Eutaxy makes the run UNSUPPORTED",
|
|
944
|
-
"
|
|
1133
|
+
"while an effect performs real I/O the real timer functions are in place for that I/O, so user code that schedules a timer concurrently with an effect gets a real one",
|
|
1134
|
+
"module-level state cannot be reset between runs; before BOUNDED the first runs are replayed in reverse order and any difference makes the run UNSUPPORTED (module_state_leak)",
|
|
1135
|
+
"outbound fetch never reaches the network: requests are answered from the scenario's declared externals, an external's dedupeBy guarantee is honoured by replaying the first response per key, and an undeclared host makes the run UNSUPPORTED"
|
|
945
1136
|
];
|
|
946
1137
|
/** Run the scenario once under the given run's fault decisions and return its log. */
|
|
947
1138
|
async function runOnce(spec, platform, run) {
|
|
948
|
-
|
|
1139
|
+
await platform.reset(spec);
|
|
1140
|
+
run.install(spec.externals);
|
|
949
1141
|
try {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1142
|
+
try {
|
|
1143
|
+
const pending = [...platform.initialEvents(spec)];
|
|
1144
|
+
while (pending.length > 0) {
|
|
1145
|
+
const event = pending.shift();
|
|
1146
|
+
const result = await platform.deliver(event, run, spec);
|
|
1147
|
+
pending.push(...result.followUps);
|
|
1148
|
+
}
|
|
1149
|
+
} finally {
|
|
1150
|
+
run.uninstall();
|
|
956
1151
|
}
|
|
957
1152
|
await platform.finish?.(spec, run);
|
|
958
1153
|
} finally {
|
|
959
|
-
|
|
1154
|
+
await platform.cleanup?.(spec);
|
|
960
1155
|
}
|
|
961
1156
|
return run.log;
|
|
962
1157
|
}
|
|
@@ -1086,6 +1281,6 @@ async function explore(spec, platform, options) {
|
|
|
1086
1281
|
reached: done()
|
|
1087
1282
|
};
|
|
1088
1283
|
}
|
|
1089
|
-
export { Run as a,
|
|
1284
|
+
export { Run as a, realTick as c, validateScenario as d, checkInvariant as f, CrashSignal as i, settleOn as l, getPath as m, replay as n, installScriptedFetch as o, checkInvariants as p, restrictSpec as r, patchGlobals as s, explore as t, defaultBounds as u };
|
|
1090
1285
|
|
|
1091
|
-
//# sourceMappingURL=src-
|
|
1286
|
+
//# sourceMappingURL=src-BrCsF5RZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"src-BrCsF5RZ.mjs","names":[],"sources":["../../core/src/prng.ts","../../core/src/faults.ts","../../core/src/invariants.ts","../../core/src/scenario.ts","../../core/src/shrink.ts","../../engine/src/clock.ts","../../engine/src/fetch.ts","../../engine/src/run.ts","../../engine/src/shrink.ts","../../engine/src/explore.ts"],"sourcesContent":["/**\n * A pure, seedable pseudo-random generator (xoshiro128**).\n *\n * State is an immutable tuple of four 32-bit words. Every operation returns a\n * value and the next state; nothing is mutated, so a schedule can be replayed\n * from any state and two explorations can never interfere with each other.\n * Not cryptographic.\n */\n\nexport type PrngState = readonly [number, number, number, number];\n\nfunction rotl(x: number, k: number): number {\n return ((x << k) | (x >>> (32 - k))) >>> 0;\n}\n\n/** splitmix32: expands a 32-bit seed into well-mixed words for seeding. */\nfunction splitmix32(seed: number): () => number {\n let a = seed >>> 0;\n return () => {\n a = (a + 0x9e3779b9) >>> 0;\n let t = a;\n t = Math.imul(t ^ (t >>> 16), 0x21f0aaad);\n t = Math.imul(t ^ (t >>> 15), 0x735a2d97);\n return (t ^ (t >>> 15)) >>> 0;\n };\n}\n\n/** FNV-1a over UTF-16 code units, so string seeds are stable across runtimes. */\nfunction hashString(s: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\n/** Derive an initial state from a number (taken modulo 2^32) or a string. */\nexport function seedPrng(seed: number | string): PrngState {\n const word = typeof seed === \"string\" ? hashString(seed) : seed >>> 0;\n const next = splitmix32(word);\n const s: [number, number, number, number] = [next(), next(), next(), next()];\n if (s[0] === 0 && s[1] === 0 && s[2] === 0 && s[3] === 0) {\n s[0] = 1; // xoshiro must never hold the all-zero state\n }\n return s;\n}\n\n/** Next 32-bit unsigned integer and the state that follows it. */\nexport function nextU32(state: PrngState): readonly [number, PrngState] {\n const [s0, s1, s2, s3] = state;\n const result = Math.imul(rotl(Math.imul(s1, 5) >>> 0, 7), 9) >>> 0;\n const t = (s1 << 9) >>> 0;\n let n2 = (s2 ^ s0) >>> 0;\n let n3 = (s3 ^ s1) >>> 0;\n const n1 = (s1 ^ n2) >>> 0;\n const n0 = (s0 ^ n3) >>> 0;\n n2 = (n2 ^ t) >>> 0;\n n3 = rotl(n3, 11);\n return [result, [n0, n1, n2, n3]];\n}\n\n/** Next float in [0, 1) with 24 bits of precision. */\nexport function nextFloat(state: PrngState): readonly [number, PrngState] {\n const [u, next] = nextU32(state);\n return [(u >>> 8) * 2 ** -24, next];\n}\n\n/**\n * Next integer in [0, bound). Uses rejection sampling, so every value is\n * equally likely; a bound of 1 always yields 0 without consuming state.\n */\nexport function nextInt(state: PrngState, bound: number): readonly [number, PrngState] {\n if (!Number.isInteger(bound) || bound < 1 || bound > 0x1_0000_0000) {\n throw new RangeError(`nextInt bound must be an integer in [1, 2^32], got ${bound}`);\n }\n if (bound === 1) return [0, state];\n const limit = 0x1_0000_0000 - (0x1_0000_0000 % bound);\n let s = state;\n for (;;) {\n const [u, next] = nextU32(s);\n s = next;\n if (u < limit) return [u % bound, s];\n }\n}\n\n/**\n * Split one generator into two independent streams: the first element is the\n * continuation of the parent, the second a freshly seeded child.\n */\nexport function fork(state: PrngState): readonly [PrngState, PrngState] {\n const [a, s1] = nextU32(state);\n const [b, s2] = nextU32(s1);\n const next = splitmix32((a ^ Math.imul(b, 0x9e3779b1)) >>> 0);\n const child: [number, number, number, number] = [next(), next(), next(), next()];\n if (child[0] === 0 && child[1] === 0 && child[2] === 0 && child[3] === 0) child[0] = 1;\n return [s2, child];\n}\n","/**\n * The fault model and the schedule. A schedule is the complete, replayable\n * record of which fault was injected at which effect point in one run.\n */\n\nimport { nextFloat, nextInt, type PrngState } from \"./prng.ts\";\n\n/**\n * `cut_off` is a crash that happens after a response or acknowledgement was\n * already sent, so only background work (ctx.waitUntil) is lost; platforms\n * offer it at the point where that work would start.\n */\nexport type FaultKind = \"crash_before\" | \"crash_after\" | \"ambiguous\" | \"error\" | \"cut_off\";\n\nexport const allFaults: readonly FaultKind[] = [\n \"crash_before\",\n \"crash_after\",\n \"ambiguous\",\n \"error\",\n \"cut_off\",\n];\n\nexport interface FaultDecision {\n /** The invocation the effect belongs to, e.g. \"msg-1#2\". */\n readonly invocation: string;\n /** Position of the effect within that invocation, from 0. Stable when other invocations are removed. */\n readonly ordinal: number;\n readonly fault: FaultKind;\n /** What the effect was, for people reading the schedule. */\n readonly target: string;\n readonly op: string;\n}\n\nexport interface Schedule {\n /** The per-run seed the decisions were drawn from. */\n readonly seed: number;\n readonly faults: readonly FaultDecision[];\n}\n\nexport interface FaultPolicy {\n readonly maxFaultsPerRun: number;\n /** Probability of injecting at an eligible effect point, in [0, 1]. */\n readonly faultProbability: number;\n}\n\n/**\n * Decide whether to inject a fault at an effect point during exploration.\n * Pure: the same state and inputs always give the same decision. The PRNG is\n * only consumed when a fault is possible, so adding an ineligible point does\n * not perturb later decisions.\n */\nexport function decideFault(\n state: PrngState,\n allowed: readonly FaultKind[],\n faultsSoFar: number,\n policy: FaultPolicy,\n): readonly [FaultKind | null, PrngState] {\n if (allowed.length === 0 || faultsSoFar >= policy.maxFaultsPerRun) return [null, state];\n const [p, s1] = nextFloat(state);\n if (p >= policy.faultProbability) return [null, s1];\n const [i, s2] = nextInt(s1, allowed.length);\n return [allowed[i] ?? null, s2];\n}\n","/**\n * Invariants are plain data describing a property of the effect log; checkers\n * are pure functions from (log, invariant) to a violation or null. The\n * library starts with what the first planted bug needs and grows from there.\n */\n\nimport { canonicalJson, type JsonValue } from \"./canonical-json.ts\";\nimport type { EffectKind, EffectLog, EffectRecord } from \"./effect-log.ts\";\n\n/** Picks effect records by target, op, kind and payload fields. */\nexport interface EffectSelector {\n readonly target: string;\n readonly op?: string;\n readonly kind?: EffectKind;\n /** Dot paths into the payload that must equal the given values. */\n readonly where?: { readonly [path: string]: JsonValue };\n /** Dot paths into the payload whose numeric value must be at least the given bound. */\n readonly atLeast?: { readonly [path: string]: number };\n}\n\n/** No two selected effects share the same key. Catches duplicate writes. */\nexport interface AtMostOncePerKey {\n readonly kind: \"atMostOncePerKey\";\n readonly name: string;\n readonly effect: EffectSelector;\n /** Dot path into the payload that identifies the key. */\n readonly key: string;\n}\n\n/** Every expected key appears in at least one selected effect. Catches lost work. */\nexport interface AtLeastOnce {\n readonly kind: \"atLeastOnce\";\n readonly name: string;\n readonly effect: EffectSelector;\n readonly key: string;\n readonly expected: readonly JsonValue[];\n /** Set when `expected` was derived from the drive's message bodies, so it can be re-derived when messages are removed. */\n readonly perMessage?: { readonly bodyKey: string };\n}\n\n/** Re-derive `expected` for per-message invariants from the bodies that remain. */\nexport function recomputePerMessageExpected(\n invariants: readonly Invariant[],\n bodies: readonly JsonValue[],\n): readonly Invariant[] {\n return invariants.map((inv) => {\n if (inv.kind !== \"atLeastOnce\" || !inv.perMessage) return inv;\n const bodyKey = inv.perMessage.bodyKey;\n const expected: JsonValue[] = [];\n for (const b of bodies) {\n const v = getPath(b, bodyKey);\n if (v !== undefined) expected.push(v);\n }\n return { ...inv, expected };\n });\n}\n\n/** A condition on one column of a row. */\nexport type RowCondition =\n | { readonly column: string; readonly op: \"eq\" | \"neq\"; readonly value: JsonValue }\n | { readonly column: string; readonly op: \"gt\" | \"gte\" | \"lt\" | \"lte\"; readonly value: number }\n | { readonly column: string; readonly op: \"in\"; readonly value: readonly JsonValue[] }\n | { readonly column: string; readonly op: \"notNull\" };\n\n/** Rows of a table in the last snapshot of a target, optionally filtered. */\nexport interface StateQuery {\n /** The snapshot target, e.g. \"D1:DB\". */\n readonly target: string;\n readonly table: string;\n readonly where?: readonly RowCondition[];\n}\n\n/** Every row the query returns satisfies all of `holds`. */\nexport interface EveryRow {\n readonly kind: \"everyRow\";\n readonly name: string;\n readonly query: StateQuery;\n readonly holds: readonly RowCondition[];\n}\n\n/**\n * For every selected effect, a row exists whose `column` equals the effect's\n * key. Ties what the shell did to what the state says, e.g. \"every acked\n * message has its payment row\".\n */\nexport interface Implies {\n readonly kind: \"implies\";\n readonly name: string;\n readonly when: EffectSelector;\n /** Dot path into the effect payload that yields the key. */\n readonly key: string;\n readonly state: StateQuery;\n readonly column: string;\n}\n\nexport type Invariant = AtMostOncePerKey | AtLeastOnce | EveryRow | Implies;\n\nexport type Row = { readonly [column: string]: JsonValue };\n\n/** The tables in the last snapshot recorded for a target, or undefined when none was. */\nexport function lastSnapshot(\n log: EffectLog,\n target: string,\n): { readonly [table: string]: readonly Row[] } | undefined {\n for (let i = log.entries.length - 1; i >= 0; i--) {\n const e = log.entries[i] as EffectRecord;\n if (e.kind === \"snapshot\" && e.target === target) {\n const tables = getPath(e.payload, \"tables\");\n if (tables && typeof tables === \"object\" && !Array.isArray(tables)) {\n return tables as { readonly [table: string]: readonly Row[] };\n }\n return {};\n }\n }\n return undefined;\n}\n\nexport function rowMatches(row: Row, condition: RowCondition): boolean {\n const v = row[condition.column];\n switch (condition.op) {\n case \"eq\":\n return v !== undefined && jsonEqual(v, condition.value);\n case \"neq\":\n return v === undefined || !jsonEqual(v, condition.value);\n case \"gt\":\n return typeof v === \"number\" && v > condition.value;\n case \"gte\":\n return typeof v === \"number\" && v >= condition.value;\n case \"lt\":\n return typeof v === \"number\" && v < condition.value;\n case \"lte\":\n return typeof v === \"number\" && v <= condition.value;\n case \"in\":\n return v !== undefined && condition.value.some((c) => jsonEqual(v, c));\n case \"notNull\":\n return v !== undefined && v !== null;\n }\n}\n\n/** Rows a state query selects from the log's last snapshot; undefined when there is no snapshot. */\nexport function queryRows(log: EffectLog, query: StateQuery): readonly Row[] | undefined {\n const tables = lastSnapshot(log, query.target);\n if (!tables) return undefined;\n const rows = tables[query.table] ?? [];\n const where = query.where ?? [];\n return rows.filter((r) => where.every((c) => rowMatches(r, c)));\n}\n\nfunction snapshotSeq(log: EffectLog, target: string): number[] {\n let last: number | undefined;\n for (const e of log.entries) if (e.kind === \"snapshot\" && e.target === target) last = e.seq;\n return last === undefined ? [] : [last];\n}\n\nexport interface Violation {\n readonly invariant: string;\n readonly message: string;\n /** The keys involved, in canonical JSON, so two violations can be compared across runs. */\n readonly keys: readonly string[];\n /** Sequence numbers of the effects that witness the violation. */\n readonly evidence: readonly number[];\n}\n\n/** True when two violations are of the same invariant for the same keys, whatever the traces. */\nexport function sameViolation(a: Violation, b: Violation): boolean {\n return (\n a.invariant === b.invariant &&\n a.keys.length === b.keys.length &&\n a.keys.every((k, i) => k === b.keys[i])\n );\n}\n\n/** Read a dot path such as \"args.params.0\" out of JSON data; undefined when absent. */\nexport function getPath(value: JsonValue, path: string): JsonValue | undefined {\n let cur: JsonValue | undefined = value;\n if (path === \"\") return cur;\n for (const part of path.split(\".\")) {\n if (cur === null || typeof cur !== \"object\") return undefined;\n if (Array.isArray(cur)) {\n const i = Number(part);\n if (!Number.isInteger(i) || i < 0) return undefined;\n cur = cur[i];\n } else {\n cur = (cur as { readonly [k: string]: JsonValue })[part];\n }\n if (cur === undefined) return undefined;\n }\n return cur;\n}\n\nfunction jsonEqual(a: JsonValue | undefined, b: JsonValue): boolean {\n if (a === undefined) return false;\n if (a === b) return true;\n if (a === null || b === null || typeof a !== \"object\" || typeof b !== \"object\") return false;\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((x, i) => jsonEqual(x, b[i] as JsonValue));\n }\n const ao = a as { readonly [k: string]: JsonValue };\n const bo = b as { readonly [k: string]: JsonValue };\n const ak = Object.keys(ao).sort();\n const bk = Object.keys(bo).sort();\n return (\n ak.length === bk.length &&\n ak.every((k, i) => k === bk[i] && jsonEqual(ao[k], bo[k] as JsonValue))\n );\n}\n\nexport function matches(record: EffectRecord, sel: EffectSelector): boolean {\n if (record.target !== sel.target) return false;\n if (sel.op !== undefined && record.op !== sel.op) return false;\n if (sel.kind !== undefined && record.kind !== sel.kind) return false;\n if (sel.where) {\n for (const [path, want] of Object.entries(sel.where)) {\n if (!jsonEqual(getPath(record.payload, path), want)) return false;\n }\n }\n if (sel.atLeast) {\n for (const [path, min] of Object.entries(sel.atLeast)) {\n const v = getPath(record.payload, path);\n if (typeof v !== \"number\" || v < min) return false;\n }\n }\n return true;\n}\n\nexport function selectEffects(log: EffectLog, sel: EffectSelector): readonly EffectRecord[] {\n return log.entries.filter((e) => matches(e, sel));\n}\n\n/** Canonical form of a key, so equal JSON values compare equal whatever their key order. */\nfunction keyOf(record: EffectRecord, path: string): string | undefined {\n const v = getPath(record.payload, path);\n return v === undefined ? undefined : canonicalJson(v);\n}\n\nexport function checkInvariant(log: EffectLog, inv: Invariant): Violation | null {\n switch (inv.kind) {\n case \"everyRow\":\n return checkEveryRow(log, inv);\n case \"implies\":\n return checkImplies(log, inv);\n case \"atMostOncePerKey\": {\n const seen = new Map<string, number>();\n for (const e of selectEffects(log, inv.effect)) {\n const k = keyOf(e, inv.key);\n if (k === undefined) continue;\n const first = seen.get(k);\n if (first !== undefined) {\n return {\n invariant: inv.name,\n message: `${inv.effect.target} ${inv.effect.op ?? \"*\"} happened twice for key ${k} (seq ${first} and ${e.seq})`,\n keys: [k],\n evidence: [first, e.seq],\n };\n }\n seen.set(k, e.seq);\n }\n return null;\n }\n case \"atLeastOnce\": {\n const present = new Set<string>();\n const selected = selectEffects(log, inv.effect);\n for (const e of selected) {\n const k = keyOf(e, inv.key);\n if (k !== undefined) present.add(k);\n }\n const missing = inv.expected.map((v) => canonicalJson(v)).filter((k) => !present.has(k));\n if (missing.length === 0) return null;\n return {\n invariant: inv.name,\n message: `${inv.effect.target} ${inv.effect.op ?? \"*\"} never happened for key(s) ${missing.join(\", \")}`,\n keys: missing,\n evidence: selected.map((e) => e.seq),\n };\n }\n }\n}\n\nfunction checkEveryRow(log: EffectLog, inv: EveryRow): Violation | null {\n const rows = queryRows(log, inv.query);\n if (rows === undefined) {\n return {\n invariant: inv.name,\n message: `no snapshot of ${inv.query.target} was recorded`,\n keys: [],\n evidence: [],\n };\n }\n const failing = rows.filter((r) => !inv.holds.every((c) => rowMatches(r, c)));\n if (failing.length === 0) return null;\n const keys = failing.map((r) => canonicalJson(r));\n const shown = keys.slice(0, 3).join(\", \") + (failing.length > 3 ? \", …\" : \"\");\n return {\n invariant: inv.name,\n message: `${failing.length} row(s) of ${inv.query.table} in ${inv.query.target} violate the condition: ${shown}`,\n keys,\n evidence: snapshotSeq(log, inv.query.target),\n };\n}\n\nfunction checkImplies(log: EffectLog, inv: Implies): Violation | null {\n const rows = queryRows(log, inv.state);\n if (rows === undefined) {\n return {\n invariant: inv.name,\n message: `no snapshot of ${inv.state.target} was recorded`,\n keys: [],\n evidence: [],\n };\n }\n const present = new Set<string>();\n for (const r of rows) {\n const v = r[inv.column];\n if (v !== undefined) present.add(canonicalJson(v));\n }\n const missing: string[] = [];\n const evidence: number[] = [];\n for (const e of selectEffects(log, inv.when)) {\n const k = keyOf(e, inv.key);\n if (k === undefined || present.has(k)) continue;\n if (!missing.includes(k)) missing.push(k);\n evidence.push(e.seq);\n }\n if (missing.length === 0) return null;\n return {\n invariant: inv.name,\n message: `${inv.when.target} ${inv.when.op ?? \"*\"} happened for key(s) ${missing.join(\", \")} but ${inv.state.table}.${inv.column} in ${inv.state.target} has no such row`,\n keys: missing,\n evidence,\n };\n}\n\nexport function checkInvariants(\n log: EffectLog,\n invariants: readonly Invariant[],\n): readonly Violation[] {\n const out: Violation[] = [];\n for (const inv of invariants) {\n const v = checkInvariant(log, inv);\n if (v) out.push(v);\n }\n return out;\n}\n","/**\n * The scenario spec: everything Eutaxy needs to run one scenario, as plain\n * data. The platform-neutral parts are typed here; what a platform needs to\n * drive the Worker and set up its state travels as `PlatformData`, which only\n * that platform's package knows how to build and interpret.\n */\n\nimport type { JsonValue } from \"./canonical-json.ts\";\nimport type { Invariant } from \"./invariants.ts\";\n\n/** Opaque, JSON-shaped data owned by a platform package. `kind` names its shape. */\nexport interface PlatformData {\n readonly kind: string;\n readonly [key: string]: JsonValue;\n}\n\n/** Where the Worker under test lives, relative to the scenario file. */\nexport interface WorkerRef {\n readonly entry: string;\n readonly config: string;\n}\n\n/** A scripted reply from an external: the first matching entry answers a request. */\nexport interface ScriptedResponse {\n /** HTTP method to match; any when absent. */\n readonly method?: string;\n /** URL path to match exactly, or a prefix when it ends with \"*\"; any when absent. */\n readonly path?: string;\n readonly status: number;\n readonly headers?: { readonly [name: string]: string };\n /** JSON body (sent as application/json) or a string body. */\n readonly body?: JsonValue;\n}\n\n/**\n * An external service the Worker talks to, what it promises, and how it\n * answers. Requests never reach the network: they are answered from\n * `responses`, and an undeclared host makes the run UNSUPPORTED.\n */\nexport interface ExternalDecl {\n readonly name: string;\n /** Host to match exactly, or a suffix pattern such as \"*.example.com\". */\n readonly host: string;\n readonly guarantees: {\n /**\n * Header whose value makes repeated requests idempotent: a request\n * repeating an earlier one's key gets the earlier response and is\n * recorded as not effective.\n */\n readonly dedupeBy?: string;\n };\n /** Omitted: every request gets 200 with an empty body. Present but unmatched: the run is UNSUPPORTED. */\n readonly responses?: readonly ScriptedResponse[];\n}\n\n/** Exploration bounds. Every verdict reports the bounds actually reached. */\nexport interface Bounds {\n readonly maxFaultsPerRun: number;\n readonly maxRedeliveries: number;\n readonly maxConcurrentInvocations: number;\n readonly budgetMs: number;\n}\n\nexport interface ScenarioSpec {\n readonly version: 1;\n readonly name: string;\n /** Which platform package built and runs this scenario, e.g. \"cloudflare\" or \"aws\". Absent means cloudflare. */\n readonly platform?: string;\n readonly worker: WorkerRef;\n /** How the scenario drives the Worker (which events, with what payloads). */\n readonly drive: PlatformData;\n /** State to establish before each run, in order. */\n readonly setup: readonly PlatformData[];\n readonly externals: readonly ExternalDecl[];\n readonly invariants: readonly Invariant[];\n readonly bounds: Bounds;\n}\n\nexport const defaultBounds: Bounds = {\n maxFaultsPerRun: 1,\n maxRedeliveries: 2,\n maxConcurrentInvocations: 1,\n budgetMs: 2000,\n};\n\nfunction isPositiveInt(n: unknown): n is number {\n return typeof n === \"number\" && Number.isInteger(n) && n > 0;\n}\n\n/** Every reason a spec is not usable; empty when it is. */\nexport function validateScenario(spec: ScenarioSpec): readonly string[] {\n const errors: string[] = [];\n if (spec.version !== 1) errors.push(`version must be 1, got ${String(spec.version)}`);\n if (!spec.name.trim()) errors.push(\"name must not be empty\");\n if (spec.platform !== undefined && !spec.platform)\n errors.push(\"platform must not be empty when given\");\n if (!/^[a-z0-9][a-z0-9-]*$/.test(spec.name))\n errors.push(`name must be lowercase letters, digits and dashes: ${JSON.stringify(spec.name)}`);\n if (!spec.worker.entry) errors.push(\"worker.entry must not be empty\");\n if (!spec.worker.config) errors.push(\"worker.config must not be empty\");\n if (!spec.drive.kind) errors.push(\"drive.kind must not be empty\");\n spec.setup.forEach((s, i) => {\n if (!s.kind) errors.push(`setup[${i}].kind must not be empty`);\n });\n if (spec.invariants.length === 0) errors.push(\"at least one invariant is required\");\n const names = new Set<string>();\n for (const inv of spec.invariants) {\n if (!inv.name) errors.push(\"every invariant needs a name\");\n else if (names.has(inv.name))\n errors.push(`duplicate invariant name ${JSON.stringify(inv.name)}`);\n names.add(inv.name);\n }\n const ext = new Set<string>();\n for (const e of spec.externals) {\n if (!e.name) errors.push(\"every external needs a name\");\n if (ext.has(e.name)) errors.push(`duplicate external ${JSON.stringify(e.name)}`);\n ext.add(e.name);\n if (!e.host) errors.push(`external ${JSON.stringify(e.name)} needs a host`);\n (e.responses ?? []).forEach((r, i) => {\n if (!(Number.isInteger(r.status) && r.status >= 100 && r.status <= 599)) {\n errors.push(\n `external ${JSON.stringify(e.name)} responses[${i}].status must be an HTTP status`,\n );\n }\n });\n }\n for (const k of [\n \"maxFaultsPerRun\",\n \"maxRedeliveries\",\n \"maxConcurrentInvocations\",\n \"budgetMs\",\n ] as const) {\n if (k === \"maxFaultsPerRun\" || k === \"maxRedeliveries\") {\n const v = spec.bounds[k];\n if (!(Number.isInteger(v) && v >= 0))\n errors.push(`bounds.${k} must be a non-negative integer`);\n } else if (!isPositiveInt(spec.bounds[k]))\n errors.push(`bounds.${k} must be a positive integer`);\n }\n return errors;\n}\n","/**\n * Shrinking, the pure part: given a violating schedule and the ids of the\n * events that drove it, the candidates to try next, smallest change first.\n * The engine replays each candidate and keeps it when the same invariant is\n * still violated for the same keys.\n */\n\nimport type { Schedule } from \"./faults.ts\";\n\nexport interface ShrinkState {\n readonly schedule: Schedule;\n readonly keepIds: readonly string[];\n}\n\n/** One-step candidates: each single fault removed, then each single event removed. */\nexport function shrinkCandidates(state: ShrinkState): readonly ShrinkState[] {\n const out: ShrinkState[] = [];\n state.schedule.faults.forEach((_, i) => {\n out.push({\n schedule: {\n seed: state.schedule.seed,\n faults: state.schedule.faults.filter((_, j) => j !== i),\n },\n keepIds: state.keepIds,\n });\n });\n if (state.keepIds.length > 1) {\n state.keepIds.forEach((id) => {\n out.push({\n schedule: {\n seed: state.schedule.seed,\n // Faults that belonged to the removed event's invocations can no longer fire.\n faults: state.schedule.faults.filter((f) => !f.invocation.startsWith(`${id}#`)),\n },\n keepIds: state.keepIds.filter((k) => k !== id),\n });\n });\n }\n return out;\n}\n\n/** Fewer events, then fewer faults: the order that keeps shrinking monotone. */\nexport function shrinkSize(state: ShrinkState): number {\n return state.keepIds.length * 1000 + state.schedule.faults.length;\n}\n","/**\n * The virtual clock and the globals patch. Within a run, Date, Math.random,\n * crypto.randomUUID, crypto.getRandomValues, performance.now and the timer\n * functions are replaced by deterministic versions driven by the run's seed\n * and by a clock that starts at a fixed epoch and advances only when the\n * engine says so: one millisecond per effect, and to each timer's due time\n * when the timer fires. Timers fire only while the invocation is idle (no\n * effect in flight), in due order, so they never race real I/O.\n */\n\nimport { nextFloat, nextU32, type PrngState, seedPrng } from \"@eutaxy/core\";\n\n/** 2026-01-01T00:00:00.000Z. Every run starts here. */\nexport const virtualEpoch = Date.UTC(2026, 0, 1);\n\n/** Virtual time advances this much at each effect completion. */\nexport const effectLatencyMs = 1;\n\n// Captured before any patching, so the engine can yield to the real event loop.\nconst realSetTimeout = globalThis.setTimeout.bind(globalThis);\nconst realSetInterval = globalThis.setInterval.bind(globalThis);\nconst realClearTimeout = globalThis.clearTimeout.bind(globalThis);\nconst realClearInterval = globalThis.clearInterval.bind(globalThis);\n\n/**\n * Tells library code apart from handler code while an effect's real I/O runs.\n * SDKs back off and time out with timers, which must be real; a handler timer\n * scheduled meanwhile must stay virtual. Node's AsyncLocalStorage follows the\n * library's promise chains and I/O callbacks but not the handler's own\n * continuations. Where it is unavailable (workerd without Node compatibility)\n * every timer stays virtual; the Cloudflare bindings do not use timers.\n */\ninterface LibraryScope {\n run<R>(store: true, fn: () => R): R;\n getStore(): true | undefined;\n}\nconst libraryScope: LibraryScope | null = (() => {\n const mod =\n typeof process !== \"undefined\"\n ? (process?.getBuiltinModule?.(\"node:async_hooks\") as\n | { AsyncLocalStorage?: new () => LibraryScope }\n | undefined)\n : undefined;\n return mod?.AsyncLocalStorage ? new mod.AsyncLocalStorage() : null;\n})();\n\ninterface Timer {\n readonly id: number;\n due: number;\n readonly callback: (...args: unknown[]) => void;\n readonly args: readonly unknown[];\n readonly interval: number | null;\n /** The invocation that scheduled it; cancelled with that invocation when it crashes. */\n readonly owner: string | null;\n}\n\nexport class VirtualClock {\n private time = virtualEpoch;\n private timers: Timer[] = [];\n private nextId = 1;\n /** The invocation whose code is running; timers scheduled now belong to it. */\n owner: string | null = null;\n\n now(): number {\n return this.time;\n }\n\n advance(ms: number): void {\n if (ms > 0) this.time += ms;\n }\n\n private schedule(\n callback: (...args: unknown[]) => void,\n delay: number,\n args: readonly unknown[],\n interval: number | null,\n ): number {\n const ms = Number.isFinite(delay) && delay > 0 ? Math.floor(delay) : 0;\n const timer: Timer = {\n id: this.nextId++,\n due: this.time + ms,\n callback,\n args,\n interval,\n owner: this.owner,\n };\n this.timers.push(timer);\n return timer.id;\n }\n\n setTimeout(callback: (...args: unknown[]) => void, delay = 0, ...args: unknown[]): number {\n return this.schedule(callback, delay, args, null);\n }\n\n setInterval(callback: (...args: unknown[]) => void, delay = 0, ...args: unknown[]): number {\n return this.schedule(callback, delay, args, Math.max(1, Math.floor(delay)));\n }\n\n clear(id: number): void {\n this.timers = this.timers.filter((t) => t.id !== id);\n }\n\n /** Whether this clock issued the handle (and the timer is still pending). */\n owns(id: unknown): id is number {\n return typeof id === \"number\" && this.timers.some((t) => t.id === id);\n }\n\n pendingTimers(): number {\n return this.timers.length;\n }\n\n /** Drop every timer an invocation scheduled: a crashed invocation's code must never run again. */\n cancelOwner(owner: string): void {\n this.timers = this.timers.filter((t) => t.owner !== owner);\n }\n\n /** Advance to the earliest due timer and run it. False when none is pending. */\n fireNext(): boolean {\n if (this.timers.length === 0) return false;\n let earliest = this.timers[0] as Timer;\n for (const t of this.timers)\n if (t.due < earliest.due || (t.due === earliest.due && t.id < earliest.id)) earliest = t;\n if (earliest.due > this.time) this.time = earliest.due;\n if (earliest.interval === null) this.timers = this.timers.filter((t) => t !== earliest);\n else earliest.due = this.time + earliest.interval;\n try {\n earliest.callback(...earliest.args);\n } catch {\n // An exception in a timer callback is uncaught in the real runtime too; it does not stop the run.\n }\n return true;\n }\n}\n\n/** Deterministic randomness for a run: Math.random, UUIDs and random bytes from one seeded stream. */\nexport class VirtualRandom {\n private state: PrngState;\n\n constructor(seed: number | string) {\n this.state = seedPrng(`random:${seed}`);\n }\n\n float(): number {\n const [f, next] = nextFloat(this.state);\n this.state = next;\n return f;\n }\n\n u32(): number {\n const [u, next] = nextU32(this.state);\n this.state = next;\n return u;\n }\n\n fill<T extends ArrayBufferView>(view: T): T {\n const bytes = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);\n for (let i = 0; i < bytes.length; i += 4) {\n const u = this.u32();\n for (let j = 0; j < 4 && i + j < bytes.length; j++) bytes[i + j] = (u >>> (8 * j)) & 0xff;\n }\n return view;\n }\n\n /** A version-4 UUID from the stream. */\n uuid(): string {\n const b = this.fill(new Uint8Array(16));\n b[6] = ((b[6] as number) & 0x0f) | 0x40;\n b[8] = ((b[8] as number) & 0x3f) | 0x80;\n const hex = [...b].map((x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n}\n\nexport interface Patched {\n readonly clock: VirtualClock;\n readonly random: VirtualRandom;\n /** Put every global back. Safe to call twice. */\n restore(): void;\n /**\n * Run an effect's real I/O: timers the library schedules inside it are\n * real (backoff, timeouts); timers the handler schedules meanwhile stay\n * virtual. The clock, Date and randomness stay virtual throughout.\n */\n libraryIo<T>(perform: () => Promise<T>): Promise<T>;\n}\n\ntype Global = Record<string, unknown>;\n\n/** Replace the nondeterministic globals for one run. Returns the handle that restores them. */\nexport function patchGlobals(seed: number | string): Patched {\n const clock = new VirtualClock();\n const random = new VirtualRandom(seed);\n const g = globalThis as unknown as Global;\n const saved = new Map<string, PropertyDescriptor | undefined>();\n const define = (target: object, key: string, value: unknown): void => {\n const owner = target === g ? g : target;\n saved.set(key, Object.getOwnPropertyDescriptor(owner, key));\n Object.defineProperty(owner, key, {\n value,\n configurable: true,\n writable: true,\n enumerable: false,\n });\n };\n\n const RealDate = Date;\n const VirtualDate = function (this: unknown, ...args: unknown[]): unknown {\n if (new.target === undefined) return new RealDate(clock.now()).toString();\n return Reflect.construct(RealDate, args.length === 0 ? [clock.now()] : args, new.target);\n } as unknown as DateConstructor;\n Object.setPrototypeOf(VirtualDate, RealDate);\n Object.defineProperty(VirtualDate, \"prototype\", { value: RealDate.prototype, writable: false });\n Object.defineProperty(VirtualDate, \"now\", {\n value: () => clock.now(),\n configurable: true,\n writable: true,\n });\n Object.defineProperty(VirtualDate, \"name\", { value: \"Date\" });\n\n define(g, \"Date\", VirtualDate);\n define(Math, \"random\", () => random.float());\n const inLibrary = () => libraryScope?.getStore() === true;\n define(g, \"setTimeout\", (cb: (...a: unknown[]) => void, ms?: number, ...args: unknown[]) =>\n inLibrary() ? realSetTimeout(cb, ms, ...args) : clock.setTimeout(cb, ms, ...args),\n );\n define(g, \"setInterval\", (cb: (...a: unknown[]) => void, ms?: number, ...args: unknown[]) =>\n inLibrary() ? realSetInterval(cb, ms, ...args) : clock.setInterval(cb, ms, ...args),\n );\n // Clearing dispatches on the handle: a virtual timer cancelled from library code, or a real\n // one cancelled from handler code, each reach the implementation that owns it.\n define(g, \"clearTimeout\", (id?: unknown) => {\n if (clock.owns(id)) clock.clear(id);\n else realClearTimeout(id as Parameters<typeof realClearTimeout>[0]);\n });\n define(g, \"clearInterval\", (id?: unknown) => {\n if (clock.owns(id)) clock.clear(id);\n else realClearInterval(id as Parameters<typeof realClearInterval>[0]);\n });\n const perf = g[\"performance\"];\n if (perf && typeof perf === \"object\") define(perf, \"now\", () => clock.now() - virtualEpoch);\n const cryptoObj = g[\"crypto\"];\n if (cryptoObj && typeof cryptoObj === \"object\") {\n define(cryptoObj, \"randomUUID\", () => random.uuid());\n define(cryptoObj, \"getRandomValues\", <T extends ArrayBufferView>(view: T) => random.fill(view));\n }\n\n let restored = false;\n const targets: Record<string, object> = {\n Date: g,\n random: Math,\n setTimeout: g,\n setInterval: g,\n clearTimeout: g,\n clearInterval: g,\n };\n if (perf && typeof perf === \"object\") targets[\"now\"] = perf;\n if (cryptoObj && typeof cryptoObj === \"object\") {\n targets[\"randomUUID\"] = cryptoObj;\n targets[\"getRandomValues\"] = cryptoObj;\n }\n return {\n clock,\n random,\n libraryIo<T>(perform: () => Promise<T>): Promise<T> {\n return libraryScope ? libraryScope.run(true, perform) : perform();\n },\n restore() {\n if (restored) return;\n restored = true;\n for (const [key, descriptor] of saved) {\n const target = targets[key] as object;\n if (descriptor) Object.defineProperty(target, key, descriptor);\n else delete (target as Global)[key];\n }\n },\n };\n}\n\n/** Yield to the real event loop so microtasks and pending I/O can make progress. */\nexport function realTick(): Promise<void> {\n return new Promise((resolve) => realSetTimeout(() => resolve(), 0));\n}\n\nexport interface SettleContext {\n readonly clock: VirtualClock;\n /** Effects currently performing real I/O. */\n readonly inFlight: () => number;\n /** True once the invocation has been crashed; the promise is then abandoned. */\n readonly crashed: () => boolean;\n /** Called when nothing can make progress: no I/O, no timers, not done. */\n readonly stuck: () => void;\n}\n\n/**\n * Wait for a promise under the virtual clock: while it is pending, let real\n * I/O complete, and when the invocation is idle fire the next due timer.\n */\nexport async function settleOn<T>(promise: Promise<T>, ctx: SettleContext): Promise<T> {\n let done = false;\n let failed = false;\n let value: T | undefined;\n let error: unknown;\n const tracked = promise.then(\n (v) => {\n done = true;\n value = v;\n },\n (e: unknown) => {\n done = true;\n failed = true;\n error = e;\n },\n );\n for (;;) {\n await Promise.race([tracked, realTick()]);\n if (done) {\n if (failed) throw error;\n return value as T;\n }\n if (ctx.crashed()) return new Promise<T>(() => {});\n if (ctx.inFlight() > 0) continue;\n if (ctx.clock.fireNext()) continue;\n ctx.stuck();\n return new Promise<T>(() => {});\n }\n}\n","/**\n * Scripted outbound fetch. During a run, `fetch` is replaced by a function\n * that answers from the scenario's declared externals instead of the\n * network. Each request is an effect point (with every fault available) when\n * run hooks are given; without hooks it is the same scripted behaviour with\n * no recording, which the differential's raw side uses.\n *\n * An external that declares `dedupeBy` remembers the first response per key\n * for the run: a repeated key gets that response back and is recorded as\n * not effective. A request to an undeclared host, or one no scripted\n * response answers, makes the run unsupported.\n */\n\nimport type { ExternalDecl, FaultKind, JsonValue, RunHooks, ScriptedResponse } from \"@eutaxy/core\";\n\nconst FAULTS: readonly FaultKind[] = [\"crash_before\", \"crash_after\", \"ambiguous\", \"error\"];\n\nexport interface FetchHooks {\n readonly hooks: RunHooks;\n readonly invocation: () => string;\n}\n\n/** Match a host against an exact host or a \"*.suffix\" pattern. */\nexport function hostMatches(pattern: string, host: string): boolean {\n if (pattern.startsWith(\"*.\")) {\n const suffix = pattern.slice(1); // \".example.com\"\n return host.endsWith(suffix) && host.length > suffix.length;\n }\n return pattern === host;\n}\n\nexport function findExternal(\n externals: readonly ExternalDecl[],\n host: string,\n): ExternalDecl | undefined {\n return externals.find((e) => hostMatches(e.host, host));\n}\n\nexport function findResponse(\n external: ExternalDecl,\n method: string,\n path: string,\n): ScriptedResponse | undefined | null {\n if (!external.responses) return null; // null: no script at all, default reply\n return external.responses.find((r) => {\n if (r.method && r.method.toUpperCase() !== method) return false;\n if (r.path === undefined) return true;\n return r.path.endsWith(\"*\") ? path.startsWith(r.path.slice(0, -1)) : r.path === path;\n });\n}\n\ninterface Reply {\n readonly status: number;\n readonly headers: { readonly [name: string]: string };\n readonly body: string;\n}\n\nconst REDIRECTS = new Set([301, 302, 303, 307, 308]);\n\nfunction replyOf(r: ScriptedResponse | null): Reply {\n if (r === null) return { status: 200, headers: {}, body: \"\" };\n const json = r.body !== undefined && typeof r.body !== \"string\";\n const headers: Record<string, string> = {};\n for (const [name, value] of Object.entries(r.headers ?? {})) headers[name.toLowerCase()] = value;\n if (json && !(\"content-type\" in headers)) headers[\"content-type\"] = \"application/json\";\n const body = r.body === undefined ? \"\" : json ? JSON.stringify(r.body) : (r.body as string);\n return { status: r.status, headers, body };\n}\n\nfunction toResponse(reply: Reply): Response {\n return new Response(reply.body === \"\" ? null : reply.body, {\n status: reply.status,\n headers: reply.headers,\n });\n}\n\nfunction parseBody(text: string): JsonValue {\n if (text === \"\") return null;\n try {\n return JSON.parse(text) as JsonValue;\n } catch {\n return text;\n }\n}\n\nexport interface ScriptedFetch {\n readonly fetch: typeof fetch;\n /** Replies already given per external and dedupe key, for the run. */\n readonly dedupe: Map<string, Reply>;\n}\n\n/**\n * Build the replacement `fetch`. With `hooks`, every request is an effect\n * point recorded as `Fetch:<external>` with the method as op; the result\n * summary carries `status`, `effective` and the dedupe key.\n */\nexport function createScriptedFetch(\n externals: readonly ExternalDecl[],\n hooks: FetchHooks | null,\n unsupported: (reason: string) => void,\n /** Called after each answered request without hooks, e.g. to advance a clock the way an effect would. */\n afterRequest: () => void = () => {},\n): ScriptedFetch {\n const dedupe = new Map<string, Reply>();\n\n const scripted = (async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const request = new Request(input, init);\n const url = new URL(request.url);\n const method = request.method.toUpperCase();\n const external = findExternal(externals, url.host);\n if (!external) {\n unsupported(\n `fetch to undeclared host ${url.host}; declare it as an external in the scenario`,\n );\n throw new TypeError(`fetch failed: ${url.host} is not a declared external`);\n }\n const headers: Record<string, string> = {};\n request.headers.forEach((value, name) => {\n headers[name.toLowerCase()] = value;\n });\n const dedupeHeader = external.guarantees.dedupeBy?.toLowerCase();\n const dedupeKey = dedupeHeader ? (headers[dedupeHeader] ?? null) : null;\n const body = parseBody(await request.text());\n const args: JsonValue = { url: request.url, method, headers, body, dedupeKey };\n\n const perform = async (): Promise<{ reply: Reply; effective: boolean }> => {\n const memo = dedupeKey === null ? null : `${external.name}\\u0000${dedupeKey}`;\n if (memo !== null) {\n const earlier = dedupe.get(memo);\n if (earlier) return { reply: earlier, effective: false };\n }\n const script = findResponse(external, method, url.pathname);\n if (script === undefined) {\n unsupported(\n `no scripted response in external ${external.name} for ${method} ${url.pathname}`,\n );\n throw new TypeError(`fetch failed: no scripted response for ${method} ${url.pathname}`);\n }\n const reply = replyOf(script);\n if (REDIRECTS.has(reply.status) && request.redirect !== \"manual\") {\n unsupported(\n `external ${external.name} answers ${method} ${url.pathname} with a ${reply.status} redirect; script the final reply or fetch with redirect: \"manual\"`,\n );\n throw new TypeError(\n `fetch failed: redirects are not modelled (${reply.status} from ${url.host})`,\n );\n }\n if (memo !== null) dedupe.set(memo, reply);\n return { reply, effective: true };\n };\n\n if (!hooks) {\n const { reply } = await perform();\n afterRequest();\n return toResponse(reply);\n }\n const { reply } = await hooks.hooks.effect(\n {\n invocation: hooks.invocation(),\n target: `Fetch:${external.name}`,\n op: method,\n args,\n allowed: FAULTS,\n },\n perform,\n (r) => ({ status: r.reply.status, effective: r.effective, dedupeKey }),\n );\n return toResponse(reply);\n }) as typeof fetch;\n\n return { fetch: scripted, dedupe };\n}\n\n/** Replace the global `fetch` for a run; returns the function that restores it. */\nexport function installScriptedFetch(\n externals: readonly ExternalDecl[],\n hooks: FetchHooks | null,\n unsupported: (reason: string) => void,\n afterRequest?: () => void,\n): () => void {\n const g = globalThis as unknown as { fetch: typeof fetch };\n const saved = Object.getOwnPropertyDescriptor(globalThis, \"fetch\");\n const { fetch: scripted } = createScriptedFetch(externals, hooks, unsupported, afterRequest);\n Object.defineProperty(globalThis, \"fetch\", {\n value: scripted,\n configurable: true,\n writable: true,\n });\n let restored = false;\n return () => {\n if (restored) return;\n restored = true;\n if (saved) Object.defineProperty(globalThis, \"fetch\", saved);\n else delete (g as { fetch?: unknown }).fetch;\n };\n}\n","/**\n * One run of a scenario: the effect log being built, the fault decisions\n * (drawn during exploration, looked up during replay), and the invocations\n * in flight. Proxies in the platform package call `effect`/`effectSync`\n * around every real effect; everything else is engine-internal.\n */\n\nimport {\n appendEffect,\n type Bounds,\n decideFault,\n type EffectLog,\n type EffectPoint,\n type ExternalDecl,\n emptyLog,\n type FaultDecision,\n type FaultKind,\n type Invocation,\n type JsonValue,\n type PrngState,\n type RunHooks,\n type Schedule,\n seedPrng,\n} from \"@eutaxy/core\";\nimport { effectLatencyMs, type Patched, patchGlobals, settleOn } from \"./clock.ts\";\nimport { installScriptedFetch } from \"./fetch.ts\";\n\n/** Thrown into user code by a synchronous effect that crashes the invocation. */\nexport class CrashSignal extends Error {\n override readonly name = \"CrashSignal\";\n readonly invocation: string;\n constructor(invocation: string) {\n super(`invocation ${invocation} crashed by an injected fault`);\n this.invocation = invocation;\n }\n}\n\n/** The error user code sees for an injected `error` or `ambiguous` fault. */\nexport class InjectedEffectError extends Error {\n override readonly name = \"InjectedEffectError\";\n readonly point: EffectPoint;\n readonly fault: FaultKind;\n constructor(point: EffectPoint, fault: FaultKind) {\n super(`${point.target} ${point.op} failed (injected ${fault})`);\n this.point = point;\n this.fault = fault;\n }\n}\n\nexport interface RunOptions {\n readonly mode: \"explore\" | \"replay\";\n readonly schedule: Schedule;\n readonly bounds: Bounds;\n readonly faultProbability: number;\n}\n\nclass InvocationState implements Invocation {\n readonly crashed: Promise<void>;\n private readonly onCrash: () => void;\n /** Effect points seen so far in this invocation; the next effect's ordinal. */\n ordinal = 0;\n private crashedFlag = false;\n private resolveCrashed: () => void = () => {};\n readonly id: string;\n\n constructor(id: string, onCrash: () => void) {\n this.id = id;\n this.onCrash = onCrash;\n this.crashed = new Promise<void>((resolve) => {\n this.resolveCrashed = resolve;\n });\n }\n\n isCrashed(): boolean {\n return this.crashedFlag;\n }\n\n crash(): void {\n if (this.crashedFlag) return;\n this.crashedFlag = true;\n this.onCrash();\n this.resolveCrashed();\n }\n}\n\n/** A promise that never settles: how an abandoned invocation experiences a crash. */\nfunction hang<T>(): Promise<T> {\n return new Promise<T>(() => {});\n}\n\nexport class Run implements RunHooks {\n private logState: EffectLog = emptyLog;\n private readonly faults: FaultDecision[] = [];\n private effectIndex = 0;\n private prng: PrngState;\n private readonly invocations = new Map<string, InvocationState>();\n private readonly reasons: string[] = [];\n private inFlight = 0;\n private patched: Patched | null = null;\n private restoreFetch: (() => void) | null = null;\n /** The invocation whose code is running (one at a time); outbound fetches are attributed to it. */\n private current = \"\";\n\n readonly options: RunOptions;\n\n constructor(options: RunOptions) {\n this.options = options;\n this.prng = seedPrng(options.schedule.seed);\n }\n\n get log(): EffectLog {\n return this.logState;\n }\n\n /** The schedule as actually executed: input decisions during replay, drawn ones during exploration. */\n get schedule(): Schedule {\n return { seed: this.options.schedule.seed, faults: [...this.faults] };\n }\n\n get effectPoints(): number {\n return this.effectIndex;\n }\n\n get faultsInjected(): number {\n return this.faults.length;\n }\n\n get unsupportedReasons(): readonly string[] {\n return this.reasons;\n }\n\n /** Replace the nondeterministic globals and `fetch` for this run. Call `uninstall` in a finally. */\n install(externals: readonly ExternalDecl[] = []): void {\n if (!this.patched) this.patched = patchGlobals(this.options.schedule.seed);\n if (!this.restoreFetch) {\n this.restoreFetch = installScriptedFetch(\n externals,\n { hooks: this, invocation: () => this.current },\n (reason) => this.unsupported(reason),\n );\n }\n }\n\n uninstall(): void {\n this.restoreFetch?.();\n this.restoreFetch = null;\n this.patched?.restore();\n this.patched = null;\n }\n\n /** Virtual milliseconds since the epoch, or the real clock when the globals are not installed. */\n now(): number {\n return this.patched ? this.patched.clock.now() : Date.now();\n }\n\n /** Timers scheduled and not yet fired or cancelled (0 when the globals are not installed). */\n pendingTimers(): number {\n return this.patched?.clock.pendingTimers() ?? 0;\n }\n\n startInvocation(id: string): Invocation {\n if (this.invocations.has(id)) throw new Error(`invocation ${id} already started`);\n const inv = new InvocationState(id, () => this.patched?.clock.cancelOwner(id));\n this.invocations.set(id, inv);\n if (this.patched) this.patched.clock.owner = id;\n this.current = id;\n return inv;\n }\n\n private invocation(id: string): InvocationState {\n const inv = this.invocations.get(id);\n if (!inv) throw new Error(`effect from unknown invocation ${id}`);\n return inv;\n }\n\n private decide(point: EffectPoint, ordinal: number): FaultKind | null {\n if (this.options.mode === \"replay\") {\n const d = this.options.schedule.faults.find(\n (f) => f.invocation === point.invocation && f.ordinal === ordinal,\n );\n return d && point.allowed.includes(d.fault) ? d.fault : null;\n }\n const [fault, next] = decideFault(this.prng, point.allowed, this.faults.length, {\n maxFaultsPerRun: this.options.bounds.maxFaultsPerRun,\n faultProbability: this.options.faultProbability,\n });\n this.prng = next;\n return fault;\n }\n\n private record(point: EffectPoint, kind: \"call\" | \"result\" | \"fault\", payload: JsonValue): void {\n this.logState = appendEffect(this.logState, {\n kind,\n invocation: point.invocation,\n target: point.target,\n op: point.op,\n payload,\n });\n }\n\n /** Open an effect point: record the call and decide the fault. */\n private open(point: EffectPoint, inv: InvocationState): FaultKind | null {\n this.effectIndex++;\n const ordinal = inv.ordinal++;\n this.record(point, \"call\", { args: point.args });\n const fault = this.decide(point, ordinal);\n if (fault) {\n this.faults.push({\n invocation: point.invocation,\n ordinal,\n fault,\n target: point.target,\n op: point.op,\n });\n }\n return fault;\n }\n\n async effect<T>(\n point: EffectPoint,\n perform: () => Promise<T>,\n summarize: (value: T) => JsonValue,\n ): Promise<T> {\n const inv = this.invocation(point.invocation);\n if (inv.isCrashed()) return hang();\n const fault = this.open(point, inv);\n if (fault === \"crash_before\" || fault === \"cut_off\") {\n this.record(point, \"fault\", { args: point.args, fault });\n inv.crash();\n return hang();\n }\n if (fault === \"error\") {\n this.record(point, \"fault\", { args: point.args, fault });\n throw new InjectedEffectError(point, fault);\n }\n let value: T;\n this.inFlight++;\n try {\n // The library's own timers inside the I/O are real; the handler's stay virtual.\n value = await (this.patched ? this.patched.libraryIo(perform) : perform());\n } catch (err) {\n this.record(point, \"result\", { args: point.args, result: null, error: String(err) });\n throw err;\n } finally {\n this.inFlight--;\n this.patched?.clock.advance(effectLatencyMs);\n }\n this.record(point, \"result\", { args: point.args, result: summarize(value) });\n // The effect committed while the invocation was dying: nothing after it runs.\n if (inv.isCrashed()) return hang();\n if (fault === \"crash_after\") {\n this.record(point, \"fault\", { args: point.args, fault });\n inv.crash();\n return hang();\n }\n if (fault === \"ambiguous\") {\n this.record(point, \"fault\", { args: point.args, fault });\n throw new InjectedEffectError(point, fault);\n }\n return value;\n }\n\n effectSync<T>(point: EffectPoint, perform: () => T, summarize: (value: T) => JsonValue): T {\n const inv = this.invocation(point.invocation);\n if (inv.isCrashed()) throw new CrashSignal(inv.id);\n const fault = this.open(point, inv);\n if (fault === \"crash_before\" || fault === \"cut_off\") {\n this.record(point, \"fault\", { args: point.args, fault });\n inv.crash();\n throw new CrashSignal(inv.id);\n }\n if (fault === \"error\") {\n this.record(point, \"fault\", { args: point.args, fault });\n throw new InjectedEffectError(point, fault);\n }\n let value: T;\n try {\n value = perform();\n } catch (err) {\n this.record(point, \"result\", { args: point.args, result: null, error: String(err) });\n throw err;\n }\n this.record(point, \"result\", { args: point.args, result: summarize(value) });\n if (fault === \"crash_after\") {\n this.record(point, \"fault\", { args: point.args, fault });\n inv.crash();\n throw new CrashSignal(inv.id);\n }\n if (fault === \"ambiguous\") {\n this.record(point, \"fault\", { args: point.args, fault });\n throw new InjectedEffectError(point, fault);\n }\n return value;\n }\n\n unsupported(reason: string): void {\n this.reasons.push(reason);\n }\n\n settle<T>(promise: Promise<T>, invocation: string): Promise<T> {\n const inv = this.invocation(invocation);\n const patched = this.patched;\n if (patched) patched.clock.owner = invocation;\n this.current = invocation;\n if (!patched) {\n // Globals not installed (direct use outside runOnce): just wait, abandoning on crash.\n return Promise.race([promise, inv.crashed.then(() => new Promise<T>(() => {}))]);\n }\n return settleOn(promise, {\n clock: patched.clock,\n inFlight: () => this.inFlight,\n crashed: () => inv.isCrashed(),\n stuck: () => {\n // Nothing can make progress: report it and abandon the invocation so the run can end.\n this.unsupported(\n `invocation ${invocation} is waiting on something Eutaxy cannot see (no effect in flight, no timer due)`,\n );\n inv.crash();\n },\n });\n }\n\n snapshot(invocation: string, target: string, payload: JsonValue): void {\n this.logState = appendEffect(this.logState, {\n kind: \"snapshot\",\n invocation,\n target,\n op: \"snapshot\",\n payload,\n });\n }\n}\n","/**\n * Shrinking, the loop: try the pure candidates in order, replay each, keep\n * the first that still violates the same invariant for the same keys, and\n * repeat from there until nothing smaller works or the budget is spent.\n */\n\nimport {\n checkInvariants,\n type EffectLog,\n type Platform,\n recomputePerMessageExpected,\n type ScenarioSpec,\n type Schedule,\n type ShrinkState,\n sameViolation,\n shrinkCandidates,\n type Violation,\n} from \"@eutaxy/core\";\nimport { replayRun } from \"./explore.ts\";\n\nexport interface ShrinkOptions {\n readonly maxRuns: number;\n readonly deadline: number;\n readonly now: () => number;\n}\n\nexport interface ShrinkResult {\n readonly spec: ScenarioSpec;\n readonly schedule: Schedule;\n readonly keptEvents: readonly string[];\n readonly trace: EffectLog;\n readonly violation: Violation;\n readonly runs: number;\n readonly faultsRemoved: number;\n readonly eventsRemoved: number;\n}\n\n/** The scenario restricted to the kept events, with per-message invariants re-derived. */\nexport function restrictSpec(\n platform: Platform,\n spec: ScenarioSpec,\n keepIds: readonly string[],\n): ScenarioSpec {\n const restricted = platform.restrictEvents(spec, keepIds);\n const bodies = platform.initialEvents(restricted).map((e) => e.data);\n return { ...restricted, invariants: recomputePerMessageExpected(restricted.invariants, bodies) };\n}\n\nexport async function shrink(\n spec: ScenarioSpec,\n platform: Platform,\n schedule: Schedule,\n violation: Violation,\n trace: EffectLog,\n options: ShrinkOptions,\n): Promise<ShrinkResult> {\n const allIds = platform.initialEvents(spec).map((e) => e.id);\n let state: ShrinkState = { schedule, keepIds: allIds };\n let best = { trace, violation };\n let runs = 0;\n\n let improved = true;\n while (improved && runs < options.maxRuns && options.now() < options.deadline) {\n improved = false;\n for (const candidate of shrinkCandidates(state)) {\n if (runs >= options.maxRuns || options.now() >= options.deadline) break;\n const candidateSpec = restrictSpec(platform, spec, candidate.keepIds);\n const run = await replayRun(candidateSpec, platform, candidate.schedule);\n const log = run.log;\n runs++;\n // A smaller run that touches something Eutaxy cannot control is not a valid counterexample.\n if (run.unsupportedReasons.length > 0) continue;\n const found = checkInvariants(log, candidateSpec.invariants).find((v) =>\n sameViolation(v, violation),\n );\n if (found) {\n state = candidate;\n best = { trace: log, violation: found };\n improved = true;\n break;\n }\n }\n }\n return {\n spec: restrictSpec(platform, spec, state.keepIds),\n schedule: state.schedule,\n keptEvents: state.keepIds,\n trace: best.trace,\n violation: best.violation,\n runs,\n faultsRemoved: schedule.faults.length - state.schedule.faults.length,\n eventsRemoved: allIds.length - state.keepIds.length,\n };\n}\n","/**\n * The exploration loop: run the scenario under seeded fault injection until\n * an invariant breaks or the budget is spent; replay any violation before\n * reporting it.\n */\n\nimport {\n type BoundsReached,\n checkInvariants,\n digestLog,\n type EffectLog,\n type EventRef,\n nextU32,\n type Platform,\n type PrngState,\n type ScenarioSpec,\n type ScenarioVerdict,\n type Schedule,\n seedPrng,\n} from \"@eutaxy/core\";\nimport { Run } from \"./run.ts\";\nimport { shrink } from \"./shrink.ts\";\n\nexport interface ExploreOptions {\n readonly seed: number | string;\n /** Hard cap on runs, in addition to the scenario's time budget. */\n readonly maxRuns?: number;\n /** Probability of injecting at an eligible effect point. */\n readonly faultProbability?: number;\n /** Clock for the time budget; injectable for tests. */\n readonly now?: () => number;\n /** Hard cap on replay runs spent shrinking a violation. */\n readonly maxShrinkRuns?: number;\n /**\n * How many of the first exploration runs to replay in reverse order\n * before reporting BOUNDED, to detect module-level state leaking between\n * runs. 0 disables the pass.\n */\n readonly leakCheckRuns?: number;\n}\n\nconst engineAssumptions: readonly string[] = [\n \"schedule points are effect boundaries: proxied bindings, patched timers and fetch; other awaits run in program order\",\n \"faults: crash_before, crash_after, ambiguous, error at any effect point; redelivery per the platform's queue model\",\n \"one invocation at a time (maxConcurrentInvocations = 1)\",\n \"Date, Math.random, crypto.randomUUID, crypto.getRandomValues, performance.now and timers are virtualised per run from the seed; time starts at 2026-01-01T00:00:00Z and advances 1 ms per effect and to each timer's due time\",\n \"timers fire only while the invocation is idle (no effect in flight), in due order; an invocation waiting on something outside Eutaxy makes the run UNSUPPORTED\",\n \"while an effect performs real I/O the real timer functions are in place for that I/O, so user code that schedules a timer concurrently with an effect gets a real one\",\n \"module-level state cannot be reset between runs; before BOUNDED the first runs are replayed in reverse order and any difference makes the run UNSUPPORTED (module_state_leak)\",\n \"outbound fetch never reaches the network: requests are answered from the scenario's declared externals, an external's dedupeBy guarantee is honoured by replaying the first response per key, and an undeclared host makes the run UNSUPPORTED\",\n];\n\n/** Run the scenario once under the given run's fault decisions and return its log. */\nexport async function runOnce(\n spec: ScenarioSpec,\n platform: Platform,\n run: Run,\n): Promise<EffectLog> {\n // Reset and the end-of-run snapshot are platform work, not user code: they run with the real\n // globals, so an in-process local service (which shares them) keeps its own timers.\n await platform.reset(spec);\n run.install(spec.externals);\n try {\n try {\n const pending: EventRef[] = [...platform.initialEvents(spec)];\n while (pending.length > 0) {\n const event = pending.shift() as EventRef;\n const result = await platform.deliver(event, run, spec);\n pending.push(...result.followUps);\n }\n } finally {\n run.uninstall();\n }\n await platform.finish?.(spec, run);\n } finally {\n // Whatever happened above, the platform undoes its per-run patching.\n await platform.cleanup?.(spec);\n }\n return run.log;\n}\n\n/** Re-run a recorded schedule exactly and return the whole run (log and support status). */\nexport async function replayRun(\n spec: ScenarioSpec,\n platform: Platform,\n schedule: Schedule,\n): Promise<Run> {\n const run = new Run({ mode: \"replay\", schedule, bounds: spec.bounds, faultProbability: 0 });\n await runOnce(spec, platform, run);\n return run;\n}\n\n/** Re-run a recorded schedule exactly. */\nexport async function replay(\n spec: ScenarioSpec,\n platform: Platform,\n schedule: Schedule,\n): Promise<EffectLog> {\n return (await replayRun(spec, platform, schedule)).log;\n}\n\nexport async function explore(\n spec: ScenarioSpec,\n platform: Platform,\n options: ExploreOptions,\n): Promise<ScenarioVerdict> {\n const now = options.now ?? (() => Date.now());\n const maxRuns = options.maxRuns ?? 100;\n const faultProbability = options.faultProbability ?? 0.5;\n const assumptions = [...engineAssumptions, ...platform.assumptions];\n const start = now();\n const reached = { runs: 0, effectPoints: 0, faultsInjected: 0 };\n const done = (): BoundsReached => ({ ...reached, elapsedMs: now() - start });\n const base = { scenario: spec.name, seed: options.seed, assumptions };\n\n if (spec.bounds.maxConcurrentInvocations !== 1) {\n return {\n ...base,\n kind: \"UNSUPPORTED\",\n cause: \"unsupported_bounds\",\n reason: \"maxConcurrentInvocations above 1 is not supported yet\",\n reached: done(),\n };\n }\n\n const leakCheckRuns = options.leakCheckRuns ?? 2;\n /** The first runs' schedules and digests, replayed in reverse order before BOUNDED. */\n const witnesses: { schedule: Schedule; digest: string }[] = [];\n\n let master: PrngState = seedPrng(options.seed);\n while (reached.runs < maxRuns && now() - start < spec.bounds.budgetMs) {\n const [runSeed, next] = nextU32(master);\n master = next;\n const run = new Run({\n mode: \"explore\",\n schedule: { seed: runSeed, faults: [] },\n bounds: spec.bounds,\n faultProbability,\n });\n const log = await runOnce(spec, platform, run);\n reached.runs++;\n reached.effectPoints += run.effectPoints;\n reached.faultsInjected += run.faultsInjected;\n if (witnesses.length < leakCheckRuns)\n witnesses.push({ schedule: run.schedule, digest: digestLog(log) });\n\n if (run.unsupportedReasons.length > 0) {\n return {\n ...base,\n kind: \"UNSUPPORTED\",\n cause: \"unsupported_api\",\n reason: run.unsupportedReasons.join(\"; \"),\n reached: done(),\n };\n }\n\n const violations = checkInvariants(log, spec.invariants);\n const violation = violations[0];\n if (violation) {\n const schedule = run.schedule;\n const replayedRun = await replayRun(spec, platform, schedule);\n const replayed = replayedRun.log;\n reached.runs++;\n if (replayedRun.unsupportedReasons.length > 0 || digestLog(replayed) !== digestLog(log)) {\n return {\n ...base,\n kind: \"UNSUPPORTED\",\n cause: \"not_replayable\",\n reason: `the violating run of seed ${schedule.seed} did not reproduce on replay`,\n reached: done(),\n };\n }\n // Shrink within the scenario's budget (a second budget's worth at most), then report.\n const shrunk = await shrink(spec, platform, schedule, violation, replayed, {\n maxRuns: options.maxShrinkRuns ?? 200,\n deadline: now() + spec.bounds.budgetMs,\n now,\n });\n reached.runs += shrunk.runs;\n return {\n ...base,\n kind: \"VIOLATED\",\n violation: shrunk.violation,\n trace: shrunk.trace,\n schedule: shrunk.schedule,\n keptEvents: shrunk.keptEvents,\n shrunk: {\n faultsRemoved: shrunk.faultsRemoved,\n eventsRemoved: shrunk.eventsRemoved,\n runs: shrunk.runs,\n },\n reached: done(),\n };\n }\n }\n // Module-state leak detection: the same schedules, in the opposite order, must give the same logs.\n for (const witness of [...witnesses].reverse()) {\n const again = await replayRun(spec, platform, witness.schedule);\n reached.runs++;\n if (again.unsupportedReasons.length > 0 || digestLog(again.log) !== witness.digest) {\n return {\n ...base,\n kind: \"UNSUPPORTED\",\n cause: \"module_state_leak\",\n reason: `run seed ${witness.schedule.seed} produced a different log when replayed after other runs: state is leaking between runs (module-level variables, or a binding Eutaxy does not reset)`,\n reached: done(),\n };\n }\n }\n return { ...base, kind: \"BOUNDED\", bounds: spec.bounds, reached: done() };\n}\n"],"mappings":";;AAWA,SAAS,KAAK,GAAW,GAAmB;CAC1C,QAAS,KAAK,IAAM,MAAO,KAAK,OAAS;AAC3C;;AAGA,SAAS,WAAW,MAA4B;CAC9C,IAAI,IAAI,SAAS;CACjB,aAAa;EACX,IAAK,IAAI,eAAgB;EACzB,IAAI,IAAI;EACR,IAAI,KAAK,KAAK,IAAK,MAAM,IAAK,SAAU;EACxC,IAAI,KAAK,KAAK,IAAK,MAAM,IAAK,UAAU;EACxC,QAAQ,IAAK,MAAM,QAAS;CAC9B;AACF;;AAGA,SAAS,WAAW,GAAmB;CACrC,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;EACjC,KAAK,EAAE,WAAW,CAAC;EACnB,IAAI,KAAK,KAAK,GAAG,QAAU;CAC7B;CACA,OAAO,MAAM;AACf;;AAGA,SAAgB,SAAS,MAAkC;CAEzD,MAAM,OAAO,WADA,OAAO,SAAS,WAAW,WAAW,IAAI,IAAI,SAAS,CACxC;CAC5B,MAAM,IAAsC;EAAC,KAAK;EAAG,KAAK;EAAG,KAAK;EAAG,KAAK;CAAC;CAC3E,IAAI,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,OAAO,GACrD,EAAE,KAAK;CAET,OAAO;AACT;;AAGA,SAAgB,QAAQ,OAAgD;CACtE,MAAM,CAAC,IAAI,IAAI,IAAI,MAAM;CACzB,MAAM,SAAS,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM;CACjE,MAAM,IAAK,MAAM,MAAO;CACxB,IAAI,MAAM,KAAK,QAAQ;CACvB,IAAI,MAAM,KAAK,QAAQ;CACvB,MAAM,MAAM,KAAK,QAAQ;CACzB,MAAM,MAAM,KAAK,QAAQ;CACzB,MAAM,KAAK,OAAO;CAClB,KAAK,KAAK,IAAI,EAAE;CAChB,OAAO,CAAC,QAAQ;EAAC;EAAI;EAAI;EAAI;CAAE,CAAC;AAClC;;AAGA,SAAgB,UAAU,OAAgD;CACxE,MAAM,CAAC,GAAG,QAAQ,QAAQ,KAAK;CAC/B,OAAO,EAAE,MAAM,KAAK,KAAK,KAAK,IAAI;AACpC;;;;;AAMA,SAAgB,QAAQ,OAAkB,OAA6C;CACrF,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,YACnD,MAAM,IAAI,WAAW,sDAAsD,OAAO;CAEpF,IAAI,UAAU,GAAG,OAAO,CAAC,GAAG,KAAK;CACjC,MAAM,QAAQ,aAAiB,aAAgB;CAC/C,IAAI,IAAI;CACR,SAAS;EACP,MAAM,CAAC,GAAG,QAAQ,QAAQ,CAAC;EAC3B,IAAI;EACJ,IAAI,IAAI,OAAO,OAAO,CAAC,IAAI,OAAO,CAAC;CACrC;AACF;;;;;;;;;;;;ACjCA,SAAgB,YACd,OACA,SACA,aACA,QACwC;CACxC,IAAI,QAAQ,WAAW,KAAK,eAAe,OAAO,iBAAiB,OAAO,CAAC,MAAM,KAAK;CACtF,MAAM,CAAC,GAAG,MAAM,UAAU,KAAK;CAC/B,IAAI,KAAK,OAAO,kBAAkB,OAAO,CAAC,MAAM,EAAE;CAClD,MAAM,CAAC,GAAG,MAAM,QAAQ,IAAI,QAAQ,MAAM;CAC1C,OAAO,CAAC,QAAQ,MAAM,MAAM,EAAE;AAChC;;;;;;;;ACrBA,SAAgB,4BACd,YACA,QACsB;CACtB,OAAO,WAAW,KAAK,QAAQ;EAC7B,IAAI,IAAI,SAAS,iBAAiB,CAAC,IAAI,YAAY,OAAO;EAC1D,MAAM,UAAU,IAAI,WAAW;EAC/B,MAAM,WAAwB,CAAC;EAC/B,KAAK,MAAM,KAAK,QAAQ;GACtB,MAAM,IAAI,QAAQ,GAAG,OAAO;GAC5B,IAAI,MAAM,KAAA,GAAW,SAAS,KAAK,CAAC;EACtC;EACA,OAAO;GAAE,GAAG;GAAK;EAAS;CAC5B,CAAC;AACH;;AA6CA,SAAgB,aACd,KACA,QAC0D;CAC1D,KAAK,IAAI,IAAI,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KAAK;EAChD,MAAM,IAAI,IAAI,QAAQ;EACtB,IAAI,EAAE,SAAS,cAAc,EAAE,WAAW,QAAQ;GAChD,MAAM,SAAS,QAAQ,EAAE,SAAS,QAAQ;GAC1C,IAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAC/D,OAAO;GAET,OAAO,CAAC;EACV;CACF;AAEF;AAEA,SAAgB,WAAW,KAAU,WAAkC;CACrE,MAAM,IAAI,IAAI,UAAU;CACxB,QAAQ,UAAU,IAAlB;EACE,KAAK,MACH,OAAO,MAAM,KAAA,KAAa,UAAU,GAAG,UAAU,KAAK;EACxD,KAAK,OACH,OAAO,MAAM,KAAA,KAAa,CAAC,UAAU,GAAG,UAAU,KAAK;EACzD,KAAK,MACH,OAAO,OAAO,MAAM,YAAY,IAAI,UAAU;EAChD,KAAK,OACH,OAAO,OAAO,MAAM,YAAY,KAAK,UAAU;EACjD,KAAK,MACH,OAAO,OAAO,MAAM,YAAY,IAAI,UAAU;EAChD,KAAK,OACH,OAAO,OAAO,MAAM,YAAY,KAAK,UAAU;EACjD,KAAK,MACH,OAAO,MAAM,KAAA,KAAa,UAAU,MAAM,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC;EACvE,KAAK,WACH,OAAO,MAAM,KAAA,KAAa,MAAM;CACpC;AACF;;AAGA,SAAgB,UAAU,KAAgB,OAA+C;CACvF,MAAM,SAAS,aAAa,KAAK,MAAM,MAAM;CAC7C,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,MAAM,OAAO,OAAO,MAAM,UAAU,CAAC;CACrC,MAAM,QAAQ,MAAM,SAAS,CAAC;CAC9B,OAAO,KAAK,QAAQ,MAAM,MAAM,OAAO,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC;AAChE;AAEA,SAAS,YAAY,KAAgB,QAA0B;CAC7D,IAAI;CACJ,KAAK,MAAM,KAAK,IAAI,SAAS,IAAI,EAAE,SAAS,cAAc,EAAE,WAAW,QAAQ,OAAO,EAAE;CACxF,OAAO,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI;AACxC;;AAYA,SAAgB,cAAc,GAAc,GAAuB;CACjE,OACE,EAAE,cAAc,EAAE,aAClB,EAAE,KAAK,WAAW,EAAE,KAAK,UACzB,EAAE,KAAK,OAAO,GAAG,MAAM,MAAM,EAAE,KAAK,EAAE;AAE1C;;AAGA,SAAgB,QAAQ,OAAkB,MAAqC;CAC7E,IAAI,MAA6B;CACjC,IAAI,SAAS,IAAI,OAAO;CACxB,KAAK,MAAM,QAAQ,KAAK,MAAM,GAAG,GAAG;EAClC,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU,OAAO,KAAA;EACpD,IAAI,MAAM,QAAQ,GAAG,GAAG;GACtB,MAAM,IAAI,OAAO,IAAI;GACrB,IAAI,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,GAAG,OAAO,KAAA;GAC1C,MAAM,IAAI;EACZ,OACE,MAAO,IAA4C;EAErD,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;CAChC;CACA,OAAO;AACT;AAEA,SAAS,UAAU,GAA0B,GAAuB;CAClE,IAAI,MAAM,KAAA,GAAW,OAAO;CAC5B,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,MAAM,QAAQ,MAAM,QAAQ,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,OAAO;CACvF,IAAI,MAAM,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,GAAG,OAAO;CAClD,IAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,GACrC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,UAAU,GAAG,EAAE,EAAe,CAAC;CAEnF,MAAM,KAAK;CACX,MAAM,KAAK;CACX,MAAM,KAAK,OAAO,KAAK,EAAE,CAAC,CAAC,KAAK;CAChC,MAAM,KAAK,OAAO,KAAK,EAAE,CAAC,CAAC,KAAK;CAChC,OACE,GAAG,WAAW,GAAG,UACjB,GAAG,OAAO,GAAG,MAAM,MAAM,GAAG,MAAM,UAAU,GAAG,IAAI,GAAG,EAAe,CAAC;AAE1E;AAEA,SAAgB,QAAQ,QAAsB,KAA8B;CAC1E,IAAI,OAAO,WAAW,IAAI,QAAQ,OAAO;CACzC,IAAI,IAAI,OAAO,KAAA,KAAa,OAAO,OAAO,IAAI,IAAI,OAAO;CACzD,IAAI,IAAI,SAAS,KAAA,KAAa,OAAO,SAAS,IAAI,MAAM,OAAO;CAC/D,IAAI,IAAI,OACD;OAAA,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,IAAI,KAAK,GACjD,IAAI,CAAC,UAAU,QAAQ,OAAO,SAAS,IAAI,GAAG,IAAI,GAAG,OAAO;CAAA;CAGhE,IAAI,IAAI,SACN,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,IAAI,OAAO,GAAG;EACrD,MAAM,IAAI,QAAQ,OAAO,SAAS,IAAI;EACtC,IAAI,OAAO,MAAM,YAAY,IAAI,KAAK,OAAO;CAC/C;CAEF,OAAO;AACT;AAEA,SAAgB,cAAc,KAAgB,KAA8C;CAC1F,OAAO,IAAI,QAAQ,QAAQ,MAAM,QAAQ,GAAG,GAAG,CAAC;AAClD;;AAGA,SAAS,MAAM,QAAsB,MAAkC;CACrE,MAAM,IAAI,QAAQ,OAAO,SAAS,IAAI;CACtC,OAAO,MAAM,KAAA,IAAY,KAAA,IAAY,cAAc,CAAC;AACtD;AAEA,SAAgB,eAAe,KAAgB,KAAkC;CAC/E,QAAQ,IAAI,MAAZ;EACE,KAAK,YACH,OAAO,cAAc,KAAK,GAAG;EAC/B,KAAK,WACH,OAAO,aAAa,KAAK,GAAG;EAC9B,KAAK,oBAAoB;GACvB,MAAM,uBAAO,IAAI,IAAoB;GACrC,KAAK,MAAM,KAAK,cAAc,KAAK,IAAI,MAAM,GAAG;IAC9C,MAAM,IAAI,MAAM,GAAG,IAAI,GAAG;IAC1B,IAAI,MAAM,KAAA,GAAW;IACrB,MAAM,QAAQ,KAAK,IAAI,CAAC;IACxB,IAAI,UAAU,KAAA,GACZ,OAAO;KACL,WAAW,IAAI;KACf,SAAS,GAAG,IAAI,OAAO,OAAO,GAAG,IAAI,OAAO,MAAM,IAAI,0BAA0B,EAAE,QAAQ,MAAM,OAAO,EAAE,IAAI;KAC7G,MAAM,CAAC,CAAC;KACR,UAAU,CAAC,OAAO,EAAE,GAAG;IACzB;IAEF,KAAK,IAAI,GAAG,EAAE,GAAG;GACnB;GACA,OAAO;EACT;EACA,KAAK,eAAe;GAClB,MAAM,0BAAU,IAAI,IAAY;GAChC,MAAM,WAAW,cAAc,KAAK,IAAI,MAAM;GAC9C,KAAK,MAAM,KAAK,UAAU;IACxB,MAAM,IAAI,MAAM,GAAG,IAAI,GAAG;IAC1B,IAAI,MAAM,KAAA,GAAW,QAAQ,IAAI,CAAC;GACpC;GACA,MAAM,UAAU,IAAI,SAAS,KAAK,MAAM,cAAc,CAAC,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;GACvF,IAAI,QAAQ,WAAW,GAAG,OAAO;GACjC,OAAO;IACL,WAAW,IAAI;IACf,SAAS,GAAG,IAAI,OAAO,OAAO,GAAG,IAAI,OAAO,MAAM,IAAI,6BAA6B,QAAQ,KAAK,IAAI;IACpG,MAAM;IACN,UAAU,SAAS,KAAK,MAAM,EAAE,GAAG;GACrC;EACF;CACF;AACF;AAEA,SAAS,cAAc,KAAgB,KAAiC;CACtE,MAAM,OAAO,UAAU,KAAK,IAAI,KAAK;CACrC,IAAI,SAAS,KAAA,GACX,OAAO;EACL,WAAW,IAAI;EACf,SAAS,kBAAkB,IAAI,MAAM,OAAO;EAC5C,MAAM,CAAC;EACP,UAAU,CAAC;CACb;CAEF,MAAM,UAAU,KAAK,QAAQ,MAAM,CAAC,IAAI,MAAM,OAAO,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC;CAC5E,IAAI,QAAQ,WAAW,GAAG,OAAO;CACjC,MAAM,OAAO,QAAQ,KAAK,MAAM,cAAc,CAAC,CAAC;CAChD,MAAM,QAAQ,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,QAAQ,SAAS,IAAI,QAAQ;CAC1E,OAAO;EACL,WAAW,IAAI;EACf,SAAS,GAAG,QAAQ,OAAO,aAAa,IAAI,MAAM,MAAM,MAAM,IAAI,MAAM,OAAO,0BAA0B;EACzG;EACA,UAAU,YAAY,KAAK,IAAI,MAAM,MAAM;CAC7C;AACF;AAEA,SAAS,aAAa,KAAgB,KAAgC;CACpE,MAAM,OAAO,UAAU,KAAK,IAAI,KAAK;CACrC,IAAI,SAAS,KAAA,GACX,OAAO;EACL,WAAW,IAAI;EACf,SAAS,kBAAkB,IAAI,MAAM,OAAO;EAC5C,MAAM,CAAC;EACP,UAAU,CAAC;CACb;CAEF,MAAM,0BAAU,IAAI,IAAY;CAChC,KAAK,MAAM,KAAK,MAAM;EACpB,MAAM,IAAI,EAAE,IAAI;EAChB,IAAI,MAAM,KAAA,GAAW,QAAQ,IAAI,cAAc,CAAC,CAAC;CACnD;CACA,MAAM,UAAoB,CAAC;CAC3B,MAAM,WAAqB,CAAC;CAC5B,KAAK,MAAM,KAAK,cAAc,KAAK,IAAI,IAAI,GAAG;EAC5C,MAAM,IAAI,MAAM,GAAG,IAAI,GAAG;EAC1B,IAAI,MAAM,KAAA,KAAa,QAAQ,IAAI,CAAC,GAAG;EACvC,IAAI,CAAC,QAAQ,SAAS,CAAC,GAAG,QAAQ,KAAK,CAAC;EACxC,SAAS,KAAK,EAAE,GAAG;CACrB;CACA,IAAI,QAAQ,WAAW,GAAG,OAAO;CACjC,OAAO;EACL,WAAW,IAAI;EACf,SAAS,GAAG,IAAI,KAAK,OAAO,GAAG,IAAI,KAAK,MAAM,IAAI,uBAAuB,QAAQ,KAAK,IAAI,EAAE,OAAO,IAAI,MAAM,MAAM,GAAG,IAAI,OAAO,MAAM,IAAI,MAAM,OAAO;EACxJ,MAAM;EACN;CACF;AACF;AAEA,SAAgB,gBACd,KACA,YACsB;CACtB,MAAM,MAAmB,CAAC;CAC1B,KAAK,MAAM,OAAO,YAAY;EAC5B,MAAM,IAAI,eAAe,KAAK,GAAG;EACjC,IAAI,GAAG,IAAI,KAAK,CAAC;CACnB;CACA,OAAO;AACT;;ACzQA,MAAa,gBAAwB;CACnC,iBAAiB;CACjB,iBAAiB;CACjB,0BAA0B;CAC1B,UAAU;AACZ;AAEA,SAAS,cAAc,GAAyB;CAC9C,OAAO,OAAO,MAAM,YAAY,OAAO,UAAU,CAAC,KAAK,IAAI;AAC7D;;AAGA,SAAgB,iBAAiB,MAAuC;CACtE,MAAM,SAAmB,CAAC;CAC1B,IAAI,KAAK,YAAY,GAAG,OAAO,KAAK,0BAA0B,OAAO,KAAK,OAAO,GAAG;CACpF,IAAI,CAAC,KAAK,KAAK,KAAK,GAAG,OAAO,KAAK,wBAAwB;CAC3D,IAAI,KAAK,aAAa,KAAA,KAAa,CAAC,KAAK,UACvC,OAAO,KAAK,uCAAuC;CACrD,IAAI,CAAC,uBAAuB,KAAK,KAAK,IAAI,GACxC,OAAO,KAAK,sDAAsD,KAAK,UAAU,KAAK,IAAI,GAAG;CAC/F,IAAI,CAAC,KAAK,OAAO,OAAO,OAAO,KAAK,gCAAgC;CACpE,IAAI,CAAC,KAAK,OAAO,QAAQ,OAAO,KAAK,iCAAiC;CACtE,IAAI,CAAC,KAAK,MAAM,MAAM,OAAO,KAAK,8BAA8B;CAChE,KAAK,MAAM,SAAS,GAAG,MAAM;EAC3B,IAAI,CAAC,EAAE,MAAM,OAAO,KAAK,SAAS,EAAE,yBAAyB;CAC/D,CAAC;CACD,IAAI,KAAK,WAAW,WAAW,GAAG,OAAO,KAAK,oCAAoC;CAClF,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,OAAO,KAAK,YAAY;EACjC,IAAI,CAAC,IAAI,MAAM,OAAO,KAAK,8BAA8B;OACpD,IAAI,MAAM,IAAI,IAAI,IAAI,GACzB,OAAO,KAAK,4BAA4B,KAAK,UAAU,IAAI,IAAI,GAAG;EACpE,MAAM,IAAI,IAAI,IAAI;CACpB;CACA,MAAM,sBAAM,IAAI,IAAY;CAC5B,KAAK,MAAM,KAAK,KAAK,WAAW;EAC9B,IAAI,CAAC,EAAE,MAAM,OAAO,KAAK,6BAA6B;EACtD,IAAI,IAAI,IAAI,EAAE,IAAI,GAAG,OAAO,KAAK,sBAAsB,KAAK,UAAU,EAAE,IAAI,GAAG;EAC/E,IAAI,IAAI,EAAE,IAAI;EACd,IAAI,CAAC,EAAE,MAAM,OAAO,KAAK,YAAY,KAAK,UAAU,EAAE,IAAI,EAAE,cAAc;EAC1E,CAAC,EAAE,aAAa,CAAC,EAAA,CAAG,SAAS,GAAG,MAAM;GACpC,IAAI,EAAE,OAAO,UAAU,EAAE,MAAM,KAAK,EAAE,UAAU,OAAO,EAAE,UAAU,MACjE,OAAO,KACL,YAAY,KAAK,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,gCACpD;EAEJ,CAAC;CACH;CACA,KAAK,MAAM,KAAK;EACd;EACA;EACA;EACA;CACF,GACE,IAAI,MAAM,qBAAqB,MAAM,mBAAmB;EACtD,MAAM,IAAI,KAAK,OAAO;EACtB,IAAI,EAAE,OAAO,UAAU,CAAC,KAAK,KAAK,IAChC,OAAO,KAAK,UAAU,EAAE,gCAAgC;CAC5D,OAAO,IAAI,CAAC,cAAc,KAAK,OAAO,EAAE,GACtC,OAAO,KAAK,UAAU,EAAE,4BAA4B;CAExD,OAAO;AACT;;;AC7HA,SAAgB,iBAAiB,OAA4C;CAC3E,MAAM,MAAqB,CAAC;CAC5B,MAAM,SAAS,OAAO,SAAS,GAAG,MAAM;EACtC,IAAI,KAAK;GACP,UAAU;IACR,MAAM,MAAM,SAAS;IACrB,QAAQ,MAAM,SAAS,OAAO,QAAQ,GAAG,MAAM,MAAM,CAAC;GACxD;GACA,SAAS,MAAM;EACjB,CAAC;CACH,CAAC;CACD,IAAI,MAAM,QAAQ,SAAS,GACzB,MAAM,QAAQ,SAAS,OAAO;EAC5B,IAAI,KAAK;GACP,UAAU;IACR,MAAM,MAAM,SAAS;IAErB,QAAQ,MAAM,SAAS,OAAO,QAAQ,MAAM,CAAC,EAAE,WAAW,WAAW,GAAG,GAAG,EAAE,CAAC;GAChF;GACA,SAAS,MAAM,QAAQ,QAAQ,MAAM,MAAM,EAAE;EAC/C,CAAC;CACH,CAAC;CAEH,OAAO;AACT;;;;;;;;;;;;AC1BA,MAAa,eAAe,KAAK,IAAI,MAAM,GAAG,CAAC;AAM/C,MAAM,iBAAiB,WAAW,WAAW,KAAK,UAAU;AAC5D,MAAM,kBAAkB,WAAW,YAAY,KAAK,UAAU;AAC9D,MAAM,mBAAmB,WAAW,aAAa,KAAK,UAAU;AAChE,MAAM,oBAAoB,WAAW,cAAc,KAAK,UAAU;AAclE,MAAM,sBAA2C;CAC/C,MAAM,MACJ,OAAO,YAAY,cACd,SAAS,mBAAmB,kBAAkB,IAG/C,KAAA;CACN,OAAO,KAAK,oBAAoB,IAAI,IAAI,kBAAkB,IAAI;AAChE,EAAA,CAAG;AAYH,IAAa,eAAb,MAA0B;CACxB,OAAe;CACf,SAA0B,CAAC;CAC3B,SAAiB;;CAEjB,QAAuB;CAEvB,MAAc;EACZ,OAAO,KAAK;CACd;CAEA,QAAQ,IAAkB;EACxB,IAAI,KAAK,GAAG,KAAK,QAAQ;CAC3B;CAEA,SACE,UACA,OACA,MACA,UACQ;EACR,MAAM,KAAK,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,KAAK,MAAM,KAAK,IAAI;EACrE,MAAM,QAAe;GACnB,IAAI,KAAK;GACT,KAAK,KAAK,OAAO;GACjB;GACA;GACA;GACA,OAAO,KAAK;EACd;EACA,KAAK,OAAO,KAAK,KAAK;EACtB,OAAO,MAAM;CACf;CAEA,WAAW,UAAwC,QAAQ,GAAG,GAAG,MAAyB;EACxF,OAAO,KAAK,SAAS,UAAU,OAAO,MAAM,IAAI;CAClD;CAEA,YAAY,UAAwC,QAAQ,GAAG,GAAG,MAAyB;EACzF,OAAO,KAAK,SAAS,UAAU,OAAO,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC;CAC5E;CAEA,MAAM,IAAkB;EACtB,KAAK,SAAS,KAAK,OAAO,QAAQ,MAAM,EAAE,OAAO,EAAE;CACrD;;CAGA,KAAK,IAA2B;EAC9B,OAAO,OAAO,OAAO,YAAY,KAAK,OAAO,MAAM,MAAM,EAAE,OAAO,EAAE;CACtE;CAEA,gBAAwB;EACtB,OAAO,KAAK,OAAO;CACrB;;CAGA,YAAY,OAAqB;EAC/B,KAAK,SAAS,KAAK,OAAO,QAAQ,MAAM,EAAE,UAAU,KAAK;CAC3D;;CAGA,WAAoB;EAClB,IAAI,KAAK,OAAO,WAAW,GAAG,OAAO;EACrC,IAAI,WAAW,KAAK,OAAO;EAC3B,KAAK,MAAM,KAAK,KAAK,QACnB,IAAI,EAAE,MAAM,SAAS,OAAQ,EAAE,QAAQ,SAAS,OAAO,EAAE,KAAK,SAAS,IAAK,WAAW;EACzF,IAAI,SAAS,MAAM,KAAK,MAAM,KAAK,OAAO,SAAS;EACnD,IAAI,SAAS,aAAa,MAAM,KAAK,SAAS,KAAK,OAAO,QAAQ,MAAM,MAAM,QAAQ;OACjF,SAAS,MAAM,KAAK,OAAO,SAAS;EACzC,IAAI;GACF,SAAS,SAAS,GAAG,SAAS,IAAI;EACpC,QAAQ,CAER;EACA,OAAO;CACT;AACF;;AAGA,IAAa,gBAAb,MAA2B;CACzB;CAEA,YAAY,MAAuB;EACjC,KAAK,QAAQ,SAAS,UAAU,MAAM;CACxC;CAEA,QAAgB;EACd,MAAM,CAAC,GAAG,QAAQ,UAAU,KAAK,KAAK;EACtC,KAAK,QAAQ;EACb,OAAO;CACT;CAEA,MAAc;EACZ,MAAM,CAAC,GAAG,QAAQ,QAAQ,KAAK,KAAK;EACpC,KAAK,QAAQ;EACb,OAAO;CACT;CAEA,KAAgC,MAAY;EAC1C,MAAM,QAAQ,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;EAC1E,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;GACxC,MAAM,IAAI,KAAK,IAAI;GACnB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IAAI,IAAI,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAM,MAAO,IAAI,IAAM;EACvF;EACA,OAAO;CACT;;CAGA,OAAe;EACb,MAAM,IAAI,KAAK,qBAAK,IAAI,WAAW,EAAE,CAAC;EACtC,EAAE,KAAO,EAAE,KAAgB,KAAQ;EACnC,EAAE,KAAO,EAAE,KAAgB,KAAQ;EACnC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;EACtE,OAAO,GAAG,IAAI,MAAM,GAAG,CAAC,EAAE,GAAG,IAAI,MAAM,GAAG,EAAE,EAAE,GAAG,IAAI,MAAM,IAAI,EAAE,EAAE,GAAG,IAAI,MAAM,IAAI,EAAE,EAAE,GAAG,IAAI,MAAM,EAAE;CACzG;AACF;;AAkBA,SAAgB,aAAa,MAAgC;CAC3D,MAAM,QAAQ,IAAI,aAAa;CAC/B,MAAM,SAAS,IAAI,cAAc,IAAI;CACrC,MAAM,IAAI;CACV,MAAM,wBAAQ,IAAI,IAA4C;CAC9D,MAAM,UAAU,QAAgB,KAAa,UAAyB;EACpE,MAAM,QAAQ,WAAW,IAAI,IAAI;EACjC,MAAM,IAAI,KAAK,OAAO,yBAAyB,OAAO,GAAG,CAAC;EAC1D,OAAO,eAAe,OAAO,KAAK;GAChC;GACA,cAAc;GACd,UAAU;GACV,YAAY;EACd,CAAC;CACH;CAEA,MAAM,WAAW;CACjB,MAAM,cAAc,SAAyB,GAAG,MAA0B;EACxE,IAAI,eAAe,KAAA,GAAW,OAAO,IAAI,SAAS,MAAM,IAAI,CAAC,CAAC,CAAC,SAAS;EACxE,OAAO,QAAQ,UAAU,UAAU,KAAK,WAAW,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,MAAM,UAAU;CACzF;CACA,OAAO,eAAe,aAAa,QAAQ;CAC3C,OAAO,eAAe,aAAa,aAAa;EAAE,OAAO,SAAS;EAAW,UAAU;CAAM,CAAC;CAC9F,OAAO,eAAe,aAAa,OAAO;EACxC,aAAa,MAAM,IAAI;EACvB,cAAc;EACd,UAAU;CACZ,CAAC;CACD,OAAO,eAAe,aAAa,QAAQ,EAAE,OAAO,OAAO,CAAC;CAE5D,OAAO,GAAG,QAAQ,WAAW;CAC7B,OAAO,MAAM,gBAAgB,OAAO,MAAM,CAAC;CAC3C,MAAM,kBAAkB,cAAc,SAAS,MAAM;CACrD,OAAO,GAAG,eAAe,IAA+B,IAAa,GAAG,SACtE,UAAU,IAAI,eAAe,IAAI,IAAI,GAAG,IAAI,IAAI,MAAM,WAAW,IAAI,IAAI,GAAG,IAAI,CAClF;CACA,OAAO,GAAG,gBAAgB,IAA+B,IAAa,GAAG,SACvE,UAAU,IAAI,gBAAgB,IAAI,IAAI,GAAG,IAAI,IAAI,MAAM,YAAY,IAAI,IAAI,GAAG,IAAI,CACpF;CAGA,OAAO,GAAG,iBAAiB,OAAiB;EAC1C,IAAI,MAAM,KAAK,EAAE,GAAG,MAAM,MAAM,EAAE;OAC7B,iBAAiB,EAA4C;CACpE,CAAC;CACD,OAAO,GAAG,kBAAkB,OAAiB;EAC3C,IAAI,MAAM,KAAK,EAAE,GAAG,MAAM,MAAM,EAAE;OAC7B,kBAAkB,EAA6C;CACtE,CAAC;CACD,MAAM,OAAO,EAAE;CACf,IAAI,QAAQ,OAAO,SAAS,UAAU,OAAO,MAAM,aAAa,MAAM,IAAI,IAAI,YAAY;CAC1F,MAAM,YAAY,EAAE;CACpB,IAAI,aAAa,OAAO,cAAc,UAAU;EAC9C,OAAO,WAAW,oBAAoB,OAAO,KAAK,CAAC;EACnD,OAAO,WAAW,oBAA+C,SAAY,OAAO,KAAK,IAAI,CAAC;CAChG;CAEA,IAAI,WAAW;CACf,MAAM,UAAkC;EACtC,MAAM;EACN,QAAQ;EACR,YAAY;EACZ,aAAa;EACb,cAAc;EACd,eAAe;CACjB;CACA,IAAI,QAAQ,OAAO,SAAS,UAAU,QAAQ,SAAS;CACvD,IAAI,aAAa,OAAO,cAAc,UAAU;EAC9C,QAAQ,gBAAgB;EACxB,QAAQ,qBAAqB;CAC/B;CACA,OAAO;EACL;EACA;EACA,UAAa,SAAuC;GAClD,OAAO,eAAe,aAAa,IAAI,MAAM,OAAO,IAAI,QAAQ;EAClE;EACA,UAAU;GACR,IAAI,UAAU;GACd,WAAW;GACX,KAAK,MAAM,CAAC,KAAK,eAAe,OAAO;IACrC,MAAM,SAAS,QAAQ;IACvB,IAAI,YAAY,OAAO,eAAe,QAAQ,KAAK,UAAU;SACxD,OAAQ,OAAkB;GACjC;EACF;CACF;AACF;;AAGA,SAAgB,WAA0B;CACxC,OAAO,IAAI,SAAS,YAAY,qBAAqB,QAAQ,GAAG,CAAC,CAAC;AACpE;;;;;AAgBA,eAAsB,SAAY,SAAqB,KAAgC;CACrF,IAAI,OAAO;CACX,IAAI,SAAS;CACb,IAAI;CACJ,IAAI;CACJ,MAAM,UAAU,QAAQ,MACrB,MAAM;EACL,OAAO;EACP,QAAQ;CACV,IACC,MAAe;EACd,OAAO;EACP,SAAS;EACT,QAAQ;CACV,CACF;CACA,SAAS;EACP,MAAM,QAAQ,KAAK,CAAC,SAAS,SAAS,CAAC,CAAC;EACxC,IAAI,MAAM;GACR,IAAI,QAAQ,MAAM;GAClB,OAAO;EACT;EACA,IAAI,IAAI,QAAQ,GAAG,OAAO,IAAI,cAAiB,CAAC,CAAC;EACjD,IAAI,IAAI,SAAS,IAAI,GAAG;EACxB,IAAI,IAAI,MAAM,SAAS,GAAG;EAC1B,IAAI,MAAM;EACV,OAAO,IAAI,cAAiB,CAAC,CAAC;CAChC;AACF;;ACtTA,MAAM,SAA+B;CAAC;CAAgB;CAAe;CAAa;AAAO;;AAQzF,SAAgB,YAAY,SAAiB,MAAuB;CAClE,IAAI,QAAQ,WAAW,IAAI,GAAG;EAC5B,MAAM,SAAS,QAAQ,MAAM,CAAC;EAC9B,OAAO,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,OAAO;CACvD;CACA,OAAO,YAAY;AACrB;AAEA,SAAgB,aACd,WACA,MAC0B;CAC1B,OAAO,UAAU,MAAM,MAAM,YAAY,EAAE,MAAM,IAAI,CAAC;AACxD;AAEA,SAAgB,aACd,UACA,QACA,MACqC;CACrC,IAAI,CAAC,SAAS,WAAW,OAAO;CAChC,OAAO,SAAS,UAAU,MAAM,MAAM;EACpC,IAAI,EAAE,UAAU,EAAE,OAAO,YAAY,MAAM,QAAQ,OAAO;EAC1D,IAAI,EAAE,SAAS,KAAA,GAAW,OAAO;EACjC,OAAO,EAAE,KAAK,SAAS,GAAG,IAAI,KAAK,WAAW,EAAE,KAAK,MAAM,GAAG,EAAE,CAAC,IAAI,EAAE,SAAS;CAClF,CAAC;AACH;AAQA,MAAM,4BAAY,IAAI,IAAI;CAAC;CAAK;CAAK;CAAK;CAAK;AAAG,CAAC;AAEnD,SAAS,QAAQ,GAAmC;CAClD,IAAI,MAAM,MAAM,OAAO;EAAE,QAAQ;EAAK,SAAS,CAAC;EAAG,MAAM;CAAG;CAC5D,MAAM,OAAO,EAAE,SAAS,KAAA,KAAa,OAAO,EAAE,SAAS;CACvD,MAAM,UAAkC,CAAC;CACzC,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,EAAE,WAAW,CAAC,CAAC,GAAG,QAAQ,KAAK,YAAY,KAAK;CAC3F,IAAI,QAAQ,EAAE,kBAAkB,UAAU,QAAQ,kBAAkB;CACpE,MAAM,OAAO,EAAE,SAAS,KAAA,IAAY,KAAK,OAAO,KAAK,UAAU,EAAE,IAAI,IAAK,EAAE;CAC5E,OAAO;EAAE,QAAQ,EAAE;EAAQ;EAAS;CAAK;AAC3C;AAEA,SAAS,WAAW,OAAwB;CAC1C,OAAO,IAAI,SAAS,MAAM,SAAS,KAAK,OAAO,MAAM,MAAM;EACzD,QAAQ,MAAM;EACd,SAAS,MAAM;CACjB,CAAC;AACH;AAEA,SAAS,UAAU,MAAyB;CAC1C,IAAI,SAAS,IAAI,OAAO;CACxB,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,QAAQ;EACN,OAAO;CACT;AACF;;;;;;AAaA,SAAgB,oBACd,WACA,OACA,aAEA,qBAAiC,CAAC,GACnB;CACf,MAAM,yBAAS,IAAI,IAAmB;CAEtC,MAAM,YAAY,OAAO,OAA0B,SAA0C;EAC3F,MAAM,UAAU,IAAI,QAAQ,OAAO,IAAI;EACvC,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;EAC/B,MAAM,SAAS,QAAQ,OAAO,YAAY;EAC1C,MAAM,WAAW,aAAa,WAAW,IAAI,IAAI;EACjD,IAAI,CAAC,UAAU;GACb,YACE,4BAA4B,IAAI,KAAK,4CACvC;GACA,MAAM,IAAI,UAAU,iBAAiB,IAAI,KAAK,4BAA4B;EAC5E;EACA,MAAM,UAAkC,CAAC;EACzC,QAAQ,QAAQ,SAAS,OAAO,SAAS;GACvC,QAAQ,KAAK,YAAY,KAAK;EAChC,CAAC;EACD,MAAM,eAAe,SAAS,WAAW,UAAU,YAAY;EAC/D,MAAM,YAAY,eAAgB,QAAQ,iBAAiB,OAAQ;EACnE,MAAM,OAAO,UAAU,MAAM,QAAQ,KAAK,CAAC;EAC3C,MAAM,OAAkB;GAAE,KAAK,QAAQ;GAAK;GAAQ;GAAS;GAAM;EAAU;EAE7E,MAAM,UAAU,YAA2D;GACzE,MAAM,OAAO,cAAc,OAAO,OAAO,GAAG,SAAS,KAAK,QAAQ;GAClE,IAAI,SAAS,MAAM;IACjB,MAAM,UAAU,OAAO,IAAI,IAAI;IAC/B,IAAI,SAAS,OAAO;KAAE,OAAO;KAAS,WAAW;IAAM;GACzD;GACA,MAAM,SAAS,aAAa,UAAU,QAAQ,IAAI,QAAQ;GAC1D,IAAI,WAAW,KAAA,GAAW;IACxB,YACE,oCAAoC,SAAS,KAAK,OAAO,OAAO,GAAG,IAAI,UACzE;IACA,MAAM,IAAI,UAAU,0CAA0C,OAAO,GAAG,IAAI,UAAU;GACxF;GACA,MAAM,QAAQ,QAAQ,MAAM;GAC5B,IAAI,UAAU,IAAI,MAAM,MAAM,KAAK,QAAQ,aAAa,UAAU;IAChE,YACE,YAAY,SAAS,KAAK,WAAW,OAAO,GAAG,IAAI,SAAS,UAAU,MAAM,OAAO,mEACrF;IACA,MAAM,IAAI,UACR,6CAA6C,MAAM,OAAO,QAAQ,IAAI,KAAK,EAC7E;GACF;GACA,IAAI,SAAS,MAAM,OAAO,IAAI,MAAM,KAAK;GACzC,OAAO;IAAE;IAAO,WAAW;GAAK;EAClC;EAEA,IAAI,CAAC,OAAO;GACV,MAAM,EAAE,UAAU,MAAM,QAAQ;GAChC,aAAa;GACb,OAAO,WAAW,KAAK;EACzB;EACA,MAAM,EAAE,UAAU,MAAM,MAAM,MAAM,OAClC;GACE,YAAY,MAAM,WAAW;GAC7B,QAAQ,SAAS,SAAS;GAC1B,IAAI;GACJ;GACA,SAAS;EACX,GACA,UACC,OAAO;GAAE,QAAQ,EAAE,MAAM;GAAQ,WAAW,EAAE;GAAW;EAAU,EACtE;EACA,OAAO,WAAW,KAAK;CACzB;CAEA,OAAO;EAAE,OAAO;EAAU;CAAO;AACnC;;AAGA,SAAgB,qBACd,WACA,OACA,aACA,cACY;CACZ,MAAM,IAAI;CACV,MAAM,QAAQ,OAAO,yBAAyB,YAAY,OAAO;CACjE,MAAM,EAAE,OAAO,aAAa,oBAAoB,WAAW,OAAO,aAAa,YAAY;CAC3F,OAAO,eAAe,YAAY,SAAS;EACzC,OAAO;EACP,cAAc;EACd,UAAU;CACZ,CAAC;CACD,IAAI,WAAW;CACf,aAAa;EACX,IAAI,UAAU;EACd,WAAW;EACX,IAAI,OAAO,OAAO,eAAe,YAAY,SAAS,KAAK;OACtD,OAAQ,EAA0B;CACzC;AACF;;;;;;;;;ACvKA,IAAa,cAAb,cAAiC,MAAM;CACrC,OAAyB;CACzB;CACA,YAAY,YAAoB;EAC9B,MAAM,cAAc,WAAW,8BAA8B;EAC7D,KAAK,aAAa;CACpB;AACF;;AAGA,IAAa,sBAAb,cAAyC,MAAM;CAC7C,OAAyB;CACzB;CACA;CACA,YAAY,OAAoB,OAAkB;EAChD,MAAM,GAAG,MAAM,OAAO,GAAG,MAAM,GAAG,oBAAoB,MAAM,EAAE;EAC9D,KAAK,QAAQ;EACb,KAAK,QAAQ;CACf;AACF;AASA,IAAM,kBAAN,MAA4C;CAC1C;CACA;;CAEA,UAAU;CACV,cAAsB;CACtB,uBAA2C,CAAC;CAC5C;CAEA,YAAY,IAAY,SAAqB;EAC3C,KAAK,KAAK;EACV,KAAK,UAAU;EACf,KAAK,UAAU,IAAI,SAAe,YAAY;GAC5C,KAAK,iBAAiB;EACxB,CAAC;CACH;CAEA,YAAqB;EACnB,OAAO,KAAK;CACd;CAEA,QAAc;EACZ,IAAI,KAAK,aAAa;EACtB,KAAK,cAAc;EACnB,KAAK,QAAQ;EACb,KAAK,eAAe;CACtB;AACF;;AAGA,SAAS,OAAsB;CAC7B,OAAO,IAAI,cAAiB,CAAC,CAAC;AAChC;AAEA,IAAa,MAAb,MAAqC;CACnC,WAA8B;CAC9B,SAA2C,CAAC;CAC5C,cAAsB;CACtB;CACA,8BAA+B,IAAI,IAA6B;CAChE,UAAqC,CAAC;CACtC,WAAmB;CACnB,UAAkC;CAClC,eAA4C;;CAE5C,UAAkB;CAElB;CAEA,YAAY,SAAqB;EAC/B,KAAK,UAAU;EACf,KAAK,OAAO,SAAS,QAAQ,SAAS,IAAI;CAC5C;CAEA,IAAI,MAAiB;EACnB,OAAO,KAAK;CACd;;CAGA,IAAI,WAAqB;EACvB,OAAO;GAAE,MAAM,KAAK,QAAQ,SAAS;GAAM,QAAQ,CAAC,GAAG,KAAK,MAAM;EAAE;CACtE;CAEA,IAAI,eAAuB;EACzB,OAAO,KAAK;CACd;CAEA,IAAI,iBAAyB;EAC3B,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,qBAAwC;EAC1C,OAAO,KAAK;CACd;;CAGA,QAAQ,YAAqC,CAAC,GAAS;EACrD,IAAI,CAAC,KAAK,SAAS,KAAK,UAAU,aAAa,KAAK,QAAQ,SAAS,IAAI;EACzE,IAAI,CAAC,KAAK,cACR,KAAK,eAAe,qBAClB,WACA;GAAE,OAAO;GAAM,kBAAkB,KAAK;EAAQ,IAC7C,WAAW,KAAK,YAAY,MAAM,CACrC;CAEJ;CAEA,YAAkB;EAChB,KAAK,eAAe;EACpB,KAAK,eAAe;EACpB,KAAK,SAAS,QAAQ;EACtB,KAAK,UAAU;CACjB;;CAGA,MAAc;EACZ,OAAO,KAAK,UAAU,KAAK,QAAQ,MAAM,IAAI,IAAI,KAAK,IAAI;CAC5D;;CAGA,gBAAwB;EACtB,OAAO,KAAK,SAAS,MAAM,cAAc,KAAK;CAChD;CAEA,gBAAgB,IAAwB;EACtC,IAAI,KAAK,YAAY,IAAI,EAAE,GAAG,MAAM,IAAI,MAAM,cAAc,GAAG,iBAAiB;EAChF,MAAM,MAAM,IAAI,gBAAgB,UAAU,KAAK,SAAS,MAAM,YAAY,EAAE,CAAC;EAC7E,KAAK,YAAY,IAAI,IAAI,GAAG;EAC5B,IAAI,KAAK,SAAS,KAAK,QAAQ,MAAM,QAAQ;EAC7C,KAAK,UAAU;EACf,OAAO;CACT;CAEA,WAAmB,IAA6B;EAC9C,MAAM,MAAM,KAAK,YAAY,IAAI,EAAE;EACnC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,kCAAkC,IAAI;EAChE,OAAO;CACT;CAEA,OAAe,OAAoB,SAAmC;EACpE,IAAI,KAAK,QAAQ,SAAS,UAAU;GAClC,MAAM,IAAI,KAAK,QAAQ,SAAS,OAAO,MACpC,MAAM,EAAE,eAAe,MAAM,cAAc,EAAE,YAAY,OAC5D;GACA,OAAO,KAAK,MAAM,QAAQ,SAAS,EAAE,KAAK,IAAI,EAAE,QAAQ;EAC1D;EACA,MAAM,CAAC,OAAO,QAAQ,YAAY,KAAK,MAAM,MAAM,SAAS,KAAK,OAAO,QAAQ;GAC9E,iBAAiB,KAAK,QAAQ,OAAO;GACrC,kBAAkB,KAAK,QAAQ;EACjC,CAAC;EACD,KAAK,OAAO;EACZ,OAAO;CACT;CAEA,OAAe,OAAoB,MAAmC,SAA0B;EAC9F,KAAK,WAAW,aAAa,KAAK,UAAU;GAC1C;GACA,YAAY,MAAM;GAClB,QAAQ,MAAM;GACd,IAAI,MAAM;GACV;EACF,CAAC;CACH;;CAGA,KAAa,OAAoB,KAAwC;EACvE,KAAK;EACL,MAAM,UAAU,IAAI;EACpB,KAAK,OAAO,OAAO,QAAQ,EAAE,MAAM,MAAM,KAAK,CAAC;EAC/C,MAAM,QAAQ,KAAK,OAAO,OAAO,OAAO;EACxC,IAAI,OACF,KAAK,OAAO,KAAK;GACf,YAAY,MAAM;GAClB;GACA;GACA,QAAQ,MAAM;GACd,IAAI,MAAM;EACZ,CAAC;EAEH,OAAO;CACT;CAEA,MAAM,OACJ,OACA,SACA,WACY;EACZ,MAAM,MAAM,KAAK,WAAW,MAAM,UAAU;EAC5C,IAAI,IAAI,UAAU,GAAG,OAAO,KAAK;EACjC,MAAM,QAAQ,KAAK,KAAK,OAAO,GAAG;EAClC,IAAI,UAAU,kBAAkB,UAAU,WAAW;GACnD,KAAK,OAAO,OAAO,SAAS;IAAE,MAAM,MAAM;IAAM;GAAM,CAAC;GACvD,IAAI,MAAM;GACV,OAAO,KAAK;EACd;EACA,IAAI,UAAU,SAAS;GACrB,KAAK,OAAO,OAAO,SAAS;IAAE,MAAM,MAAM;IAAM;GAAM,CAAC;GACvD,MAAM,IAAI,oBAAoB,OAAO,KAAK;EAC5C;EACA,IAAI;EACJ,KAAK;EACL,IAAI;GAEF,QAAQ,OAAO,KAAK,UAAU,KAAK,QAAQ,UAAU,OAAO,IAAI,QAAQ;EAC1E,SAAS,KAAK;GACZ,KAAK,OAAO,OAAO,UAAU;IAAE,MAAM,MAAM;IAAM,QAAQ;IAAM,OAAO,OAAO,GAAG;GAAE,CAAC;GACnF,MAAM;EACR,UAAU;GACR,KAAK;GACL,KAAK,SAAS,MAAM,QAAA,CAAuB;EAC7C;EACA,KAAK,OAAO,OAAO,UAAU;GAAE,MAAM,MAAM;GAAM,QAAQ,UAAU,KAAK;EAAE,CAAC;EAE3E,IAAI,IAAI,UAAU,GAAG,OAAO,KAAK;EACjC,IAAI,UAAU,eAAe;GAC3B,KAAK,OAAO,OAAO,SAAS;IAAE,MAAM,MAAM;IAAM;GAAM,CAAC;GACvD,IAAI,MAAM;GACV,OAAO,KAAK;EACd;EACA,IAAI,UAAU,aAAa;GACzB,KAAK,OAAO,OAAO,SAAS;IAAE,MAAM,MAAM;IAAM;GAAM,CAAC;GACvD,MAAM,IAAI,oBAAoB,OAAO,KAAK;EAC5C;EACA,OAAO;CACT;CAEA,WAAc,OAAoB,SAAkB,WAAuC;EACzF,MAAM,MAAM,KAAK,WAAW,MAAM,UAAU;EAC5C,IAAI,IAAI,UAAU,GAAG,MAAM,IAAI,YAAY,IAAI,EAAE;EACjD,MAAM,QAAQ,KAAK,KAAK,OAAO,GAAG;EAClC,IAAI,UAAU,kBAAkB,UAAU,WAAW;GACnD,KAAK,OAAO,OAAO,SAAS;IAAE,MAAM,MAAM;IAAM;GAAM,CAAC;GACvD,IAAI,MAAM;GACV,MAAM,IAAI,YAAY,IAAI,EAAE;EAC9B;EACA,IAAI,UAAU,SAAS;GACrB,KAAK,OAAO,OAAO,SAAS;IAAE,MAAM,MAAM;IAAM;GAAM,CAAC;GACvD,MAAM,IAAI,oBAAoB,OAAO,KAAK;EAC5C;EACA,IAAI;EACJ,IAAI;GACF,QAAQ,QAAQ;EAClB,SAAS,KAAK;GACZ,KAAK,OAAO,OAAO,UAAU;IAAE,MAAM,MAAM;IAAM,QAAQ;IAAM,OAAO,OAAO,GAAG;GAAE,CAAC;GACnF,MAAM;EACR;EACA,KAAK,OAAO,OAAO,UAAU;GAAE,MAAM,MAAM;GAAM,QAAQ,UAAU,KAAK;EAAE,CAAC;EAC3E,IAAI,UAAU,eAAe;GAC3B,KAAK,OAAO,OAAO,SAAS;IAAE,MAAM,MAAM;IAAM;GAAM,CAAC;GACvD,IAAI,MAAM;GACV,MAAM,IAAI,YAAY,IAAI,EAAE;EAC9B;EACA,IAAI,UAAU,aAAa;GACzB,KAAK,OAAO,OAAO,SAAS;IAAE,MAAM,MAAM;IAAM;GAAM,CAAC;GACvD,MAAM,IAAI,oBAAoB,OAAO,KAAK;EAC5C;EACA,OAAO;CACT;CAEA,YAAY,QAAsB;EAChC,KAAK,QAAQ,KAAK,MAAM;CAC1B;CAEA,OAAU,SAAqB,YAAgC;EAC7D,MAAM,MAAM,KAAK,WAAW,UAAU;EACtC,MAAM,UAAU,KAAK;EACrB,IAAI,SAAS,QAAQ,MAAM,QAAQ;EACnC,KAAK,UAAU;EACf,IAAI,CAAC,SAEH,OAAO,QAAQ,KAAK,CAAC,SAAS,IAAI,QAAQ,WAAW,IAAI,cAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;EAEjF,OAAO,SAAS,SAAS;GACvB,OAAO,QAAQ;GACf,gBAAgB,KAAK;GACrB,eAAe,IAAI,UAAU;GAC7B,aAAa;IAEX,KAAK,YACH,cAAc,WAAW,+EAC3B;IACA,IAAI,MAAM;GACZ;EACF,CAAC;CACH;CAEA,SAAS,YAAoB,QAAgB,SAA0B;EACrE,KAAK,WAAW,aAAa,KAAK,UAAU;GAC1C,MAAM;GACN;GACA;GACA,IAAI;GACJ;EACF,CAAC;CACH;AACF;;;;;;;;ACrSA,SAAgB,aACd,UACA,MACA,SACc;CACd,MAAM,aAAa,SAAS,eAAe,MAAM,OAAO;CACxD,MAAM,SAAS,SAAS,cAAc,UAAU,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;CACnE,OAAO;EAAE,GAAG;EAAY,YAAY,4BAA4B,WAAW,YAAY,MAAM;CAAE;AACjG;AAEA,eAAsB,OACpB,MACA,UACA,UACA,WACA,OACA,SACuB;CACvB,MAAM,SAAS,SAAS,cAAc,IAAI,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE;CAC3D,IAAI,QAAqB;EAAE;EAAU,SAAS;CAAO;CACrD,IAAI,OAAO;EAAE;EAAO;CAAU;CAC9B,IAAI,OAAO;CAEX,IAAI,WAAW;CACf,OAAO,YAAY,OAAO,QAAQ,WAAW,QAAQ,IAAI,IAAI,QAAQ,UAAU;EAC7E,WAAW;EACX,KAAK,MAAM,aAAa,iBAAiB,KAAK,GAAG;GAC/C,IAAI,QAAQ,QAAQ,WAAW,QAAQ,IAAI,KAAK,QAAQ,UAAU;GAClE,MAAM,gBAAgB,aAAa,UAAU,MAAM,UAAU,OAAO;GACpE,MAAM,MAAM,MAAM,UAAU,eAAe,UAAU,UAAU,QAAQ;GACvE,MAAM,MAAM,IAAI;GAChB;GAEA,IAAI,IAAI,mBAAmB,SAAS,GAAG;GACvC,MAAM,QAAQ,gBAAgB,KAAK,cAAc,UAAU,CAAC,CAAC,MAAM,MACjE,cAAc,GAAG,SAAS,CAC5B;GACA,IAAI,OAAO;IACT,QAAQ;IACR,OAAO;KAAE,OAAO;KAAK,WAAW;IAAM;IACtC,WAAW;IACX;GACF;EACF;CACF;CACA,OAAO;EACL,MAAM,aAAa,UAAU,MAAM,MAAM,OAAO;EAChD,UAAU,MAAM;EAChB,YAAY,MAAM;EAClB,OAAO,KAAK;EACZ,WAAW,KAAK;EAChB;EACA,eAAe,SAAS,OAAO,SAAS,MAAM,SAAS,OAAO;EAC9D,eAAe,OAAO,SAAS,MAAM,QAAQ;CAC/C;AACF;;;;;;;ACpDA,MAAM,oBAAuC;CAC3C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,eAAsB,QACpB,MACA,UACA,KACoB;CAGpB,MAAM,SAAS,MAAM,IAAI;CACzB,IAAI,QAAQ,KAAK,SAAS;CAC1B,IAAI;EACF,IAAI;GACF,MAAM,UAAsB,CAAC,GAAG,SAAS,cAAc,IAAI,CAAC;GAC5D,OAAO,QAAQ,SAAS,GAAG;IACzB,MAAM,QAAQ,QAAQ,MAAM;IAC5B,MAAM,SAAS,MAAM,SAAS,QAAQ,OAAO,KAAK,IAAI;IACtD,QAAQ,KAAK,GAAG,OAAO,SAAS;GAClC;EACF,UAAU;GACR,IAAI,UAAU;EAChB;EACA,MAAM,SAAS,SAAS,MAAM,GAAG;CACnC,UAAU;EAER,MAAM,SAAS,UAAU,IAAI;CAC/B;CACA,OAAO,IAAI;AACb;;AAGA,eAAsB,UACpB,MACA,UACA,UACc;CACd,MAAM,MAAM,IAAI,IAAI;EAAE,MAAM;EAAU;EAAU,QAAQ,KAAK;EAAQ,kBAAkB;CAAE,CAAC;CAC1F,MAAM,QAAQ,MAAM,UAAU,GAAG;CACjC,OAAO;AACT;;AAGA,eAAsB,OACpB,MACA,UACA,UACoB;CACpB,QAAQ,MAAM,UAAU,MAAM,UAAU,QAAQ,EAAA,CAAG;AACrD;AAEA,eAAsB,QACpB,MACA,UACA,SAC0B;CAC1B,MAAM,MAAM,QAAQ,cAAc,KAAK,IAAI;CAC3C,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,mBAAmB,QAAQ,oBAAoB;CACrD,MAAM,cAAc,CAAC,GAAG,mBAAmB,GAAG,SAAS,WAAW;CAClE,MAAM,QAAQ,IAAI;CAClB,MAAM,UAAU;EAAE,MAAM;EAAG,cAAc;EAAG,gBAAgB;CAAE;CAC9D,MAAM,cAA6B;EAAE,GAAG;EAAS,WAAW,IAAI,IAAI;CAAM;CAC1E,MAAM,OAAO;EAAE,UAAU,KAAK;EAAM,MAAM,QAAQ;EAAM;CAAY;CAEpE,IAAI,KAAK,OAAO,6BAA6B,GAC3C,OAAO;EACL,GAAG;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACR,SAAS,KAAK;CAChB;CAGF,MAAM,gBAAgB,QAAQ,iBAAiB;;CAE/C,MAAM,YAAsD,CAAC;CAE7D,IAAI,SAAoB,SAAS,QAAQ,IAAI;CAC7C,OAAO,QAAQ,OAAO,WAAW,IAAI,IAAI,QAAQ,KAAK,OAAO,UAAU;EACrE,MAAM,CAAC,SAAS,QAAQ,QAAQ,MAAM;EACtC,SAAS;EACT,MAAM,MAAM,IAAI,IAAI;GAClB,MAAM;GACN,UAAU;IAAE,MAAM;IAAS,QAAQ,CAAC;GAAE;GACtC,QAAQ,KAAK;GACb;EACF,CAAC;EACD,MAAM,MAAM,MAAM,QAAQ,MAAM,UAAU,GAAG;EAC7C,QAAQ;EACR,QAAQ,gBAAgB,IAAI;EAC5B,QAAQ,kBAAkB,IAAI;EAC9B,IAAI,UAAU,SAAS,eACrB,UAAU,KAAK;GAAE,UAAU,IAAI;GAAU,QAAQ,UAAU,GAAG;EAAE,CAAC;EAEnE,IAAI,IAAI,mBAAmB,SAAS,GAClC,OAAO;GACL,GAAG;GACH,MAAM;GACN,OAAO;GACP,QAAQ,IAAI,mBAAmB,KAAK,IAAI;GACxC,SAAS,KAAK;EAChB;EAIF,MAAM,YADa,gBAAgB,KAAK,KAAK,UAClB,CAAC,CAAC;EAC7B,IAAI,WAAW;GACb,MAAM,WAAW,IAAI;GACrB,MAAM,cAAc,MAAM,UAAU,MAAM,UAAU,QAAQ;GAC5D,MAAM,WAAW,YAAY;GAC7B,QAAQ;GACR,IAAI,YAAY,mBAAmB,SAAS,KAAK,UAAU,QAAQ,MAAM,UAAU,GAAG,GACpF,OAAO;IACL,GAAG;IACH,MAAM;IACN,OAAO;IACP,QAAQ,6BAA6B,SAAS,KAAK;IACnD,SAAS,KAAK;GAChB;GAGF,MAAM,SAAS,MAAM,OAAO,MAAM,UAAU,UAAU,WAAW,UAAU;IACzE,SAAS,QAAQ,iBAAiB;IAClC,UAAU,IAAI,IAAI,KAAK,OAAO;IAC9B;GACF,CAAC;GACD,QAAQ,QAAQ,OAAO;GACvB,OAAO;IACL,GAAG;IACH,MAAM;IACN,WAAW,OAAO;IAClB,OAAO,OAAO;IACd,UAAU,OAAO;IACjB,YAAY,OAAO;IACnB,QAAQ;KACN,eAAe,OAAO;KACtB,eAAe,OAAO;KACtB,MAAM,OAAO;IACf;IACA,SAAS,KAAK;GAChB;EACF;CACF;CAEA,KAAK,MAAM,WAAW,CAAC,GAAG,SAAS,CAAC,CAAC,QAAQ,GAAG;EAC9C,MAAM,QAAQ,MAAM,UAAU,MAAM,UAAU,QAAQ,QAAQ;EAC9D,QAAQ;EACR,IAAI,MAAM,mBAAmB,SAAS,KAAK,UAAU,MAAM,GAAG,MAAM,QAAQ,QAC1E,OAAO;GACL,GAAG;GACH,MAAM;GACN,OAAO;GACP,QAAQ,YAAY,QAAQ,SAAS,KAAK;GAC1C,SAAS,KAAK;EAChB;CAEJ;CACA,OAAO;EAAE,GAAG;EAAM,MAAM;EAAW,QAAQ,KAAK;EAAQ,SAAS,KAAK;CAAE;AAC1E"}
|