@mark1russell7/harness 0.15.0 → 0.15.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["spreadOf","middle","intervalOfMedian","median","between","newState","oldState","ERRNO","between","newState","oldState","ipOf","nameOf","between","numberOf","between","findingsOf","between","between","sleep","STEADY","sleep","peersOf","droppedSoFar","sleep","STEADY","TAIL_MS","waitFor","droppedSoFar","sleep","STEADY","TAIL_MS","waitFor","droppedSoFar","sleep","droppedSoFar","waitFor","TAIL_MS","sleep","RAW_TAIL","STEADY","TAIL_MS","waitFor","droppedSoFar","sleep","droppedSoFar","driverSettled"],"sources":["../src/load.ts","../src/verdict.ts","../src/application.ts","../src/driver.ts","../src/queue.ts","../src/conntrack.ts","../src/pause.ts","../src/ports.ts","../src/recovery.ts","../src/timeline.ts","../src/observe.ts","../src/fabric.ts","../src/substrate.ts","../src/lab.ts","../src/standby.ts","../src/pins.ts","../src/group.ts","../src/replset.ts","../src/drill.ts","../src/cluster.ts","../src/kafka.ts","../src/run.ts"],"sourcesContent":["import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { Rung, RungRecord } from \"@mark1russell7/rigor-bench\";\nimport { rungVerdict } from \"@mark1russell7/rigor-bench\";\nimport type { Completion, LoadMeasure, Schedule } from \"@mark1russell7/rigor-chaos\";\nimport { measureLoad, schedule, scheduleHeld } from \"@mark1russell7/rigor-chaos\";\nimport { quantile } from \"@mark1russell7/rigor-statistics\";\nimport type { LoadPrediction, LoadStream, ProbeEvent, RunStream } from \"./cell.ts\";\n\n/**\n * The measure and the verdict of an open-loop cell (SYS-68). A client on a schedule sends each\n * arrival at its time, thus a stall counts in each arrival that it delayed. The package rigor-chaos\n * counts each latency from the planned time. The package rigor-bench judges a quantile by a\n * distribution-free interval.\n */\n\n/** This path is where the client of an open-loop cell finds its schedule. */\nexport const SCHEDULE_PATH = \"/tmp/schedule.json\";\n\n/** This function gives the time of a line of the client, in ms from the start of the schedule. */\nconst fromStart = (start: number, t: number): number => (t - start) / 1e6;\n\n/**\n * This function gives the measure of one run of a schedule from the lines of its client. It gives\n * null when the client did not start the schedule. The first `sent` line of a client is its request\n * before `ready`, and it names no arrival. The end of the run is its last line.\n */\nexport const loadOf = (events: readonly ProbeEvent[], plan: Schedule): RunLoad | null => {\n const start = events.find((event) => event.ev === \"scheduled\")?.t;\n if (start === undefined) return null;\n return measureOf(events, start, plan, undefined);\n};\n\n/**\n * A run load is the measure of one run of a schedule. `failed` counts the replies with a status\n * outside 200 to 299. Such a reply is a completion, thus its time is in `latency`. The client\n * `schedule` gives no status, and a record from before this field has none: both read as 0.\n */\nexport type RunLoad = LoadMeasure & { readonly failed?: number };\n\n/** This function tells if a status of a reply is a failure: a number outside 200 to 299. */\nconst failedStatus = (status: unknown): boolean => typeof status === \"number\" && (status < 200 || status > 299);\n\n/** This function gives the measure of the arrivals of one stream: the lines with the key `key`, or each line for no key. */\nconst measureOf = (events: readonly ProbeEvent[], start: number, plan: Schedule, key: string | undefined): RunLoad => {\n const sent = new Map<number, number>();\n const done = new Map<number, number>();\n let failed = 0;\n for (const event of events) {\n const index = event[\"i\"];\n if (typeof index !== \"number\" || (key !== undefined && event[\"k\"] !== key)) continue;\n if (event.ev === \"sent\") sent.set(index, fromStart(start, event.t));\n if (event.ev === \"replied\") {\n done.set(index, fromStart(start, event.t));\n if (failedStatus(event[\"status\"])) failed += 1;\n }\n }\n const completions: Completion[] = [...sent].map(([index, at]) => ({ index, sent: at, done: done.get(index) ?? null }));\n const end = events.reduce((latest, event) => Math.max(latest, fromStart(start, event.t)), 0);\n return { ...measureLoad(plan, completions, end), failed };\n};\n\n/** This path is where the client `load` finds its plan. */\nexport const LOAD_PATH = \"/tmp/load.json\";\n\n/** This text is the format of the plan of the client `load`. */\nexport const LOAD_FORMAT = \"systems-load/1\";\n\n/**\n * This function gives the schedule of each stream of a cell, and the text of the plan of the client\n * `load`. It throws for no stream, for two streams with one key and for a stream with no request.\n */\nexport const loadPlanOf = (streams: readonly LoadStream[]): { readonly streams: readonly RunStream[]; readonly content: string } => {\n if (streams.length === 0) throw new RangeError(\"a plan of the client load has no stream\");\n const keys = new Set<string>();\n for (const stream of streams) {\n if (keys.has(stream.key)) throw new RangeError(`two streams have the key ${stream.key}`);\n if (stream.requests.length === 0) throw new RangeError(`the stream ${stream.key} has no request`);\n keys.add(stream.key);\n }\n const scheduled = streams.map((stream) => ({ key: stream.key, schedule: schedule(stream.plan.profile, stream.plan.options), requests: stream.requests }));\n return {\n streams: scheduled.map(({ key, schedule: each }) => ({ key, schedule: each })),\n content: JSON.stringify({ format: LOAD_FORMAT, streams: scheduled }),\n };\n};\n\n/**\n * This function gives the measure of each stream of a run of the client `load`, and their pool. Each\n * stream counts its arrivals from 0, thus the lines of a stream are the lines with its key. The pool\n * sums the counts and joins the times, in the order of the streams. It gives null when the client did\n * not start its schedule.\n */\nexport const streamsLoadOf = (\n events: readonly ProbeEvent[],\n streams: readonly RunStream[],\n): { readonly pool: RunLoad; readonly streams: Readonly<Record<string, RunLoad>> } | null => {\n const start = events.find((event) => event.ev === \"scheduled\")?.t;\n if (start === undefined) return null;\n const each = streams.map((stream) => [stream.key, measureOf(events, start, stream.schedule, stream.key)] as const);\n const measures = each.map(([, measure]) => measure);\n const sum = (count: (measure: RunLoad) => number) => measures.reduce((total, measure) => total + count(measure), 0);\n const join = (times: (measure: RunLoad) => readonly number[]) => measures.flatMap(times);\n return {\n pool: {\n planned: sum((measure) => measure.planned),\n unsent: sum((measure) => measure.unsent),\n unfinished: sum((measure) => measure.unfinished),\n failed: sum((measure) => measure.failed ?? 0),\n latency: join((measure) => measure.latency),\n service: join((measure) => measure.service),\n lag: join((measure) => measure.lag),\n censored: join((measure) => measure.censored),\n },\n streams: Object.fromEntries(each),\n };\n};\n\n/** A load spread is a part of the distribution of one measure of an open-loop cell, over its counted runs. */\nexport interface LoadSpread {\n readonly p50: Quantity;\n readonly p99: Quantity;\n readonly max: Quantity;\n}\n\n/**\n * A load verdict sums the schedule of an open-loop cell over its counted runs. `latency` counts from\n * the planned time, and `service` counts from the send: the measure of a closed-loop driver. Each\n * arrival with no reply counts in `latency` at its age at the end of its run, a lower bound.\n */\nexport interface LoadVerdict {\n readonly planned: number;\n readonly unsent: number;\n readonly unfinished: number;\n /** This count is the replies with a status of a failure, over the counted runs. */\n readonly failed: number;\n readonly latency: LoadSpread | null;\n readonly service: LoadSpread | null;\n readonly lag: LoadSpread | null;\n /** This text is the verdict of each band, in the order of the prediction. */\n readonly bands: readonly string[];\n /** This text is the verdict of the share of failed arrivals, when the prediction has a limit on it. */\n readonly failures?: string;\n}\n\n/** This function gives the spread of a list of times in ms, or null for no time. */\nconst spreadOf = (values: readonly number[]): LoadSpread | null =>\n values.length === 0\n ? null\n : {\n p50: quantity(quantile(values, 0.5, \"nearest-rank\"), \"ms\"),\n p99: quantity(quantile(values, 0.99, \"nearest-rank\"), \"ms\"),\n max: quantity(values.reduce((most, value) => Math.max(most, value), 0), \"ms\"),\n };\n\n/** This time is the date of the record of a band and the date of its verdict. The record has no age, because it comes from this run. */\nconst NOW = \"2026-01-01T00:00:00.000Z\";\n\n/**\n * This function judges one band of the latency over the pooled arrivals of the counted runs. The\n * top of the band reads the interval of rigor-bench: the band holds only if the interval is under its top.\n * The latencies of one run can follow each other, thus the width of the interval is an estimate.\n * The bottom of the band reads the quantile itself. It gives the text of the verdict, and if it holds.\n */\nconst bandVerdict = (\n band: LoadPrediction[\"bands\"][number],\n values: readonly number[],\n censored: readonly number[],\n): { readonly holds: boolean; readonly words: string } => {\n const high = valueIn(band.high, \"ms\");\n const rung: Rung = {\n name: \"band\",\n at: {},\n budgets: [{ kind: \"quantile\", measure: \"latency\", unit: \"ms\", quantile: band.quantile, limit: high }],\n test: \"the cell\",\n };\n const record: RungRecord = {\n rung: \"band\",\n commit: \"the cell\",\n at: NOW,\n real: [\"the counted runs\"],\n synthetic: [],\n evidence: [{ kind: \"quantile\", measure: \"latency\", values, censored }],\n };\n const top = rungVerdict(rung, record, { now: NOW });\n const read = values.length + censored.length === 0 ? null : quantile([...values, ...censored], band.quantile, \"nearest-rank\");\n const low = band.low === undefined ? null : valueIn(band.low, \"ms\");\n const above = low === null || (read !== null && read >= low);\n const place = low === null ? `under ${high} ms` : `in [${low}, ${high}] ms`;\n // the rung judges only the top of the band: a read under its bottom is not within the band\n const outcome = top.outcome === \"within\" && !above ? \"under the bottom of the band\" : top.outcome;\n return {\n holds: top.outcome === \"within\" && above,\n words: `p${band.quantile * 100} of the latency ${read === null ? \"has no value\" : `is ${read} ms`}, wanted ${place}: ${outcome}. ${top.reason}`,\n };\n};\n\n/**\n * This function judges the share of failed arrivals over the counted runs against a limit. Each\n * planned arrival is a trial. An arrival fails if the client did not send it. It also fails with no\n * reply at the end of its run, or with the status of a failure. The rate budget of rigor-bench\n * reads the upper end of the Wilson interval at 0.95. Thus 381 arrivals with no failure hold a limit\n * of 1 %, and fewer arrivals cannot decide.\n */\nconst failuresVerdict = (limit: number, failures: number, trials: number): { readonly holds: boolean; readonly words: string } => {\n const rung: Rung = { name: \"failures\", at: {}, budgets: [{ kind: \"rate\", measure: \"failures\", limit }], test: \"the cell\" };\n const record: RungRecord = {\n rung: \"failures\",\n commit: \"the cell\",\n at: NOW,\n real: [\"the counted runs\"],\n synthetic: [],\n evidence: [{ kind: \"rate\", measure: \"failures\", failures, trials }],\n };\n const verdict = rungVerdict(rung, record, { now: NOW });\n return {\n holds: verdict.outcome === \"within\",\n words: `${failures} of ${trials} arrivals failed, wanted a share under ${limit * 100} %: ${verdict.outcome}. ${verdict.reason}`,\n };\n};\n\n/** This record is what the verdict of a cell takes from its load: the runs that broke the schedule, and the sum. */\nexport interface LoadJudgement {\n readonly holds: boolean;\n readonly outside: ReadonlyArray<{ readonly run: string; readonly why: string }>;\n readonly load: LoadVerdict;\n}\n\n/**\n * This function judges the load of an open-loop cell over its counted runs. A run that did not keep\n * its schedule measures its driver, not the target, thus it is a finding of that run. Each\n * band reads all the arrivals of the counted runs.\n */\nexport const loadVerdict = (\n prediction: LoadPrediction,\n runs: ReadonlyArray<{ readonly name: string; readonly load: RunLoad | undefined }>,\n): LoadJudgement => {\n const limit = valueIn(prediction.lag, \"ms\");\n const outside = runs.flatMap((run) => {\n if (run.load === undefined) return [{ run: run.name, why: \"the client never started its schedule\" }];\n const check = scheduleHeld(run.load, limit);\n return check.held ? [] : [{ run: run.name, why: check.reason }];\n });\n const measures = runs.flatMap((run) => (run.load === undefined ? [] : [run.load]));\n const latency = measures.flatMap((measure) => measure.latency);\n const censored = measures.flatMap((measure) => measure.censored);\n const bands = prediction.bands.map((band) => bandVerdict(band, latency, censored));\n const total = (count: (measure: RunLoad) => number) => measures.reduce((sum, measure) => sum + count(measure), 0);\n const planned = total((measure) => measure.planned);\n const unsent = total((measure) => measure.unsent);\n const unfinished = total((measure) => measure.unfinished);\n const failed = total((measure) => measure.failed ?? 0);\n const failures = prediction.failures === undefined ? undefined : failuresVerdict(prediction.failures, unsent + unfinished + failed, planned);\n return {\n holds: runs.length > 0 && outside.length === 0 && bands.every((band) => band.holds) && (failures?.holds ?? true),\n outside,\n load: {\n planned,\n unsent,\n unfinished,\n failed,\n latency: spreadOf([...latency, ...censored]),\n service: spreadOf(measures.flatMap((measure) => measure.service)),\n lag: spreadOf(measures.flatMap((measure) => measure.lag.map((lag) => Math.abs(lag)))),\n bands: bands.map((band) => band.words),\n ...(failures === undefined ? {} : { failures: failures.words }),\n },\n };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport { medianInterval as intervalOfMedian, median as middle, quantileSorted } from \"@mark1russell7/rigor-statistics\";\nimport type { Prediction, Run, Stage } from \"./cell.ts\";\nimport type { LoadVerdict } from \"./load.ts\";\nimport { loadVerdict } from \"./load.ts\";\nimport type { Measured, Reordering } from \"./observe.ts\";\n\n/** This function gives the words of the outcome of a second request: its connection, a retry, and its end. */\nexport const requestWords = (outcome: {\n readonly connection: \"reused\" | \"new\";\n readonly retried: boolean;\n readonly error: string | null;\n readonly pending?: boolean | undefined;\n}): string =>\n `${outcome.connection}${outcome.retried ? \", a retry\" : \"\"}, ${outcome.pending === true ? \"pending\" : (outcome.error ?? \"a reply\")}`;\n\n/**\n * This amount is the noise of the pipeline itself, δ_abs, as the calibration measured it. It is\n * the 99.9th percentile of the whole latency of a reset, at the concurrency cap or less. Its\n * minimum is one jiffy. On 2026-10-12 the worst of 60 resets at 1 and 4 environments took\n * 1.141 ms, thus the minimum sets it to 4 ms. The calibration occurs again after each change to\n * the harness, the kernel or Docker.\n */\nexport const NOISE: Quantity = quantity(4, \"ms\");\n\n/**\n * This time is how late the injector can commit or lift a fault before the run is void. Stage 0\n * measures the commit apart from δ_abs, and the commit is longer. On a hosted runner it took up to\n * 2.75 ms at 4 environments, where δ_abs is 1 ms. Thus a cell's δ_abs does not change it.\n */\nexport const INJECT: Quantity = NOISE;\n\n/** This function gives the δ_abs of a cell: its own, or `NOISE` for a cell that gives none. */\nexport const noiseOf = (cell: { readonly noise?: Quantity | undefined }): Quantity => cell.noise ?? NOISE;\n\n/**\n * A pairing is the window of a run in which a line of its program pairs with the kernel's record\n * of its act. `bound` is the jitter of the program that the run measured, or null. `delta` is the\n * window: δ_abs of the cell, or the bound when the bound is longer.\n */\nexport interface Pairing {\n readonly bound: Quantity | null;\n readonly delta: Quantity;\n}\n\n/**\n * This function gives the pairing window of a run (SYS-25). On a runner of GitHub, the jitter of\n * a program can be longer than the δ_abs of 1 ms. Thus each run measures it before its fault\n * (`Run.jitter`), and its own measurement widens its window. A run without a jitter record is\n * from before SYS-25. It reads as a bound of null, thus its window is δ_abs. The decision of\n * 2026-10-19 keeps the rule of one miss: a pair that a window misses is still a finding.\n */\nexport const pairingOf = (cell: { readonly noise?: Quantity | undefined }, run: Pick<Run, \"jitter\">): Pairing => {\n const noise = noiseOf(cell);\n const bound = run.jitter?.bound ?? null;\n return { bound, delta: bound !== null && valueIn(bound, \"s\") > valueIn(noise, \"s\") ? bound : noise };\n};\n\n/**\n * This function sums the pairings of the measurements of a cell. It gives the longest bound and\n * the longest window. It also counts the pairings whose window is longer than δ_abs (`noise`). It\n * is null when no measurement has a pairing.\n */\nexport const pairingsOf = (\n runs: readonly Measured[],\n noise: Quantity = NOISE,\n): { readonly bound: Quantity | null; readonly delta: Quantity; readonly widened: number } | null => {\n const pairings = runs.flatMap((run) => (run.pairing === undefined ? [] : [run.pairing]));\n if (pairings.length === 0) return null;\n const longest = (values: readonly Quantity[]): Quantity => values.reduce((most, each) => (valueIn(each, \"s\") > valueIn(most, \"s\") ? each : most));\n const bounds = pairings.flatMap((pairing) => (pairing.bound === null ? [] : [pairing.bound]));\n return {\n bound: bounds.length === 0 ? null : longest(bounds),\n delta: longest(pairings.map((pairing) => pairing.delta)),\n widened: pairings.filter((pairing) => valueIn(pairing.delta, \"s\") > valueIn(noise, \"s\")).length,\n };\n};\n\n/**\n * This function tells if a timer firing came late enough to void a run. A firing two jiffies or\n * more behind its wheel slot came late because the host stopped a vCPU. With the HZ of the run,\n * the rule is in time: the delay must also reach δ_abs, because each band already includes that\n * noise. At HZ 250 two jiffies are 8 ms, more than a δ_abs of 4 ms. At HZ 1000 they are 2 ms.\n */\nexport const delayVoids = (behind: number, hz: number | undefined, noise: Quantity): boolean => {\n if (behind < 2) return false;\n if (hz === undefined || !(hz > 0)) return true;\n return behind / hz >= Math.max(2 / hz, valueIn(noise, \"s\"));\n};\n/** This fraction, δ_rel, is how far the median of a cell can be outside the prediction and stay equivalent. */\nexport const RELATIVE = 0.05;\n/** These are the run counts of a cell: 11, then 22 and 44 while its median crosses the edge of the band. */\nexport const STEPS = [11, 22, 44] as const;\n\n/**\n * A decision is the result of a verdict. A cell whose outcome is a distribution has no band, and\n * its decision is `measured`: a record, not a test.\n */\nexport type Decision = \"holds\" | \"fails\" | \"extend\" | \"inconclusive\" | \"measured\";\n\n/** An interval is a range of times. */\nexport interface Interval {\n readonly low: Quantity;\n readonly high: Quantity;\n}\n\n/** A spread is the distribution of a set of times: its count, its median and its upper quantiles by nearest rank. */\nexport interface Spread {\n readonly count: number;\n readonly median: Quantity;\n readonly p99: Quantity;\n readonly p999: Quantity;\n readonly max: Quantity;\n}\n\n/** A verdict is the judgement of a cell on its runs. */\nexport interface Verdict {\n readonly decision: Decision;\n readonly counted: number;\n readonly voided: number;\n /** This band is where each run must land: [T_lo − δ_abs, T_hi + δ_abs]. It is null for a silent prediction. */\n readonly band: Interval | null;\n /** These are the runs outside the band, and the reason for each. Each is a finding. */\n readonly outside: ReadonlyArray<{ readonly run: string; readonly why: string }>;\n readonly median: Quantity | null;\n /** This interval is the order-statistic interval of the median at 95 %, or the whole range for fewer than six runs. */\n readonly medianInterval: Interval | null;\n /** This time is the slowest reply of a cell that measures a distribution. A closed loop hides the sends in a stall, thus a quantile is a lower bound, and this maximum is not. */\n readonly slowest?: Quantity;\n /** This record is the sum of what reordering did in each counted run of a measurement-only cell. */\n readonly reordering?: Reordering;\n /** This record is the load of an open-loop cell over its counted runs. */\n readonly load?: LoadVerdict;\n /** This record is the time of the proxy of a calibration cell, in each direction. */\n readonly proxy?: { readonly hop: string; readonly up: Spread | null; readonly down: Spread | null };\n /** This record is what the group of a group cell did over the counted runs: its stages, and its writes. */\n readonly group?: GroupVerdict;\n /**\n * These are the outcomes of the second request of an HTTP client over the counted runs, each\n * with its count: for example \"reused, a retry, a reply\". An outcome other than the predicted\n * one is a finding of its run.\n */\n readonly requests?: Readonly<Record<string, number>>;\n /** This record is what the client did after the detection over the counted runs, for a prediction that says when it reconnects. */\n readonly reconnect?: ReconnectVerdict;\n /** These are the outcomes of the call in flight of a WebSocket client over the counted runs, each with its count. */\n readonly calls?: Readonly<Record<string, number>>;\n /**\n * This record is the time from a drop of the program to the close of its socket by its own side,\n * over the counted runs. It also counts the runs where the socket did not close itself.\n * `exited` is the spread of the end of the client process, for the runs where the socket stayed\n * open until that end (`Measured.exited`).\n */\n readonly left?: { readonly spread: Spread | null; readonly stayed: number; readonly exited?: Spread | null };\n readonly why: string;\n}\n\n/**\n * A reconnect verdict sums the reconnect of the client over the counted runs. Each wait before a\n * try gets its spread. A wait outside its band is a finding of its run, thus it is in `outside`.\n * - `syn` is the time from the detection to the first SYN of a new socket.\n * - `established` is the time from the detection to the first new socket that became ESTABLISHED.\n * - `connect` is the time from a `dial` line to the SYN of its socket: the work of the program.\n */\nexport interface ReconnectVerdict {\n readonly waits: ReadonlyArray<Spread | null>;\n readonly syn: Spread | null;\n readonly established: Spread | null;\n readonly connect: Spread | null;\n}\n\n/**\n * A stage verdict is the test of one stage of the timeline of a group against its band. The band\n * is [T_lo − δ_abs, T_hi + the error of the stamps + δ_abs]. A run that did not announce the stage\n * is outside too.\n */\nexport interface StageVerdict {\n readonly stage: Stage;\n readonly band: Interval;\n readonly median: Quantity | null;\n readonly outside: ReadonlyArray<{ readonly run: string; readonly why: string }>;\n readonly decision: \"holds\" | \"fails\";\n}\n\n/**\n * A group verdict sums what the group of a group cell did in its counted runs:\n * - `stages` tests each stage that the prediction gives a band.\n * - `medians` is the median of each stage that a run announced, from the fault.\n * - `lost` counts the writes that a primary accepted and the group did not keep, in each run.\n * - `old` counts the writes that the old primary accepted after the fault, in each run.\n * - `unknown` counts the writes whose outcome the client did not see, and how many the group kept.\n * - `errors` are the errors on the way: the runs that met each, and the median of its first time.\n * - `lags` is the spread of the delays of the stamps, for a calibration.\n * - `duplicates` counts the extra copies that the group holds, in each run. A cell with no band of\n * copies has no such count.\n */\nexport interface GroupVerdict {\n readonly stages: readonly StageVerdict[];\n readonly medians: Partial<Record<Stage, Quantity>>;\n readonly lost: { readonly runs: number; readonly total: number; readonly median: number | null; readonly max: number | null };\n readonly old: { readonly median: number | null; readonly max: number | null };\n readonly unknown: { readonly total: number; readonly held: number };\n readonly errors: ReadonlyArray<{ readonly name: string; readonly runs: number; readonly first: Quantity }>;\n readonly lags?: Spread | null;\n readonly duplicates?: { readonly runs: number; readonly total: number; readonly median: number | null; readonly max: number | null };\n}\n\nconst s = (value: number): Quantity => quantity(Math.round(value * 1e6) / 1e6, \"s\");\nconst name = (run: Measured): string => `env ${run.environment} run ${run.index}`;\n\n/**\n * This function gives the value at quantile p of sorted values, by nearest rank: x_(⌈p·n⌉). It is\n * `quantileSorted` of @mark1russell7/rigor-statistics with the method `\"nearest-rank\"`.\n */\nexport const quantileOf = (sorted: readonly number[], p: number): number => quantileSorted(sorted, p, \"nearest-rank\");\n\n/** This function gives the spread of a set of times, or null for none. */\nexport const spreadOf = (times: readonly Quantity[]): Spread | null => {\n if (times.length === 0) return null;\n const sorted = times.map((time) => valueIn(time, \"s\")).sort((a, b) => a - b);\n return {\n count: sorted.length,\n median: s(middle(sorted)),\n p99: s(quantileOf(sorted, 0.99)),\n p999: s(quantileOf(sorted, 0.999)),\n max: s(sorted.at(-1)!),\n };\n};\n\n/** This function adds the reordering records of runs: the counts add, and each largest value is the largest of all. */\nconst reorderingTotal = (runs: readonly Measured[]): Reordering | undefined => {\n const each = runs.flatMap((run) => (run.reordering === undefined ? [] : [run.reordering]));\n if (each.length === 0) return undefined;\n const sum = (key: \"outOfOrder\" | \"duplicates\" | \"fast\") => each.reduce((total, one) => total + one[key], 0);\n const add = (key: \"ooo\" | \"dsacks\" | \"seen\") =>\n each.some((one) => one[key] !== null) ? each.reduce((total, one) => total + (one[key] ?? 0), 0) : null;\n const top = (key: \"sacked\" | \"lost\" | \"degree\") =>\n each.some((one) => one[key] !== null) ? Math.max(...each.map((one) => one[key] ?? 0)) : null;\n return {\n outOfOrder: sum(\"outOfOrder\"),\n duplicates: sum(\"duplicates\"),\n ooo: add(\"ooo\"),\n sacked: top(\"sacked\"),\n lost: top(\"lost\"),\n dsacks: add(\"dsacks\"),\n fast: sum(\"fast\"),\n degree: top(\"degree\"),\n seen: add(\"seen\"),\n };\n};\n\n/** This function says a reordering record in words. */\nconst reorderingWords = (total: Reordering): string =>\n [\n `${total.outOfOrder} arrivals out of order and ${total.duplicates} duplicate arrivals at the client`,\n ...(total.ooo === null ? [] : [`its kernel counted ${total.ooo} segments out of order`]),\n ...(total.sacked === null ? [] : [`the server held up to ${total.sacked} segments SACKed`]),\n ...(total.dsacks === null ? [] : [`got ${total.dsacks} DSACKs`]),\n `sent ${total.fast} fast retransmissions`,\n ...(total.seen === null ? [] : [`saw ${total.seen} reorderings`]),\n ...(total.degree === null ? [] : [`and its reordering degree went to ${total.degree}`]),\n ].join(\", \");\n\n/** This function says a spread in words, in milliseconds. */\nconst spreadWords = (spread: Spread | null): string => {\n if (spread === null) return \"no time\";\n const ms = (time: Quantity) => Math.round(valueIn(time, \"s\") * 1e6) / 1e3;\n return `median ${ms(spread.median)} ms, p99 ${ms(spread.p99)} ms, p99.9 ${ms(spread.p999)} ms, max ${ms(spread.max)} ms of ${spread.count}`;\n};\n\n/**\n * This function gives the distribution-free interval of a median: [x_(k), x_(n+1−k)], for the\n * largest k whose two tails each hold 2.5 % or less. For eleven runs, it gives [x_(2), x_(10)],\n * at 98.8 %. It is `medianInterval` of @mark1russell7/rigor-statistics at the level 0.95. An\n * empty list throws a RangeError.\n */\nexport const medianInterval = (sorted: readonly number[]): [number, number] => {\n const interval = intervalOfMedian(sorted, 0.95);\n return [interval.low, interval.high];\n};\n\n/**\n * This function gives the verdict of a cell, from two tests:\n * - Containment: each run lands in [T_lo − δ_abs, T_hi + δ_abs]. A run outside is a finding.\n * - Median equivalence: the interval of the median is in the band, made wider by δ_rel. An\n * interval outside the band fails. An interval across its edge extends the cell to 22 runs, then\n * 44, and then the verdict is inconclusive.\n *\n * A silent prediction holds only if no run detected the fault in its window. After a stall, the\n * return of the reply gets the same test as a detection, by its interval, and a detection is a\n * finding. The distribution test (a DKW band) needs a predicted distribution from a simulator,\n * which does not exist at this time.\n */\nexport const verdictOf = (prediction: Prediction, runs: readonly Measured[], noise: Quantity = NOISE): Verdict => {\n const band = verdictOfBand(prediction, runs, noise);\n const counted = runs.filter((run) => run.void === null);\n const asked = counted.some((run) => run.request !== undefined) ? withRequests(band, counted) : band;\n const verdict = withProgram(asked, counted);\n if (prediction.group === undefined && !counted.some((run) => run.group !== undefined)) return verdict;\n return { ...verdict, group: groupVerdictOf(prediction, counted, noise) };\n};\n\n/**\n * This function adds the reconnect of the client and the outcomes of its call in flight to a\n * verdict. Its reason gets a sentence for each. A verdict whose runs have neither stays as it is.\n */\nconst withProgram = (verdict: Verdict, counted: readonly Measured[]): Verdict => {\n const reconnects = counted.flatMap((run) => (run.reconnect === undefined ? [] : [run.reconnect]));\n const calls = counted.flatMap((run) => (run.call === undefined ? [] : [run.call]));\n const lefts = counted.flatMap((run) => (run.left === undefined ? [] : [run.left]));\n if (reconnects.length === 0 && calls.length === 0 && lefts.length === 0) return verdict;\n const ms = (spread: Spread | null) => (spread === null ? \"none\" : `${Math.round(valueIn(spread.median, \"s\") * 1e6) / 1e3} ms`);\n const tries = Math.max(0, ...reconnects.map((each) => each.waits.length));\n const reconnect: ReconnectVerdict | undefined =\n reconnects.length === 0\n ? undefined\n : {\n waits: Array.from({ length: tries }, (_, at) =>\n spreadOf(reconnects.flatMap((each) => (each.waits[at] === undefined ? [] : [each.waits[at]!]))),\n ),\n syn: spreadOf(reconnects.flatMap((each) => (each.syn === null ? [] : [each.syn]))),\n established: spreadOf(reconnects.flatMap((each) => (each.established === null ? [] : [each.established]))),\n connect: spreadOf(reconnects.flatMap((each) => each.connects)),\n };\n const outcomes: Record<string, number> = {};\n for (const call of calls) outcomes[call.outcome] = (outcomes[call.outcome] ?? 0) + 1;\n const gone = lefts.flatMap((each) => (each === null ? [] : [each]));\n // a socket that stayed open until the end of the client process: its kernel closed it, not the program\n const ends = counted.flatMap((run) => (run.exited === undefined ? [] : [run.exited]));\n const left =\n lefts.length === 0\n ? undefined\n : { spread: spreadOf(gone), stayed: lefts.length - gone.length, ...(ends.length === 0 ? {} : { exited: spreadOf(ends) }) };\n const ended = ends.length === 0 ? \"\" : `: in ${ends.length} the socket stayed open until the client process ended, median ${ms(spreadOf(ends))} after the drop line`;\n const said = [\n ...(left === undefined\n ? []\n : [\n `After the drop, the program closed its socket in ${gone.length} runs, median ${ms(left.spread)} after its drop line${left.stayed === 0 ? \"\" : `, and it did not close it in ${left.stayed}${ended}`}.`,\n ]),\n ...(reconnect === undefined\n ? []\n : [\n `Reconnect: the waits before each try, median ${reconnect.waits.map(ms).join(\", \")}; the first SYN median ${ms(reconnect.syn)} and ESTABLISHED median ${ms(reconnect.established)} after the detection.`,\n ]),\n ...(calls.length === 0\n ? []\n : [`Calls in flight: ${Object.entries(outcomes).map(([outcome, n]) => `${n} ${outcome}`).join(\"; \")}.`]),\n ];\n return {\n ...verdict,\n ...(reconnect === undefined ? {} : { reconnect }),\n ...(calls.length === 0 ? {} : { calls: outcomes }),\n ...(left === undefined ? {} : { left }),\n why: `${verdict.why.endsWith(\".\") ? verdict.why : `${verdict.why}.`} ${said.join(\" \")}`,\n };\n};\n\n/**\n * This function adds the outcomes of the second request of an HTTP client to a verdict. A cell\n * whose outcome is a distribution gets them in its reason too.\n */\nconst withRequests = (verdict: Verdict, counted: readonly Measured[]): Verdict => {\n const requests: Record<string, number> = {};\n for (const run of counted) {\n const words = run.request === null || run.request === undefined ? \"no second request\" : requestWords(run.request);\n requests[words] = (requests[words] ?? 0) + 1;\n }\n const listed = Object.entries(requests)\n .map(([words, n]) => `${n} ${words}`)\n .join(\"; \");\n return {\n ...verdict,\n requests,\n why: verdict.decision === \"measured\" ? `${verdict.why} Second requests: ${listed}.` : verdict.why,\n };\n};\n\n/** This function gives the median of some counts, or null for none. */\nconst medianCount = (values: readonly number[]): number | null =>\n values.length === 0 ? null : middle([...values].sort((a, b) => a - b));\n\n/** This function sums what the group of a group cell did in its counted runs, and tests each stage that has a band. */\nexport const groupVerdictOf = (prediction: Prediction, counted: readonly Measured[], delta: Quantity = NOISE): GroupVerdict => {\n const noise = valueIn(delta, \"s\");\n const stamps = prediction.group?.stamps === undefined ? 0 : valueIn(prediction.group.stamps, \"s\");\n const stages = (prediction.group?.stages ?? []).map((band): StageVerdict => {\n const interval = { low: s(valueIn(band.low, \"s\") - noise), high: s(valueIn(band.high, \"s\") + stamps + noise) };\n const outside: Array<{ run: string; why: string }> = [];\n const values: number[] = [];\n for (const run of counted) {\n const at = run.group?.stages[band.stage];\n if (at === undefined) {\n // a stage of a Sentinel starts with +: a Sentinel announces it. The members and the client of a replica set mark the others\n const who = band.stage.startsWith(\"+\") ? \"no Sentinel announced\" : \"no member or client marked\";\n outside.push({ run: name(run), why: `${who} ${band.stage}` });\n continue;\n }\n const value = valueIn(at, \"s\");\n values.push(value);\n if (value < valueIn(interval.low, \"s\") || value > valueIn(interval.high, \"s\"))\n outside.push({ run: name(run), why: `${band.stage} at ${value} s is outside [${interval.low.value}, ${interval.high.value}] s` });\n }\n values.sort((a, b) => a - b);\n return {\n stage: band.stage,\n band: interval,\n median: values.length === 0 ? null : s(middle(values)),\n outside,\n decision: outside.length === 0 && values.length > 0 ? \"holds\" : \"fails\",\n };\n });\n const medians: Partial<Record<Stage, Quantity>> = {};\n const seen = new Set(counted.flatMap((run) => Object.keys(run.group?.stages ?? {}) as Stage[]));\n for (const stage of seen) {\n const values = counted.flatMap((run) => {\n const at = run.group?.stages[stage];\n return at === undefined ? [] : [valueIn(at, \"s\")];\n });\n medians[stage] = s(middle(values.sort((a, b) => a - b)));\n }\n const lostCounts = counted.flatMap((run) => (run.group?.writes.lost === null || run.group === undefined ? [] : [run.group.writes.lost.length]));\n const oldCounts = counted.flatMap((run) => (run.group === undefined ? [] : [run.group.writes.old]));\n const unknown = counted.flatMap((run) => run.group?.writes.unknown ?? []);\n const errors = new Map<string, number[]>();\n for (const run of counted)\n for (const error of run.group?.errors ?? []) errors.set(error.name, [...(errors.get(error.name) ?? []), valueIn(error.first, \"s\")]);\n const lags = counted.flatMap((run) => run.group?.lags ?? []);\n const copyCounts = counted.flatMap((run) => {\n const copies = run.group?.writes.duplicates;\n return copies === null || copies === undefined ? [] : [copies.length];\n });\n return {\n stages,\n medians,\n lost: {\n runs: lostCounts.length,\n total: lostCounts.reduce((sum, n) => sum + n, 0),\n median: medianCount(lostCounts),\n max: lostCounts.length === 0 ? null : Math.max(...lostCounts),\n },\n old: { median: medianCount(oldCounts), max: oldCounts.length === 0 ? null : Math.max(...oldCounts) },\n unknown: { total: unknown.length, held: unknown.filter((each) => each.held === true).length },\n errors: [...errors].map(([error, firsts]) => ({ name: error, runs: firsts.length, first: s(middle(firsts.sort((a, b) => a - b))) })),\n ...(lags.length === 0 ? {} : { lags: spreadOf(lags) }),\n ...(prediction.group?.duplicates === undefined\n ? {}\n : {\n duplicates: {\n runs: copyCounts.length,\n total: copyCounts.reduce((sum, n) => sum + n, 0),\n median: medianCount(copyCounts),\n max: copyCounts.length === 0 ? null : Math.max(...copyCounts),\n },\n }),\n };\n};\n\n/** This function gives the verdict of the band of a cell: its containment and the equivalence of its median. */\nconst verdictOfBand = (prediction: Prediction, runs: readonly Measured[], delta: Quantity = NOISE): Verdict => {\n const counted = runs.filter((run) => run.void === null);\n const voided = runs.length - counted.length;\n const outside = counted\n .filter((run) => run.finding !== null)\n .map((run) => ({ run: name(run), why: run.finding! }));\n const empty = { counted: counted.length, voided, median: null, medianInterval: null };\n if (counted.length === 0)\n return { ...empty, decision: \"inconclusive\", band: null, outside, why: \"no run counted\" };\n\n if (prediction.detects === null) {\n // the law of an accept queue, a port range, a paused consumer or a conntrack table: each run holds each term of it, or the run is outside\n const law =\n prediction.queue !== undefined\n ? \"queue\"\n : prediction.ports !== undefined\n ? \"port range\"\n : prediction.pause !== undefined\n ? \"paused consumer\"\n : prediction.conntrack !== undefined\n ? \"conntrack table\"\n : undefined;\n if (law !== undefined) {\n const off = new Set(outside.map((each) => each.run)).size;\n return {\n ...empty,\n decision: off === 0 ? \"holds\" : \"fails\",\n band: null,\n outside,\n why: `${counted.length - off} of ${counted.length} runs hold the law of the ${law}; ${prediction.why}`,\n };\n }\n // a calibration of a proxy: its time in each direction, over all the requests of the runs\n const crossed = counted.flatMap((run) => (run.crossings === undefined ? [] : [run.crossings]));\n if (crossed.length > 0) {\n const hop = crossed[0]!.hop;\n const up = spreadOf(crossed.flatMap((each) => each.up));\n const down = spreadOf(crossed.flatMap((each) => each.down));\n return {\n ...empty,\n decision: \"measured\",\n band: null,\n outside: [],\n median: up?.median ?? null,\n proxy: { hop, up, down },\n why: `${counted.length} runs measured ${hop}: toward the target ${spreadWords(up)}; toward the client ${spreadWords(down)}. ${prediction.why}`,\n };\n }\n // a measurement-only cell with a reference: the outcomes, and the times from the reference\n if (prediction.from !== undefined) {\n const times = counted\n .flatMap((run) => (run.elapsed === null ? [] : [valueIn(run.elapsed, \"s\")]))\n .sort((a, b) => a - b);\n const kinds = new Map<string, number>();\n for (const run of counted) {\n const kind = run.outcome.kind === \"error\" ? run.outcome.errno : run.outcome.kind;\n kinds.set(kind, (kinds.get(kind) ?? 0) + 1);\n }\n const outcomes = [...kinds].map(([kind, n]) => `${n} ${kind}`).join(\", \");\n const timed =\n times.length === 0\n ? \"no time\"\n : `median ${s(middle(times)).value} s from ${prediction.from}, range [${s(times[0]!).value}, ${s(times.at(-1)!).value}] s`;\n // exact counts judge the cell: the times have no band\n const { counts } = prediction;\n if (counts !== undefined) {\n const exact = counts.map((each) => `${each.what} ${each.count}`).join(\", \");\n return {\n ...empty,\n decision: outside.length === 0 ? \"holds\" : \"fails\",\n band: null,\n outside,\n median: times.length === 0 ? null : s(middle(times)),\n why: `${counted.length - outside.length} of ${counted.length} runs gave the exact counts (${exact}); ${outcomes}; ${timed}. ${prediction.why}`,\n };\n }\n // a band of lost writes or of extra copies judges the cell: the time stays a measurement, and each finding of a run counts\n const lost = prediction.group?.lost;\n const copies = prediction.group?.duplicates;\n if (lost !== undefined || copies !== undefined) {\n const off = new Set(outside.map((each) => each.run)).size;\n const bands = [\n ...(lost === undefined ? [] : [`lost writes [${lost.low}, ${lost.high}]`]),\n ...(copies === undefined ? [] : [`extra copies [${copies.low}, ${copies.high}]`]),\n ];\n return {\n ...empty,\n decision: off === 0 ? \"holds\" : \"fails\",\n band: null,\n outside,\n median: times.length === 0 ? null : s(middle(times)),\n why: `${counted.length - off} of ${counted.length} runs inside the band of ${bands.join(\" and the band of \")}; ${outcomes}; ${timed}. ${prediction.why}`,\n };\n }\n // the end has no band, but each wait of the reconnect has one: a wait outside it is a finding of its run\n const missed = outside.filter((each) => counted.some((run) => name(run) === each.run && run.reconnect !== undefined));\n const late = missed.length === 0 ? \"\" : ` ${missed.length} runs had a wait of the reconnect outside its band.`;\n return {\n ...empty,\n decision: \"measured\",\n band: null,\n outside: missed,\n median: times.length === 0 ? null : s(middle(times)),\n why: `${counted.length} runs measured: ${outcomes}; ${timed}.${late} ${prediction.why}`,\n };\n }\n // an open-loop cell: each run keeps its schedule, and each band of the latency holds\n if (counted.some((run) => run.load !== undefined)) {\n const judged = loadVerdict(\n prediction.load ?? { lag: quantity(Number.MAX_SAFE_INTEGER, \"ms\"), bands: [] },\n counted.map((run) => ({ name: name(run), load: run.load })),\n );\n const middleOfLoad = judged.load.latency?.p50;\n const failed = judged.load.failed === 0 ? \"\" : `, ${judged.load.failed} with the status of a failure`;\n const read = [`${counted.length} runs on a schedule, ${judged.load.planned} arrivals, ${judged.load.unsent} not sent, ${judged.load.unfinished} with no reply${failed}.`, ...judged.load.bands, ...(judged.load.failures === undefined ? [] : [judged.load.failures]), prediction.why].join(\" \");\n return {\n ...empty,\n decision: prediction.load === undefined ? \"measured\" : judged.holds ? \"holds\" : \"fails\",\n band: null,\n outside: judged.outside,\n median: middleOfLoad === undefined ? null : s(valueIn(middleOfLoad, \"s\")),\n ...(judged.load.latency === null ? {} : { slowest: s(valueIn(judged.load.latency.max, \"s\")) }),\n load: judged.load,\n why: read,\n };\n }\n const samples = counted\n .flatMap((run) => (run.samples ?? []).map((sample) => valueIn(sample, \"s\")))\n .sort((a, b) => a - b);\n const retransmissions = counted.reduce((sum, run) => sum + run.retransmissions, 0);\n const ended = counted.filter((run) => run.outcome.kind === \"error\" || run.outcome.kind === \"eof\");\n const reordering = reorderingTotal(counted);\n // a run in which nothing came out of order, twice or SACKed says nothing about reordering\n const anything =\n reordering !== undefined &&\n [reordering.outOfOrder, reordering.duplicates, reordering.ooo, reordering.sacked, reordering.dsacks, reordering.fast, reordering.seen].some(\n (count) => (count ?? 0) > 0,\n );\n const reordered = anything ? ` Reordering: ${reorderingWords(reordering)}.` : \"\";\n const why =\n samples.length === 0\n ? `${counted.length} runs measured, with no reply: ${prediction.why}`\n : `${counted.length} runs, ${samples.length} replies: median ${s(middle(samples)).value} s, p99 ${s(quantileOf(samples, 0.99)).value} s, slowest ${s(samples.at(-1)!).value} s, ${retransmissions} retransmissions, ${ended.length} connections ended.${reordered} ${prediction.why}`;\n return {\n ...empty,\n decision: \"measured\",\n band: null,\n outside: [],\n median: samples.length === 0 ? null : s(middle(samples)),\n ...(samples.length === 0 ? {} : { slowest: s(samples.at(-1)!) }),\n ...(reordering === undefined ? {} : { reordering }),\n why,\n };\n }\n\n if (!prediction.detects && prediction.recovers === undefined && prediction.replies === undefined) {\n const decision = outside.length === 0 ? \"holds\" : \"fails\";\n const why =\n decision === \"holds\"\n ? `nothing detected it in ${counted.length} runs of ${valueIn(prediction.window, \"s\")} s`\n : `${outside.length} of ${counted.length} runs detected it`;\n return { ...empty, decision, band: null, outside, why };\n }\n\n // the interval of a detection, of the return of the reply after a stall, or of a reply in its band\n const timed = prediction.detects ? prediction : (prediction.recovers ?? prediction.replies)!;\n const noise = valueIn(delta, \"s\");\n const low = valueIn(timed.low, \"s\");\n const high = valueIn(timed.high, \"s\");\n const band = { low: s(low - noise), high: s(high + noise) };\n const values: number[] = [];\n for (const run of counted) {\n if (run.elapsed === null) continue;\n const value = valueIn(run.elapsed, \"s\");\n values.push(value);\n if (value < low - noise || value > high + noise)\n outside.push({\n run: name(run),\n why: `${value} s is outside [${band.low.value}, ${band.high.value}] s`,\n });\n }\n values.sort((a, b) => a - b);\n if (values.length === 0)\n return { ...empty, decision: \"fails\", band, outside, why: \"no run measured its time\" };\n const [from, to] = medianInterval(values);\n const median = s(middle(values));\n const interval = { low: s(from), high: s(to) };\n const wide = { low: low * (1 - RELATIVE), high: high * (1 + RELATIVE) };\n const inside = from >= wide.low && to <= wide.high;\n const disjoint = to < wide.low || from > wide.high;\n // a run can be outside for its time and for a finding: it counts once\n const off = new Set(outside.map((each) => each.run)).size;\n const counts = `${counted.length - off} of ${counted.length} runs inside [${band.low.value}, ${band.high.value}] s`;\n const centre = `median ${median.value} s, its interval [${interval.low.value}, ${interval.high.value}] s`;\n const result = {\n counted: counted.length,\n voided,\n band,\n outside,\n median,\n medianInterval: interval,\n };\n if (outside.length > 0 || disjoint)\n return { ...result, decision: \"fails\", why: `${counts}; ${centre}` };\n if (inside) return { ...result, decision: \"holds\", why: `${counts}; ${centre}` };\n const decision = counted.length < STEPS[2] ? \"extend\" : \"inconclusive\";\n return { ...result, decision, why: `${counts}; ${centre} straddles the band` };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, Jitter, KernelRecord, ProbeEvent, Reconnects, Run } from \"./cell.ts\";\nimport { NOISE } from \"./verdict.ts\";\n\n/**\n * This module reads the acts of the program of the observer: its heartbeat, its drop of the\n * connection, its reconnect and its call in flight. The kernel has no report of a detection by\n * a program. Thus the program writes a line before each of its own acts, on CLOCK_MONOTONIC:\n * - `ping` before each ping of its heartbeat, and `drop` before it closes the connection by itself.\n * - `reconnecting` when it starts its reconnect timer, and `dial` before each new connection.\n *\n * The kernel then stamps each write of the program on the socket (`tx`) and each change of the\n * state of the socket. A line of the client names its socket by its local address (`local`), and\n * a line of a server names it by its peer (`peer`).\n */\n\n/**\n * This time bounds the handling of a drop by the program of the observer. It starts when the timer\n * of the program fires. It ends at the kernel's stamp of the act: the write of a close frame, or\n * the close of the socket. The `drop` line comes in that time, before the act.\n *\n * This bound is not δ_abs. δ_abs is the noise of the pipeline, and stage 0 calibrates it from a\n * reset. The handling is the time of the code of the program, and it is longer:\n * - No source and no machine document bounds it (`http/timers.ts` of `@mark1russell7/machines`).\n * - The handling time of the HTTP cells (`HANDLING` in `packages/cells/src/http/race.ts`) is\n * another act. It is the first reply of a new process, up to 11.182 ms.\n * - A drop comes from a timer, long after the start of the process.\n *\n * The bound comes from the CI records of the WS and WST cells, from the `drop` line to the act:\n * - 585 drops with a close frame had a median of 0.652 ms, a 99th percentile of 0.87 ms and a\n * maximum of 1.017 ms.\n * - 559 drops with a close of the socket had a maximum of 0.914 ms.\n * - Two drops took more than the δ_abs of 1 ms. Each failed its cell, and its time was in the band.\n * These are the runs 39390222333 and 39903020657 of the client repository.\n *\n * The bound is 1.5 ms: the maximum and a margin of 0.48 ms. The pairing of a drop with its act\n * uses it, or the pairing window of the run when that window is longer. The band of a drop adds\n * it to its high bound (the WS catalog of the cells). Read the records again after a change to the subject, to Node or to\n * the runners.\n */\nexport const DROP_HANDLING: Quantity = quantity(1.5, \"ms\");\n\n/** This function gives the window of the act of a drop, in seconds: `DROP_HANDLING`, or the pairing window (`delta`) when it is longer. */\nconst dropWindow = (delta: Quantity): number => Math.max(valueIn(DROP_HANDLING, \"s\"), valueIn(delta, \"s\"));\n\n/** This function gives the interval between two instants on the one clock, in seconds to the microsecond. */\nconst between = (from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\n/** This function gives the state of a state record after the change, and before it. TCP_ESTABLISHED is 1, TCP_SYN_SENT 2. */\nconst newState = (record: KernelRecord): number | undefined => (record as { readonly new?: number }).new;\nconst oldState = (record: KernelRecord): number | undefined => (record as { readonly old?: number }).old;\n\n/**\n * A program event is a line of the program of the observer, with the kernel's stamp of its act.\n * The act is a write, or a change of state of the socket. Without a record of the kernel in its\n * window after the line, the instant is the stamp of the line. The window is the pairing window of\n * the run (`pairingOf`), and for a drop it is `DROP_HANDLING` when that is longer.\n */\nexport interface ProgramEvent {\n readonly line: ProbeEvent;\n readonly at: number;\n /** This flag tells that the kernel stamped the event. */\n readonly kernel: boolean;\n /** This name is the kind of the record of the kernel: a write, or a change of state. It is null without a record. */\n readonly record: \"write\" | \"state\" | null;\n}\n\n/** This function gives the lines of the program of the observer: the client, or the target for the server. A proxy has no lines. */\nexport const programLines = (cell: Cell, run: Run): readonly ProbeEvent[] => {\n const observer = cell.observer ?? \"client\";\n if (observer === \"client\") return run.events;\n if (observer === \"server\") return run.server ?? [];\n return [];\n};\n\n/**\n * This function tells if a line of the program is about the connection of the run. The client\n * names it by its local address, and a server by its peer. A line with neither is about the one\n * connection of its program. A line whose address is null is about a socket that did not open:\n * a try that failed.\n */\nconst onConnection = (line: ProbeEvent, local: unknown): boolean => {\n if (!(\"local\" in line) && !(\"peer\" in line)) return true;\n return (line[\"local\"] ?? line[\"peer\"]) === local;\n};\n\n/** This function gives the first record of a socket that matches, at the stamp of a line or in a window (`delta`) after it. */\nconst kernelAt = (\n socket: readonly KernelRecord[],\n line: ProbeEvent,\n matches: (record: KernelRecord) => boolean,\n delta: Quantity,\n): KernelRecord | undefined => {\n const noise = valueIn(delta, \"s\") * 1e9;\n return socket.find((record) => record.mono >= line.t && record.mono <= line.t + noise && matches(record));\n};\n\nconst eventOf = (\n socket: readonly KernelRecord[],\n line: ProbeEvent,\n matches: (record: KernelRecord) => boolean,\n delta: Quantity = NOISE,\n): ProgramEvent => {\n const record = kernelAt(socket, line, matches, delta);\n return {\n line,\n at: record?.mono ?? line.t,\n kernel: record !== undefined,\n record: record === undefined ? null : record.ev === \"tx\" ? \"write\" : \"state\",\n };\n};\n\n/**\n * This function gives the time from a line of the program to the close of the socket by its own\n * side. That close is its change from ESTABLISHED to FIN_WAIT1, or to CLOSE (an abort). A FIN of\n * the peer (CLOSE_WAIT) is not such a close. It is null when the socket did not close itself.\n */\nexport const leftAfter = (socket: readonly KernelRecord[], line: ProbeEvent): Quantity | null => {\n const left = socket.find(\n (record) => record.ev === \"state\" && oldState(record) === 1 && (newState(record) === 4 || newState(record) === 7) && record.mono >= line.t,\n );\n return left === undefined ? null : between(line.t, left.mono);\n};\n\n/**\n * This function gives the end of the client process in a run, as the kernel stamps it. The process\n * ends after its last try, and its kernel then closes each socket that is still open, at one\n * instant. Thus the end is the first change out of ESTABLISHED of another socket of the client\n * after its last `dial` line. The program dropped none of these sockets. It is undefined when the\n * record has no such change, for example when the last try did not open.\n */\nexport const exitOf = (run: Run, cookie: number | undefined): number | undefined => {\n const last = run.events.filter((line) => line.ev === \"dial\").at(-1);\n if (last === undefined) return undefined;\n const dropped = new Set(run.events.filter((line) => line.ev === \"drop\").map((line) => line[\"local\"]));\n return run.kernel.find(\n (record) =>\n record.netns === run.netns &&\n record.cookie !== cookie &&\n record.ev === \"state\" &&\n oldState(record) === 1 &&\n (newState(record) === 4 || newState(record) === 7) &&\n record.mono >= last.t &&\n !dropped.has(record.src),\n )?.mono;\n};\n\n/**\n * This function separates a close of the socket by the program from the end of the client process.\n * `left` is the time from the drop line to the close, and `exit` is the end of the process. A close\n * in δ_abs of that end is the end, not the program: `left` becomes null, and `exited` keeps the time.\n */\nexport const closeOrExit = (\n line: ProbeEvent,\n left: Quantity | null,\n exit: number | undefined,\n delta: Quantity = NOISE,\n): { readonly left: Quantity | null; readonly exited?: Quantity } => {\n if (left === null || exit === undefined) return { left };\n const at = line.t + valueIn(left, \"s\") * 1e9;\n return Math.abs(at - exit) <= valueIn(delta, \"s\") * 1e9 ? { left: null, exited: left } : { left };\n};\n\n/**\n * This function tells how a drop differs from the way that its prediction gives, or gives null.\n * A close closes the socket at once, in the handling time of the program (`DROP_HANDLING`). If\n * the pairing window of the run (`delta`) is longer, that window is the limit. A close frame is a\n * write, and the program does not close the socket at the drop. A peer that answers the close frame can close it, and that is no finding.\n */\nexport const dropFinding = (\n expected: \"frame\" | \"close\",\n drop: ProgramEvent,\n left: Quantity | null,\n delta: Quantity = NOISE,\n exited?: Quantity,\n): string | null => {\n const noise = dropWindow(delta);\n const soon = left !== null && valueIn(left, \"s\") <= noise;\n if (expected === \"close\") {\n if (left === null)\n return `the program did not close its socket after the drop, where a close is at once${exited === undefined ? \"\" : \": it stayed open until the client process ended\"}`;\n return soon ? null : `the program closed its socket ${left.value} s after the drop, not at once`;\n }\n if (drop.record !== \"write\") return \"the drop wrote no close frame on its socket\";\n return soon ? \"the program closed its socket at the drop, where a close frame leaves it open\" : null;\n};\n\nconst isWrite = (record: KernelRecord): boolean => record.ev === \"tx\";\n\n/**\n * This function measures the jitter of a program from its acts before `until`, the start of the\n * fault. An act is a `write` line or a `ping` line on the connection. Its delay goes from the line\n * to the first write of data on the socket after it, before the next act and before `until`. An\n * act with no such write does not count. The bound is the longest delay, to the microsecond.\n */\nexport const jitterOfLines = (\n lines: readonly ProbeEvent[],\n socket: readonly KernelRecord[],\n local: unknown,\n until: number,\n): Jitter => {\n const acts = lines.filter((line) => (line.ev === \"write\" || line.ev === \"ping\") && line.t < until && onConnection(line, local));\n const delays = acts.flatMap((line, at) => {\n const next = Math.min(acts[at + 1]?.t ?? until, until);\n const write = socket.find((record) => isWrite(record) && (record.seg?.len.value ?? 0) > 0 && record.mono >= line.t && record.mono < next);\n return write === undefined ? [] : [write.mono - line.t];\n });\n return {\n acts: delays.length,\n bound: delays.length === 0 ? null : quantity(Math.round(Math.max(...delays) / 1e3) / 1e3, \"ms\"),\n };\n};\n\n/** This function gives each ping of the program on the connection, with the kernel's stamp of its write in the pairing window (`delta`). */\nexport const pingsOf = (\n lines: readonly ProbeEvent[],\n socket: readonly KernelRecord[],\n local: unknown,\n delta: Quantity = NOISE,\n): ProgramEvent[] =>\n lines.filter((line) => line.ev === \"ping\" && onConnection(line, local)).map((line) => eventOf(socket, line, isWrite, delta));\n\n/**\n * This function gives the first ping that got no answer: no segment with data reached the socket\n * after its write, up to `until`. Its write starts the wait of the heartbeat that the fault met.\n */\nexport const firstUnanswered = (\n pings: readonly ProgramEvent[],\n socket: readonly KernelRecord[],\n until: number = Number.POSITIVE_INFINITY,\n): ProgramEvent | undefined =>\n pings\n .filter((ping) => ping.at <= until)\n .find(\n (ping) =>\n !socket.some((record) => record.ev === \"rx\" && (record.seg?.len.value ?? 0) > 0 && record.mono > ping.at && record.mono <= until),\n );\n\n/**\n * This function gives the first drop of the connection by its program. The kernel stamps it as the\n * write of a close frame. Or it stamps the change of the socket out of ESTABLISHED: a close or an\n * abort. That stamp comes in the handling time of the program after the drop line\n * (`DROP_HANDLING`). If the pairing window of the run (`delta`) is longer, that window is the limit.\n */\nexport const dropOf = (\n lines: readonly ProbeEvent[],\n socket: readonly KernelRecord[],\n local: unknown,\n delta: Quantity = NOISE,\n): ProgramEvent | undefined => {\n const line = lines.find((each) => each.ev === \"drop\" && onConnection(each, local));\n return line === undefined\n ? undefined\n : eventOf(socket, line, (record) => isWrite(record) || (record.ev === \"state\" && oldState(record) === 1), quantity(dropWindow(delta), \"s\"));\n};\n\n/** A reconnect reading is what the client did after the detection, from its lines and from the records of the kernel. */\nexport interface ReconnectReading {\n /** These are the waits of the program before each try: from a `reconnecting` line to the next `dial` line. */\n readonly waits: readonly Quantity[];\n /** This time is from the detection to the first SYN of a new socket. The kernel stamps the change to SYN_SENT at connect(2). */\n readonly syn: Quantity | null;\n /** This time is from the detection to the first new socket of the client that became ESTABLISHED. */\n readonly established: Quantity | null;\n /** These are the times from each `dial` line after the detection to the SYN of its socket: the work of the program before connect(2). */\n readonly connects: readonly Quantity[];\n}\n\n/**\n * This function reads the reconnect of the client after the detection at `detected`. The socket of\n * the run has the cookie `cookie`. The lines of the program count from `from`: the drop line of a\n * drop, which comes before the kernel's stamp of it.\n */\nexport const reconnectOf = (run: Run, detected: number, cookie: number | undefined, from: number = detected): ReconnectReading => {\n const after = run.events.filter((line) => line.t > from);\n const starts = after.filter((line) => line.ev === \"reconnecting\");\n const dials = after.filter((line) => line.ev === \"dial\");\n const waits = starts.flatMap((start, at) => {\n const next = starts[at + 1]?.t ?? Number.POSITIVE_INFINITY;\n const dial = dials.find((each) => each.t >= start.t && each.t < next);\n return dial === undefined ? [] : [between(start.t, dial.t)];\n });\n const fresh = run.kernel.filter((record) => record.netns === run.netns && record.cookie !== cookie && record.ev === \"state\" && record.mono > detected);\n const syns = fresh.filter((record) => newState(record) === 2);\n const established = fresh.find((record) => newState(record) === 1);\n const connects = dials.flatMap((dial) => {\n const syn = syns.find((record) => record.mono >= dial.t);\n return syn === undefined ? [] : [between(dial.t, syn.mono)];\n });\n return {\n waits,\n syn: syns[0] === undefined ? null : between(detected, syns[0].mono),\n established: established === undefined ? null : between(detected, established.mono),\n connects,\n };\n};\n\n/** This function tells how the waits of a reconnect differ from their bands, each widened by δ_abs, or gives null. */\nexport const reconnectFinding = (expected: Reconnects, read: ReconnectReading, delta: Quantity = NOISE): string | null => {\n const noise = valueIn(delta, \"s\");\n const round = (value: number) => Math.round(value * 1e6) / 1e6;\n const found = expected.waits.flatMap((band, at) => {\n const wait = read.waits[at];\n if (wait === undefined) return [`the client made no try ${at + 1} after the detection`];\n const value = valueIn(wait, \"s\");\n const low = round(valueIn(band.low, \"s\") - noise);\n const high = round(valueIn(band.high, \"s\") + noise);\n return value < low || value > high ? [`its wait before try ${at + 1} was ${value} s, outside [${low}, ${high}] s`] : [];\n });\n return found.length === 0 ? null : found.join(\". \");\n};\n\n/**\n * A call reading is what the call in flight of a WebSocket client met: its error, a reply, or\n * nothing in the run. The time counts from the detection to its end.\n */\nexport interface CallReading {\n readonly outcome: string;\n readonly after: Quantity | null;\n}\n\n/** This function reads the call that the client sent into the fault: its `call-error` or `data` line after the request. */\nexport const callOf = (events: readonly ProbeEvent[], request: ProbeEvent, detected: number | undefined): CallReading => {\n const end = events.find((line) => (line.ev === \"call-error\" || line.ev === \"data\") && line.t > request.t);\n if (end === undefined) return { outcome: \"pending\", after: null };\n const outcome = end.ev === \"data\" ? \"a reply\" : String(end[\"message\"] ?? end[\"code\"] ?? \"an error\");\n return { outcome, after: detected === undefined ? null : between(detected, end.t) };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, DriverBand, KernelRecord, LineCount, LineMatch, ProbeEvent, Reference, Run } from \"./cell.ts\";\nimport { requestFirst } from \"./cell.ts\";\nimport type { Measured, Outcome } from \"./observe.ts\";\nimport { INJECT, delayVoids, noiseOf } from \"./verdict.ts\";\n\n/**\n * This module measures a run of a cell whose client is a driver with more than one socket, for\n * example the MongoDB driver. Its monitor, its pool and its round-trip pinger each have their own\n * socket, and the client names each socket by its role. A band counts from an event of one socket,\n * as the kernel records it. It ends at a line of the client, or at the report of the kernel on\n * that socket.\n */\n\n/** A driver socket is one socket of the driver in a run: its role, its local address, its server, and when it opened and ended. */\nexport interface DriverSocket {\n readonly role: string;\n readonly local: string;\n readonly server: string;\n readonly opened: number;\n readonly ended: number | null;\n}\n\n/** A driver step time is the time of one later band of a run. It is null when its line did not come. */\nexport interface DriverStepTime {\n readonly what: string;\n readonly name: string | null;\n readonly elapsed: Quantity | null;\n}\n\n/** These are the errno numbers that the kernel reports to a socket, by the names that predictions use. */\nconst ERRNO: Readonly<Record<number, string>> = {\n 32: \"EPIPE\",\n 101: \"ENETUNREACH\",\n 103: \"ECONNABORTED\",\n 104: \"ECONNRESET\",\n 110: \"ETIMEDOUT\",\n 111: \"ECONNREFUSED\",\n 113: \"EHOSTUNREACH\",\n};\n\nconst between = (from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\nconst round = (seconds: number): number => Math.round(seconds * 1e6) / 1e6;\n\n/** This function gives the value of a field of a line by its name. A dotted name is a field in a field. */\nexport const fieldOf = (line: unknown, path: string): unknown =>\n path.split(\".\").reduce<unknown>((value, key) => (value !== null && typeof value === \"object\" ? (value as Record<string, unknown>)[key] : undefined), line);\n\n/** This function tells if a line of the client matches a line match: its `ev`, and each field that the match names. */\nexport const matches = (line: ProbeEvent, match: LineMatch): boolean =>\n line.ev === match.ev && Object.entries(match.where ?? {}).every(([path, value]) => fieldOf(line, path) === value);\n\n/** This function gives the count of the lines that match. */\nexport const countOf = (lines: readonly ProbeEvent[], match: LineMatch): number => lines.filter((line) => matches(line, match)).length;\n\n/** This function gives the finding of the line counts of a run, or null when each count is the exact one. */\nexport const countFinding = (counts: readonly LineCount[], lines: readonly ProbeEvent[]): string | null => {\n const off = counts.flatMap((each) => {\n const seen = countOf(lines, each.match);\n return seen === each.count ? [] : [`${each.what}: ${seen} lines, and the law gives ${each.count}`];\n });\n return off.length === 0 ? null : off.join(\"; \");\n};\n\n/** This function says a line match in words, for a finding. */\nexport const wordsOf = (match: LineMatch): string => {\n const where = Object.entries(match.where ?? {}).map(([path, value]) => `${path} ${String(value)}`);\n return where.length === 0 ? `a ${match.ev} line` : `a ${match.ev} line with ${where.join(\", \")}`;\n};\n\n/** This function gives the sockets of the driver in a run, from the `socket` and `socket-end` lines of the client. */\nexport const socketsOf = (events: readonly ProbeEvent[]): DriverSocket[] =>\n events\n .filter((event) => event.ev === \"socket\")\n .map((event) => {\n const local = String(event[\"local\"]);\n const end = events.find((each) => each.ev === \"socket-end\" && each[\"local\"] === local && each.t >= event.t);\n return { role: String(event[\"role\"]), local, server: String(event[\"server\"]), opened: event.t, ended: end?.t ?? null };\n });\n\n/**\n * This function finds the socket of a role at an instant. The pool's socket is the first one, which\n * the client names in its `connected` line. Each other role has the latest socket that opened at\n * the instant or before it.\n */\nexport const socketAt = (events: readonly ProbeEvent[], role: string, at: number): DriverSocket | undefined => {\n const sockets = socketsOf(events);\n if (role === \"pool\") {\n const local = events.find((event) => event.ev === \"connected\")?.[\"local\"];\n return sockets.find((socket) => socket.local === local);\n }\n return sockets.filter((socket) => socket.role === role && socket.opened <= at).at(-1);\n};\n\n/** A kernel place is the namespace and the cookie of a socket, and its records in the run. */\ninterface KernelPlace {\n readonly netns: number;\n readonly cookie: number;\n readonly records: readonly KernelRecord[];\n}\n\nconst placeOf = (run: Run, netns: number, find: (record: KernelRecord) => boolean): KernelPlace | undefined => {\n const cookie = run.kernel.find((record) => record.netns === netns && find(record))?.cookie;\n if (cookie === undefined) return undefined;\n return { netns, cookie, records: run.kernel.filter((record) => record.netns === netns && record.cookie === cookie) };\n};\n\nconst portOf = (address: string): string => address.split(\":\").at(-1) ?? \"\";\n\n/**\n * This function gives the socket of the target for a socket of the client. In a direct pair, its\n * peer is the address of the client socket. Behind a router, its peer is the address of the router\n * with the port of the client socket. The router keeps the port when it is free.\n */\nconst peerPlace = (run: Run, local: string): KernelPlace | undefined => {\n const peer = run.topology === undefined ? local : `${run.topology.targetPeer}:${portOf(local)}`;\n return placeOf(run, run.targetNetns, (record) => record.dst === peer);\n};\n\n/**\n * This function gives the socket that a hop of the topology opens toward its target in the run. It is\n * the first one that moves to SYN_SENT after the outset. A pooler connects to the server by itself,\n * thus no line of the client names that socket. The last hop goes first, because it faces the target.\n */\nconst upstreamOf = (run: Run): KernelPlace | undefined => {\n if (run.topology === undefined) return undefined;\n const outset = outsetOf(run);\n for (const hop of Object.values(run.topology.hops).reverse()) {\n const place = placeOf(run, hop.netns, (record) => record.ev === \"state\" && newState(record) === 2 && record.mono >= outset && record.dst === hop.target);\n if (place !== undefined) return place;\n }\n return undefined;\n};\n\n/**\n * This function gives the kernel place of a socket of a role at an instant. The role `server` is a\n * socket of the target, and the role `upstream` is the socket that a hop opens toward the target.\n */\nconst kernelOf = (run: Run, role: string, at: number): { socket: DriverSocket | undefined; place: KernelPlace | undefined } => {\n if (role === \"upstream\") return { socket: undefined, place: upstreamOf(run) };\n if (role === \"server\") {\n const pool = socketAt(run.events, \"pool\", at);\n return { socket: pool, place: pool === undefined ? undefined : peerPlace(run, pool.local) };\n }\n const socket = socketAt(run.events, role, at);\n return { socket, place: socket === undefined ? undefined : placeOf(run, run.netns, (record) => record.src === socket.local) };\n};\n\nconst newState = (record: KernelRecord): number | undefined => (record as { readonly new?: number }).new;\nconst oldState = (record: KernelRecord): number | undefined => (record as { readonly old?: number }).old;\n\n/** This function gives the instant that a run starts to look for its outcome. It is the fault, the reply before it, or the start of the client. */\nconst outsetOf = (run: Run): number => {\n const ready = run.events.find((event) => event.ev === \"ready\");\n return run.fault?.t0 ?? ready?.t ?? run.events[0]?.t ?? 0;\n};\n\n/**\n * This function gives the instant of a reference in a run, on a socket of the driver:\n * - `last-received`: the last segment that the socket received before the fault held. A band of\n * the kernel counts from the last segment of any kind. A band that a line ends is a timer of\n * the driver. It counts from the last segment with data that the socket received or sent.\n * - `request-sent`: the send of the operation into the fault, the second `sent` line.\n * - `first-retransmission`: the first retransmission of the RTO timer on the socket.\n * - `last-data`: the last segment with data that the socket received or sent before the fault\n * held, for a band of the kernel too. An idle timer of a peer counts from the end of a stream.\n * - `peer-closed`: the change of state of the socket of the target, when its process dies.\n * - `fault`: the start of the commit of the fault. `client-start`: the `connecting` line.\n * - `first-sent`: the first segment with data that the socket sends after the fault.\n * - `last-reply`: the refusal that a retry follows. It is the last segment with data that a socket\n * of the client received before the end of the band (`end`). The retry can go on another socket.\n * A reference that this judge does not know (`ping-sent`) does not come: its band is a finding.\n */\nexport const referenceOf = (run: Run, from: Reference, role: string, data: boolean, end: number = Infinity): number | undefined => {\n const ready = run.events.find((event) => event.ev === \"ready\");\n const before = run.fault?.t1 ?? ready?.t ?? Infinity;\n if (from === \"fault\") return run.fault?.t0;\n if (from === \"client-start\") return (run.events.find((event) => event.ev === \"connecting\") ?? run.events[0])?.t;\n if (from === \"request-sent\") return run.events.filter((event) => event.ev === \"sent\")[1]?.t;\n // a retry can go on a new connection: its refusal is the last data that a socket of the client got\n if (from === \"last-reply\")\n return run.kernel.filter((record) => record.netns === run.netns && record.mono < end && record.ev === \"rx\" && (record.seg?.len.value ?? 0) > 0).at(-1)?.mono;\n const { socket, place } = kernelOf(run, role, before);\n if (place === undefined) return undefined;\n if (from === \"last-received\" || from === \"last-data\") {\n // the idle timer of a Node socket starts again at each read and at each write of data\n const withData = data || from === \"last-data\";\n const counts = (record: KernelRecord) =>\n withData ? (record.ev === \"rx\" || record.ev === \"tx\") && (record.seg?.len.value ?? 0) > 0 : record.ev === \"rx\";\n return place.records.filter((record) => record.mono <= before && counts(record)).at(-1)?.mono;\n }\n if (from === \"first-sent\")\n return place.records.find((record) => record.ev === \"tx\" && record.mono > before && (record.seg?.len.value ?? 0) > 0)?.mono;\n // the connect of the socket: its change to SYN_SENT, which the kernel stamps when it sends the SYN\n if (from === \"syn-sent\") return place.records.find((record) => record.ev === \"state\" && newState(record) === 2)?.mono;\n if (from === \"first-retransmission\") {\n const request = run.events.filter((event) => event.ev === \"sent\")[1]?.t ?? before;\n return place.records.find((record) => record.ev === \"retrans\" && record.why === \"rto\" && record.mono > request)?.mono;\n }\n // before 0.11.22 an unknown reference fell to the close of the peer: through a proxy, that was the\n // first close of a socket of the target, for example the idle close of an upstream connection\n if (from !== \"peer-closed\") return undefined;\n // the close of the peer: the socket of the target leaves ESTABLISHED\n const peer = socket === undefined ? undefined : peerPlace(run, socket.local);\n const closed = peer?.records.find((record) => record.ev === \"state\" && oldState(record) === 1)?.mono;\n if (closed !== undefined || run.topology === undefined) return closed;\n return proxiedClose(run);\n};\n\n/**\n * This function gives the close of the target behind a proxy. It is the first socket of the target\n * toward the last hop that leaves ESTABLISHED after the outset. A proxy opens its own connection to the\n * target, with a port of its own, and a pooler keeps it across its clients. Thus no socket of the\n * target has the port of the client, and the one of the run can be older than the run. The death of\n * the process of the target closes each of them at once.\n */\nexport const proxiedClose = (run: Run): number | undefined => {\n if (run.topology === undefined) return undefined;\n const hop = run.topology.targetPeer;\n const outset = outsetOf(run);\n return run.kernel.find(\n (record) =>\n record.netns === run.targetNetns && record.ev === \"state\" && oldState(record) === 1 && record.mono >= outset && record.dst !== undefined && ipOf(record.dst) === hop,\n )?.mono;\n};\n\n/** This function gives the address of an address with its port. */\nconst ipOf = (address: string): string => address.slice(0, address.lastIndexOf(\":\"));\n\n/** This function gives the first line of the client that matches, after an instant. */\nconst lineAfter = (events: readonly ProbeEvent[], match: LineMatch, after: number): ProbeEvent | undefined =>\n events.find((event) => event.t > after && matches(event, match));\n\n/** This function gives the name of the error of a line: the field that the match names, or `name`. */\nconst nameOf = (line: ProbeEvent, match: LineMatch): string => String(fieldOf(line, match.name ?? \"name\") ?? line.ev);\n\n/**\n * This function gives the report of the kernel on a socket after an instant: an error, or the end of\n * the file (CLOSE_WAIT). With neither, a close of the socket in SYN_SENT is the end. The program gave\n * up on its connect, and the kernel reports no error and sends no FIN. A refused connect also leaves\n * SYN_SENT, but it has its error.\n */\nconst reportOf = (place: KernelPlace, after: number): { at: number; outcome: Outcome } | undefined => {\n const report = place.records.find(\n (record) => record.mono > after && ((record.ev === \"error\" && (record.err ?? 0) !== 0) || (record.ev === \"state\" && newState(record) === 8)),\n );\n if (report === undefined) {\n const given = place.records.find((record) => record.mono > after && record.ev === \"state\" && oldState(record) === 2 && newState(record) === 7);\n return given === undefined ? undefined : { at: given.mono, outcome: { kind: \"closed\" } };\n }\n return report.ev === \"error\"\n ? { at: report.mono, outcome: { kind: \"error\", errno: ERRNO[report.err!] ?? `E${report.err}` } }\n : { at: report.mono, outcome: { kind: \"eof\" } };\n};\n\n/**\n * This function gives the latest instant of the bands of a driver prediction, in seconds from their\n * references. A band from the refusal before it (`last-reply`) follows the band before it. Thus the\n * times of those bands add: five retries of 30 s end 150 s after the first refusal.\n */\nexport const longestOf = (cell: Cell): number => {\n const { prediction } = cell;\n if (prediction.detects === null) return valueIn(prediction.window, \"s\");\n const then = prediction.driver?.then ?? [];\n const steps = then.map((step) => valueIn(step.high, \"s\"));\n const own = prediction.detects ? valueIn(prediction.high, \"s\") : valueIn(prediction.window, \"s\");\n const chained = [...(prediction.detects && prediction.from === \"last-reply\" ? [own] : []), ...then.filter((step) => step.from === \"last-reply\").map((step) => valueIn(step.high, \"s\"))];\n return Math.max(own, ...steps, chained.reduce((total, high) => total + high, 0));\n};\n\n/**\n * This function tells if a run of a driver cell has its outcome, so that its wait can stop. For a\n * detection, the outcome is the end of its band and of each later band. A silent prediction waits\n * for its window.\n */\nexport const settled = (cell: Cell, run: Run): boolean => {\n const { prediction } = cell;\n if (prediction.detects !== true || prediction.driver === undefined) return false;\n const driver: DriverBand = prediction.driver;\n const after = outsetOf(run);\n const ended =\n driver.ends === undefined\n ? (() => {\n const { place } = kernelOf(run, driver.socket, run.fault?.t1 ?? after);\n return place !== undefined && reportOf(place, after) !== undefined;\n })()\n : lineAfter(run.events, driver.ends, after) !== undefined;\n return ended && (driver.then ?? []).every((step) => lineAfter(run.events, step.ends, after) !== undefined);\n};\n\n/**\n * This function examines the keepalive timer of a socket between two instants. A firing two\n * jiffies or more behind its wheel slot was delayed by the host, which stopped a vCPU. A firing\n * that found the socket held by its owner put itself off by HZ/20. Either way, the run measured\n * something other than the timer.\n */\nconst delayed = (place: KernelPlace, from: number, to: number, hz: number | undefined, noise: Quantity): string | null => {\n const firings = place.records.filter((record) => record.ev === \"timer\" && record.what === \"keepalive\" && record.mono >= from && record.mono <= to);\n const late = firings.find((record) => delayVoids(record.behind?.value ?? 0, hz, noise));\n if (late !== undefined) return `its keepalive timer ran ${late.behind!.value} jiffies behind its wheel slot: the VM delayed it, not the kernel`;\n const held = firings.find((record) => record.owned === true);\n return held === undefined ? null : \"its keepalive timer found the socket held by its owner and put itself off by HZ/20: the run measured the owner, not the timer\";\n};\n\n/**\n * This function reads one run of a driver cell.\n * - The band of the cell counts from its reference on its socket. It ends at its line, or at the\n * report of the kernel on that socket.\n * - Each later band (`then`) gets the same test. A later band outside its band, or absent, is a finding.\n * - A line that the prediction names as quiet, after the fault and in its window, is a finding.\n * So is a flow of an open socket of the driver that a router forgot, for a silent prediction.\n * A prediction with `middlebox.forgets` gives a band for the flow of the socket of the driver. The\n * band counts from the last segment that the socket got before the fault.\n * - A silent prediction can time a reply (`reply`), and the verdict tests it against `replies`.\n *\n * A run is void when the prober lost records, or when the client did not get its first reply. It\n * is also void when the operation went out before the fault held. A late lift of a hold and a\n * keepalive probe before the fault also make it void. So do a delayed timer and a round trip\n * above the assumption.\n */\nexport const measureDriver = (cell: Cell, run: Run): Measured => {\n const { prediction } = cell;\n if (prediction.detects === null || prediction.driver === undefined) throw new Error(`${cell.name} has no driver band`);\n const driver = prediction.driver;\n const { events } = run;\n const ready = events.find((event) => event.ev === \"ready\");\n const request = events.filter((event) => event.ev === \"sent\")[1];\n const after = outsetOf(run);\n const before = run.fault?.t1 ?? ready?.t ?? after;\n const { place } = kernelOf(run, driver.socket, before);\n const records = place?.records ?? [];\n const pool = kernelOf(run, \"pool\", before).place;\n const srtt = pool?.records.find((record) => record.tcp?.srtt !== undefined)?.tcp?.srtt;\n const rtt = srtt === undefined ? null : quantity(valueIn(srtt, \"us\") / 1000, \"ms\");\n const base = {\n environment: run.environment,\n index: run.index,\n probes: records.filter((record) => record.ev === \"probe\" && record.what === \"keepalive\").length,\n retransmissions: records.filter((record) => record.ev === \"retrans\").length,\n acks: request === undefined ? 0 : records.filter((record) => record.ev === \"rx\" && record.mono > request.t).length,\n rtt,\n };\n const nothing = { outcome: { kind: \"silent\" } as const, elapsed: null, socket: null, noticed: null, steps: [], finding: null };\n\n if (cell.before !== true && ready === undefined) return { ...base, ...nothing, void: \"the client never had its reply\" };\n if (run.lost === null) return { ...base, ...nothing, void: \"the prober wrote no clock line after the run, so nothing says what it dropped\" };\n if (run.lost > 0) return { ...base, ...nothing, void: `the prober dropped ${run.lost} records` };\n\n let voided: string | null = null;\n if (cell.probe.mode !== \"idle\" && cell.before !== true) {\n if (request === undefined) voided = \"the operation was never sent into the fault\";\n else if (requestFirst(cell)) {\n // an event at a hop that comes while the operation is in flight: the operation goes first\n if (run.fault !== null && run.fault.t0 < request.t) voided = \"the event came before the operation\";\n } else if (run.fault !== null && run.fault.t1 > request.t) voided = \"the operation went out before the fault held\";\n }\n const keepalive = records.find((record) => record.ev === \"probe\" && record.what === \"keepalive\");\n if (voided === null && run.fault !== null && keepalive !== undefined && keepalive.mono < run.fault.t1)\n voided = \"a keepalive probe went out before the fault held\";\n if (voided === null && cell.hold !== undefined && run.fault !== null) {\n const heal = run.heal ?? null;\n if (heal === null) voided = \"the fault never lifted\";\n else {\n const late = (heal.t0 - run.fault.t0) / 1e9 - valueIn(cell.hold, \"s\");\n if (late > valueIn(INJECT, \"s\")) voided = `the lift came ${Math.round(late * 1e4) / 10} ms after its hold: the injector was late, not the client`;\n }\n }\n const assumed = prediction.rtt;\n if (voided === null && assumed !== undefined && rtt !== null && valueIn(rtt, \"ms\") > valueIn(assumed.high, \"ms\"))\n voided = `rtt-over-assumption: its first round trip was ${rtt.value} ms, above the ${valueIn(assumed.high, \"ms\")} ms that the prediction assumes`;\n\n const findings: string[] = [];\n const noise = valueIn(noiseOf(cell), \"s\");\n // the end of the window: the window of a silent prediction, or the end of the run\n const until = prediction.detects ? Infinity : after + valueIn(prediction.window, \"s\") * 1e9;\n for (const match of driver.quiet ?? []) {\n const line = events.find((event) => event.t > after && event.t <= until && matches(event, match));\n if (line !== undefined) findings.push(`${wordsOf(match)} came ${between(after, line.t).value} s after the fault, where none should`);\n }\n const expected = prediction.detects ? undefined : prediction.middlebox?.forgets;\n if (!prediction.detects && (run.middlebox !== undefined || expected !== undefined)) {\n // a router forgets a flow of a socket that is still open: the flow of a live connection is gone,\n // unless the prediction says when the router forgets the flow of the socket of the driver\n const own = socketAt(events, driver.socket, before)?.local;\n if (expected !== undefined && own === undefined) findings.push(`the client opened no ${driver.socket} socket before the fault`);\n const middlebox: NonNullable<Run[\"middlebox\"]> = run.middlebox ?? [];\n for (const socket of socketsOf(events)) {\n const forgot = middlebox.find(\n (line) =>\n line.ev === \"ct\" &&\n line[\"type\"] === \"DESTROY\" &&\n String(line[\"orig\"] ?? \"\").startsWith(`${socket.local}>`) &&\n line.t > socket.opened &&\n (socket.ended === null || line.t < socket.ended) &&\n line.t <= until,\n );\n if (expected === undefined || socket.local !== own) {\n if (forgot !== undefined) findings.push(`a router forgot the flow of the ${socket.role} socket ${between(after, forgot.t).value} s after the fault, where it should keep it`);\n continue;\n }\n // the band counts from the last segment that the socket got before the fault, as for the client of TCP\n const last = referenceOf(run, \"last-received\", driver.socket, false);\n if (forgot === undefined) findings.push(`no router forgot the flow of the ${socket.role} socket in the window, where it should forget it`);\n else if (last === undefined) findings.push(`the ${socket.role} socket got no segment before the fault`);\n else {\n const at = between(last, forgot.t).value;\n const [low, high] = [round(valueIn(expected.low, \"s\") - noise), round(valueIn(expected.high, \"s\") + noise)];\n if (at < low || at > high) findings.push(`a router forgot the flow of the ${socket.role} socket ${at} s after its last segment, outside [${low}, ${high}] s`);\n }\n }\n }\n const stepTimes: DriverStepTime[] = (driver.then ?? []).map((step) => {\n const line = lineAfter(events, step.ends, after);\n const from = referenceOf(run, step.from, step.socket ?? driver.socket, true, line?.t);\n if (line === undefined || from === undefined) {\n findings.push(line === undefined ? `${step.what}: ${wordsOf(step.ends)} never came` : `${step.what}: its reference (${step.from}) never came`);\n return { what: step.what, name: line === undefined ? null : nameOf(line, step.ends), elapsed: null };\n }\n const elapsed = between(from, line.t);\n const name = nameOf(line, step.ends);\n if (step.name !== \"OK\" && name !== step.name) findings.push(`${step.what}: it ended with ${name}, not ${step.name}`);\n const [low, high] = [round(valueIn(step.low, \"s\") - noise), round(valueIn(step.high, \"s\") + noise)];\n if (elapsed.value < low || elapsed.value > high) findings.push(`${step.what}: ${elapsed.value} s is outside [${low}, ${high}] s`);\n return { what: step.what, name, elapsed };\n });\n const stepped = stepTimes.length === 0 ? {} : { driver: { steps: stepTimes } };\n\n if (!prediction.detects) {\n if (driver.reply === undefined || prediction.replies === undefined)\n return { ...base, ...nothing, ...stepped, void: voided, finding: findings[0] ?? null };\n const line = lineAfter(events, driver.reply.ends, after);\n const from = referenceOf(run, driver.reply.from, driver.socket, true, line?.t);\n if (line === undefined || from === undefined)\n return { ...base, ...nothing, ...stepped, void: voided, finding: findings[0] ?? `the reply never came: ${wordsOf(driver.reply.ends)}` };\n return {\n ...base,\n ...nothing,\n ...stepped,\n outcome: { kind: \"answered\" },\n elapsed: between(from, line.t),\n void: voided,\n finding: findings[0] ?? null,\n };\n }\n\n // the band of the cell: its line, or the report of the kernel on its socket\n const line = driver.ends === undefined ? undefined : lineAfter(events, driver.ends, after);\n const report = driver.ends === undefined && place !== undefined ? reportOf(place, after) : undefined;\n if (driver.ends === undefined && place === undefined)\n return { ...base, ...nothing, ...stepped, void: voided ?? `the prober saw nothing of the ${driver.socket} socket`, finding: findings[0] ?? null };\n const ended = line?.t ?? report?.at;\n const outcome: Outcome =\n line !== undefined && driver.ends !== undefined ? { kind: \"error\", errno: nameOf(line, driver.ends) } : (report?.outcome ?? { kind: \"silent\" });\n if (ended === undefined)\n return { ...base, ...nothing, ...stepped, void: voided, finding: findings[0] ?? `nothing detected it: ${prediction.timer} never fired` };\n const reference = referenceOf(run, prediction.from, driver.socket, driver.ends !== undefined, ended);\n if (reference === undefined)\n return { ...base, ...nothing, ...stepped, outcome, void: voided, finding: `it ended without its reference event (${prediction.from} on the ${driver.socket} socket)` };\n if (driver.ends === undefined && prediction.from === \"last-received\" && place !== undefined) voided ??= delayed(place, reference, ended, run.hz, noiseOf(cell));\n const name = outcome.kind === \"error\" ? outcome.errno : outcome.kind === \"eof\" ? \"EOF\" : outcome.kind === \"closed\" ? \"CLOSED\" : \"silent\";\n if (prediction.errno !== \"OK\" && name !== prediction.errno) findings.unshift(`it ended with ${name}, not ${prediction.errno}`);\n // the client's own view: its first error line after the report of the kernel\n const seen = report === undefined ? undefined : events.find((event) => event.t >= report.at && (event.ev === \"error\" || event.ev === \"socket-error\"));\n return {\n ...base,\n ...stepped,\n outcome,\n elapsed: between(reference, ended),\n socket: seen === undefined ? null : between(reference, seen.t),\n noticed: report === undefined || seen === undefined ? null : between(report.at, seen.t),\n steps: (prediction.from === \"last-received\" ? records.filter((record) => record.ev === \"probe\" && record.what === \"keepalive\" && record.mono > reference) : []).map(\n (record) => between(reference, record.mono),\n ),\n void: voided,\n finding: findings[0] ?? null,\n };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { KernelRecord, ProbeEvent, QueueBand, QueueConnection, QueuePrediction, Run } from \"./cell.ts\";\nimport type { Measured } from \"./observe.ts\";\n\n/** This bit is the SYN of the flags of an `rx` record of the prober. */\nconst SYN = 2;\n\n/** This record is what one connection of a queue cell did, from its lines and the records of its socket. */\nexport interface QueueConnectionReading {\n readonly name: string;\n readonly connected: boolean;\n /** These times are the waits of the SYN. The first one counts from the dial. */\n readonly syns: readonly Quantity[];\n /** These times are the waits of each SYN-ACK sent again. The first one counts from the dial. */\n readonly synAcks: readonly Quantity[];\n /** This count is the segments that the socket sent again. */\n readonly retransmissions: number;\n readonly errno: string | null;\n /** This time is from the line of the prediction to the end of the connection. It is null for a live connection, or with no prediction. */\n readonly ended: Quantity | null;\n /** This time is from the last retransmission to the end of the connection. */\n readonly afterLast: Quantity | null;\n /** This count is the segments of the socket with no acknowledgment at the end of the run. */\n readonly unacked: number | null;\n}\n\n/** This record is what a run of a queue cell measured. The counts are the changes in the run. */\nexport interface QueueReading {\n readonly max: number;\n readonly held: number;\n readonly connected: number;\n readonly overflows: number;\n readonly drops: number;\n readonly cookies: number;\n readonly timeouts: number;\n readonly resets: number;\n readonly drained: number;\n /** This time is from the first dial of the burst to the last `TCPTimeouts` of the prediction. */\n readonly expiry: Quantity | null;\n /** This time is from the first dial of the burst to the rise of the count of the queue. */\n readonly rise: Quantity | null;\n readonly connections: readonly QueueConnectionReading[];\n}\n\n/** This function gives the time between two stamps of CLOCK_MONOTONIC. */\nexport const between = (from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\nconst numberOf = (line: ProbeEvent, field: string): number => {\n const value = line[field];\n return typeof value === \"number\" ? value : 0;\n};\n\n/** This function says if a time is inside a band. */\nexport const inside = (time: Quantity, band: QueueBand): boolean => {\n const seconds = valueIn(time, \"s\");\n return seconds >= valueIn(band.low, \"s\") && seconds <= valueIn(band.high, \"s\");\n};\n\n/** This function gives the words of a band. */\nexport const bandWords = (band: QueueBand): string => `[${valueIn(band.low, \"s\")}, ${valueIn(band.high, \"s\")}] s`;\n\nconst waitsOf = (from: number, stamps: readonly number[]): Quantity[] =>\n stamps.map((stamp, at) => between(at === 0 ? from : stamps[at - 1]!, stamp));\n\n/** This function finds the records of the sockets of the client that had this local address. */\nconst socketsAt = (run: Run, local: unknown): KernelRecord[] => {\n const cookies = new Set(\n run.kernel.filter((record) => record.netns === run.netns && record.src === local).map((record) => record.cookie),\n );\n return run.kernel.filter((record) => record.netns === run.netns && cookies.has(record.cookie));\n};\n\nconst readConnection = (name: string, run: Run, expected: QueueConnection | undefined): QueueConnectionReading => {\n const lineOf = (ev: string): ProbeEvent | undefined =>\n run.events.find((event) => event.ev === ev && event[\"name\"] === name);\n const dial = lineOf(\"dial\");\n const connected = lineOf(\"connected\");\n const failed = lineOf(\"failed\");\n const state = lineOf(\"state\");\n const socket = dial === undefined ? [] : socketsAt(run, dial[\"local\"]);\n const sent = socket.filter((record) => record.ev === \"retrans\").map((record) => record.mono);\n const rx = socket.filter((record) => record.ev === \"rx\" && ((record.seg?.flags ?? 0) & SYN) !== 0);\n const from = dial?.t ?? 0;\n const start = expected?.ends === null || expected?.ends === undefined ? undefined : lineOf(expected.ends.from);\n const last = sent.at(-1);\n return {\n name,\n connected: connected !== undefined,\n // a socket that connected sends its data again, not its SYN\n syns: waitsOf(from, connected === undefined ? sent : sent.filter((stamp) => stamp < connected.t)),\n synAcks: waitsOf(\n from,\n rx.map((record) => record.mono),\n ),\n retransmissions: sent.length,\n errno: failed === undefined ? null : String(failed[\"errno\"]),\n ended: failed === undefined || start === undefined ? null : between(start.t, failed.t),\n afterLast: failed === undefined || last === undefined ? null : between(last, failed.t),\n unacked: state === undefined ? null : numberOf(state, \"unacked\"),\n };\n};\n\n/** This function reads one run against the band of each wait in a list, and gives the words of each miss. */\nconst waitFindings = (what: string, seen: readonly Quantity[], bands: readonly QueueBand[]): string[] => {\n if (seen.length !== bands.length) return [`${what}: ${seen.length} waits, not ${bands.length}`];\n return seen.flatMap((wait, at) =>\n inside(wait, bands[at]!) ? [] : [`${what}: wait ${at} of ${valueIn(wait, \"s\")} s, outside ${bandWords(bands[at]!)}`],\n );\n};\n\nconst connectionFindings = (\n expected: QueueConnection,\n read: QueueConnectionReading,\n expiredAt: number | null,\n stamps: readonly number[],\n): string[] => {\n const { name, ends } = expected;\n const found: string[] = [];\n if (read.connected !== expected.connects)\n found.push(`${name}: ${read.connected ? \"connected\" : \"did not connect\"}, against the prediction`);\n if (expected.syns !== undefined) found.push(...waitFindings(`${name} SYN`, read.syns, expected.syns));\n if (expected.synAcks !== undefined) found.push(...waitFindings(`${name} SYN-ACK`, read.synAcks, expected.synAcks));\n if (expected.unacked !== undefined && read.unacked !== expected.unacked)\n found.push(`${name}: ${read.unacked ?? \"no\"} segments without an ACK, not ${expected.unacked}`);\n if (ends === null) {\n if (read.errno !== null) found.push(`${name}: ended with ${read.errno}, and the prediction has no end`);\n return found;\n }\n if (read.errno !== ends.errno) found.push(`${name}: ended with ${read.errno ?? \"nothing\"}, not ${ends.errno}`);\n if (read.ended === null) return [...found, `${name}: no time for its end`];\n if (!inside(read.ended, ends.within))\n found.push(`${name}: its end came at ${valueIn(read.ended, \"s\")} s, outside ${bandWords(ends.within)}`);\n if (ends.retransmitted === undefined) return found;\n if (read.afterLast === null || !inside(read.afterLast, ends.retransmitted))\n found.push(`${name}: its end came ${read.afterLast === null ? \"with no retransmission\" : `${valueIn(read.afterLast, \"s\")} s after its last retransmission`}, outside ${bandWords(ends.retransmitted)}`);\n if (expiredAt === null) return found;\n const before = stamps.at(-2);\n const last = stamps.at(-1);\n if (last === undefined || last < expiredAt || (before !== undefined && before > expiredAt))\n found.push(`${name}: its last two retransmissions do not span the expiry`);\n return found;\n};\n\n/**\n * This function reads one run of a queue cell. The client lines give the connections and the\n * counters at the two ends of the run. The target lines give the count of the queue. The records of\n * the prober give the waits of each socket.\n */\nexport const measureQueue = (run: Run, expected: QueuePrediction): Measured => {\n const { events, kernel } = run;\n const lineOf = (ev: string): ProbeEvent | undefined => events.find((event) => event.ev === ev);\n const base = {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions: kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length,\n acks: 0,\n };\n const voided = (why: string): Measured => ({ ...base, void: why, finding: null });\n const opened = lineOf(\"opened\");\n const stats = lineOf(\"stats\");\n if (opened === undefined) return voided(\"the target did not open its listener\");\n if (stats === undefined || lineOf(\"done\") === undefined) return voided(\"the client did not reach its end\");\n if (run.lost === null) return voided(\"the prober wrote no clock line after the run, so nothing says what it dropped\");\n if (run.lost > 0) return voided(`the prober dropped ${run.lost} records`);\n const lines = (run.server ?? []).filter((line) => line.ev === \"queue\" && line.t >= opened.t);\n if (lines.length === 0) return voided(\"the target wrote no queue line in the run\");\n\n const named = [...new Set(events.filter((event) => event.ev === \"dial\").map((event) => String(event[\"name\"])))];\n const predicted = new Map(expected.connections.map((each) => [each.name, each]));\n const connections = named.map((name) => readConnection(name, run, predicted.get(name)));\n const admitted = expected.admitted === undefined ? undefined : connections.find((each) => each.name === expected.admitted);\n if (expected.admitted !== undefined && (admitted === undefined || !admitted.connected || admitted.unacked !== 0))\n return voided(`${expected.admitted} did not take the last place in the queue: the burst did not land in its sequence`);\n\n const change = (field: string): number => numberOf(stats, field) - numberOf(opened, field);\n const burst = events.find((event) => event.ev === \"dial\" && event[\"name\"] === \"in\")?.t ?? opened.t;\n const counted = expected.expiry?.timeouts;\n const expired = counted === undefined ? undefined : lines.find((line) => numberOf(line, \"timeouts\") - numberOf(opened, \"timeouts\") >= counted);\n const accepted = events.find((event) => event.ev === \"accepted\");\n // the rise counts from the first count below it: a line of the count before the accept can come after the reply of the accept\n const rise = expected.rise?.count ?? 0;\n const low = accepted === undefined ? -1 : lines.findIndex((line) => line.t >= accepted.t && numberOf(line, \"count\") < rise);\n const risen = low < 0 ? undefined : lines.slice(low).find((line) => numberOf(line, \"count\") >= rise);\n const drained = events\n .filter((event) => event.ev === \"accepted\")\n .reduce((sum, event) => sum + (Array.isArray(event[\"peers\"]) ? event[\"peers\"].length : 0), 0);\n const queue: QueueReading = {\n max: numberOf(opened, \"max\"),\n held: Math.max(...lines.map((line) => numberOf(line, \"count\"))),\n connected: connections.filter((each) => each.connected).length,\n overflows: change(\"overflows\"),\n drops: change(\"drops\"),\n cookies: change(\"cookies\"),\n timeouts: change(\"timeouts\"),\n resets: change(\"resets\"),\n drained,\n expiry: expired === undefined ? null : between(burst, expired.t),\n rise: risen === undefined ? null : between(burst, risen.t),\n connections,\n };\n\n const found: string[] = [];\n if (queue.max !== expected.max) found.push(`the limit is ${queue.max}, not ${expected.max}`);\n if (queue.held !== expected.held) found.push(`the queue held ${queue.held}, not ${expected.held}`);\n if (queue.connected !== expected.connected) found.push(`${queue.connected} connected, not ${expected.connected}`);\n if (queue.overflows < expected.overflows.low || queue.overflows > expected.overflows.high)\n found.push(`${queue.overflows} overflows, outside [${expected.overflows.low}, ${expected.overflows.high}]`);\n if (queue.resets !== expected.resets) found.push(`${queue.resets} resets, not ${expected.resets}`);\n if (queue.cookies !== 0) found.push(`${queue.cookies} SYN cookies, and the law has none`);\n if (expected.drained !== undefined && queue.drained !== expected.drained)\n found.push(`${queue.drained} accepted, not ${expected.drained}`);\n if (expected.expiry !== undefined && (queue.expiry === null || !inside(queue.expiry, expected.expiry.within)))\n found.push(`the expiry came at ${queue.expiry === null ? \"no time\" : `${valueIn(queue.expiry, \"s\")} s`}, outside ${bandWords(expected.expiry.within)}`);\n if (expected.rise !== undefined && (queue.rise === null || !inside(queue.rise, expected.rise.within)))\n found.push(`the count got back to ${expected.rise.count} at ${queue.rise === null ? \"no time\" : `${valueIn(queue.rise, \"s\")} s`}, outside ${bandWords(expected.rise.within)}`);\n for (const each of expected.connections) {\n const read = connections.find((connection) => connection.name === each.name);\n if (read === undefined) {\n found.push(`${each.name}: the client did not dial it`);\n continue;\n }\n const dial = events.find((event) => event.ev === \"dial\" && event[\"name\"] === each.name);\n const stamps = socketsAt(run, dial?.[\"local\"]).filter((record) => record.ev === \"retrans\").map((record) => record.mono);\n found.push(...connectionFindings(each, read, expired?.t ?? null, stamps));\n }\n return { ...base, void: null, finding: found.length === 0 ? null : found.join(\". \"), queue };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { ConntrackPrediction, ProbeEvent, Run } from \"./cell.ts\";\nimport type { Measured } from \"./observe.ts\";\nimport { bandWords, between, inside } from \"./queue.ts\";\n\n/** This errno tells that a connect got a slot. */\nconst NONE = \"none\";\n\n/** This record is the end of a connect that found no entry at its start. */\nexport interface StallReading {\n readonly errno: string;\n readonly time: Quantity;\n /** This count is the rise of the field `drop` of the conntrack statistics during the connect. */\n readonly drops: number;\n /** This count is the rise of `TCPRetransFail` during the connect. */\n readonly retransFail: number;\n}\n\n/** This record is what a run of a conntrack cell measured. */\nexport interface ConntrackReading {\n /** This count is the flows that the client holds at its `full` line. */\n readonly flows: number;\n /** This count is what the namespace of the client reads at that line. */\n readonly count: number;\n /** This count is what the namespace of the target reads while the client holds its flows. */\n readonly neighbor: number | null;\n readonly stall: StallReading | null;\n /** This time is from the `closing` line to the first fall of the count. */\n readonly firstFall: Quantity | null;\n /** This time is from the `closing` line to the zero of the count. */\n readonly zero: Quantity | null;\n /** This count is what the namespace reads after each side closes. */\n readonly closed: number | null;\n /** This count is the lowest that the poll of the count read. */\n readonly lowest: number | null;\n /** This count is what the namespace reads after a connect that got a slot. */\n readonly after: number | null;\n}\n\nconst numberOr = (line: ProbeEvent | undefined, field: string): number | null => {\n const value = line?.[field];\n return typeof value === \"number\" ? value : null;\n};\n\n/** This function gives the time from one stamp to a stamp of a field of a line, when the line has it. */\nconst untilField = (from: ProbeEvent | undefined, line: ProbeEvent | undefined, field: string): Quantity | null => {\n const stamp = numberOr(line, field);\n return from === undefined || stamp === null ? null : between(from.t, stamp);\n};\n\nconst stallOf = (line: ProbeEvent | undefined): StallReading | null =>\n line === undefined\n ? null\n : {\n errno: String(line[\"errno\"]),\n time: quantity(Math.round((numberOr(line, \"elapsed\") ?? 0) / 1e3) / 1e6, \"s\"),\n drops: numberOr(line, \"drops\") ?? 0,\n retransFail: numberOr(line, \"retrans_fail\") ?? 0,\n };\n\n/** This function tells where a reading differs from the law of its cell. */\nconst findingsOf = (read: ConntrackReading, failed: unknown, expected: ConntrackPrediction): string[] => {\n const found: string[] = [];\n const { max, neighbor, refused, drained, pressure } = expected;\n if (typeof failed === \"string\") found.push(`a connect failed with ${failed} before the client held its flows`);\n if (read.flows !== max) found.push(`the client held ${read.flows} flows, not ${max}`);\n if (read.count !== max) found.push(`the count read ${read.count} at the fill, not ${max}`);\n if (neighbor !== undefined && read.neighbor !== neighbor)\n found.push(`the namespace of the target read ${read.neighbor ?? \"nothing\"}, not ${neighbor}`);\n if (refused !== undefined) {\n const stall = read.stall;\n if (stall === null) found.push(\"no connect after the fill ended\");\n else {\n if (stall.errno !== refused.errno) found.push(`the connect after the fill ended with ${stall.errno}, not ${refused.errno}`);\n if (!inside(stall.time, refused.within))\n found.push(`the connect after the fill took ${valueIn(stall.time, \"s\")} s, outside ${bandWords(refused.within)}`);\n if (stall.drops !== refused.drops) found.push(`the field drop rose by ${stall.drops}, not ${refused.drops}`);\n if (stall.retransFail !== refused.retransFail) found.push(`TCPRetransFail rose by ${stall.retransFail}, not ${refused.retransFail}`);\n }\n }\n if (drained !== undefined) {\n for (const [name, time] of [[\"first fall\", read.firstFall], [\"zero\", read.zero]] as const) {\n if (time === null || !inside(time, drained))\n found.push(`the ${name} of the count came at ${time === null ? \"no time\" : `${valueIn(time, \"s\")} s`}, outside ${bandWords(drained)}`);\n }\n }\n if (pressure !== undefined) {\n const stall = read.stall;\n if (read.closed !== max) found.push(`the count read ${read.closed ?? \"nothing\"} after each side closed, not ${max}`);\n const { highest } = pressure;\n if (highest === undefined) {\n if (read.lowest !== pressure.lowest) found.push(`the lowest count was ${read.lowest ?? \"nothing\"}, not ${pressure.lowest}`);\n if (read.after !== pressure.after) found.push(`the count read ${read.after ?? \"nothing\"} after the connect, not ${pressure.after}`);\n } else if (read.lowest === null || read.lowest < pressure.lowest || read.lowest > highest) {\n found.push(`the lowest count was ${read.lowest ?? \"nothing\"}, outside ${pressure.lowest} to ${highest}`);\n } else if (read.after !== read.lowest + 1) {\n found.push(`the count read ${read.after ?? \"nothing\"} after the connect, not ${read.lowest + 1}`);\n }\n if (stall === null) found.push(\"no connect after the close ended\");\n else {\n if (stall.errno !== NONE) found.push(`the connect after the close ended with ${stall.errno}`);\n if (!pressure.points.some((point) => inside(stall.time, point)))\n found.push(`the connect after the close took ${valueIn(stall.time, \"s\")} s, on no point of the schedule`);\n }\n }\n return found;\n};\n\n/**\n * This function reads one run of a conntrack cell from the lines of its client and its target. An\n * `unsettled` line makes the run void. The entries of the run before it were still in the table, thus\n * the run did not start from an empty table.\n */\nexport const measureConntrack = (run: Run, expected: ConntrackPrediction): Measured => {\n const { events, kernel } = run;\n const retransmissions = kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length;\n const base = {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions,\n acks: 0,\n };\n const voided = (why: string): Measured => ({ ...base, void: why, finding: null });\n const unsettled = events.find((event) => event.ev === \"unsettled\");\n if (unsettled !== undefined) return voided(`the table held ${String(unsettled[\"count\"])} entries at the end of the wait before the run`);\n if (events.find((event) => event.ev === \"done\") === undefined) {\n // the program writes the error that stopped it as its last line\n const error = events.find((event) => event.ev === \"error\");\n return voided(error === undefined ? \"the client did not reach its end\" : `the client did not reach its end: ${String(error[\"what\"])}`);\n }\n if (run.lost === null) return voided(\"the prober wrote no clock line after the run, so nothing says what it dropped\");\n if (run.lost > 0) return voided(`the prober dropped ${run.lost} records`);\n\n const full = events.find((event) => event.ev === \"full\");\n if (full === undefined) return voided(\"the client wrote no line for its fill\");\n const stall = events.find((event) => event.ev === \"stall\");\n const closing = events.find((event) => event.ev === \"closing\");\n const drained = events.find((event) => event.ev === \"drained\");\n const closed = events.find((event) => event.ev === \"closed\");\n // the count of the neighbor while the client holds its flows: from the fill to the end of the connect after it\n const neighbor = (run.server ?? []).filter((line) => line.ev === \"count\" && line.t >= full.t && (stall === undefined || line.t <= stall.t)).at(-1);\n const conntrack: ConntrackReading = {\n flows: numberOr(full, \"flows\") ?? 0,\n count: numberOr(full, \"count\") ?? 0,\n neighbor: numberOr(neighbor, \"count\"),\n stall: stallOf(stall),\n firstFall: untilField(closing, drained, \"first_fall\"),\n zero: untilField(closing, drained, \"zero\"),\n closed: numberOr(closed, \"count\"),\n lowest: numberOr(drained ?? stall, \"lowest\"),\n after: numberOr(stall, \"after\"),\n };\n const found = findingsOf(conntrack, full[\"errno\"], expected);\n return { ...base, void: null, finding: found.length === 0 ? null : found.join(\". \"), conntrack };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { PauseBand, PausePrediction, ProbeEvent, Run } from \"./cell.ts\";\nimport type { Measured } from \"./observe.ts\";\n\n/**\n * This module reads one run of a paused consumer against its law. Two members of a group each hold\n * one partition. A SIGSTOP stops the first member while it holds a batch, and a SIGCONT ends that\n * stop. Three sources give the reading: the lines of each member, the log lines of the brokers, and\n * the stamps of the injector.\n *\n * The broker writes its log on the clock of the wall, and the members and the injector use the\n * monotonic clock. The `start` line of a member has both clocks, thus it converts a log line.\n */\n\n/** A commit reading is the first commit of the stopped member after the stop. */\nexport interface PauseCommit {\n readonly acked: boolean;\n /** This name is the class of the error of the commit. It is null for a commit that the broker acknowledged. */\n readonly name: string | null;\n readonly message: string | null;\n /** This number is the epoch that the member held at the commit. */\n readonly epoch: number | null;\n}\n\n/** A pause reading is what one run of a paused consumer measured. Each offset is the next offset to read, as a commit names it. */\nexport interface PauseReading {\n /** This number is the partition of the stopped member before the stop. */\n readonly partition: number;\n /** This time is from the stop to the log line of the broker that removes the member. It is null when no such line came. */\n readonly fence: Quantity | null;\n /** This time is from the stop to the first report of the partition by the other member. It is null when no report came. */\n readonly takeover: Quantity | null;\n readonly commit: PauseCommit | null;\n /** This number is the epoch at the last acknowledged commit before the stop. */\n readonly epochBefore: number | null;\n /** This offset is the last acknowledged commit of the stopped member before the stop. */\n readonly lastAck: number;\n /** This offset is the first offset of the partition that the other member read after the stop. */\n readonly otherFirst: number | null;\n /** This offset is the last acknowledged commit of the other member on the partition, before the commit of the stopped member. */\n readonly otherLast: number | null;\n /** This time is from the end of the stop to the new epoch of the member. It is null when no new epoch came. */\n readonly rejoin: Quantity | null;\n /** This value tells if the stopped member reported the partition again between the end of the stop and its commit. */\n readonly reassigned: boolean;\n /** This offset is the committed offset that the member read after its commit. */\n readonly committed: number | null;\n /** This offset is what the first commit after the stop names for the partition. */\n readonly stale: number | null;\n}\n\n/** This expression finds the stamp of a log line of a broker, as its console writes it, on UTC. */\nconst LOG_TIME = /\\[(\\d{4})-(\\d\\d)-(\\d\\d) (\\d\\d):(\\d\\d):(\\d\\d),(\\d{3})\\]/;\n\n/** This function gives the time of a log line on the monotonic clock of a member, in ns, from the `start` line of that member. It is null for a line with no stamp. */\nexport const logTimeOf = (line: string, start: ProbeEvent): number | null => {\n const found = LOG_TIME.exec(line);\n if (found === null) return null;\n const wall = Date.UTC(Number(found[1]), Number(found[2]) - 1, Number(found[3]), Number(found[4]), Number(found[5]), Number(found[6]), Number(found[7]));\n return start.t + (wall - Number(start[\"wall\"])) * 1e6;\n};\n\n/** This function gives the time between two instants of the monotonic clock, in s, to 1 microsecond. */\nconst secondsBetween = (from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\nconst isInside = (time: Quantity, band: PauseBand): boolean => {\n const seconds = valueIn(time, \"s\");\n return seconds >= valueIn(band.low, \"s\") && seconds <= valueIn(band.high, \"s\");\n};\n\nconst bandText = (band: PauseBand): string => `[${valueIn(band.low, \"s\")}, ${valueIn(band.high, \"s\")}] s`;\n\nconst isChange = (event: ProbeEvent): boolean => event.ev === \"assigned\" || event.ev === \"revoked\" || event.ev === \"lost\";\n\n/** This function gives the partitions that a line of the rebalance listener names, in its field `partitions` or `held`. */\nconst partitionsOf = (event: ProbeEvent, field: \"partitions\" | \"held\"): readonly number[] => (event[field] as readonly number[] | undefined) ?? [];\n\n/** This function gives the last line of the rebalance listener in a list of lines. */\nconst lastChange = (events: readonly ProbeEvent[]): ProbeEvent | undefined => events.findLast(isChange);\n\n/** This function gives the offset that a commit names for a partition, or null. */\nconst offsetOf = (event: ProbeEvent, partition: number): number | null => {\n const value = (event[\"offsets\"] as Readonly<Record<string, number | null>> | undefined)?.[String(partition)];\n return typeof value === \"number\" ? value : null;\n};\n\n/**\n * This function tells if the two members can take the fault. Each member holds one partition, the\n * two partitions differ, and the first member has two acknowledged commits on its partition after its\n * last change. Thus the first member reads and commits at a steady rate.\n */\nexport const pauseReady = (first: readonly ProbeEvent[], other: readonly ProbeEvent[]): boolean => {\n const mine = lastChange(first);\n const theirs = lastChange(other);\n if (mine === undefined || theirs === undefined) return false;\n const held = partitionsOf(mine, \"held\");\n const others = partitionsOf(theirs, \"held\");\n if (held.length !== 1 || others.length !== 1 || held[0] === others[0]) return false;\n const commits = first.filter((event) => event.ev === \"commit\" && event.t > mine.t && offsetOf(event, held[0]!) !== null);\n return commits.length >= 2;\n};\n\n/** This function tells if a log line of a broker tells that a member left a group, under either protocol. */\nexport const isFenceLine = (line: string): boolean =>\n /Member \\S+ fenced from the group because|Member \\S+ in group \\S+ has failed, removing it from the group/.test(line);\n\n/** This function tells if a fence line names a group. The two protocols write the name in different words. */\nexport const namesGroup = (line: string, group: string): boolean => line.includes(`[GroupId ${group}]`) || line.includes(`in group ${group} has`);\n\n/** This function compares a reading to the law, and gives each disagreement. */\nconst findingsOf = (reading: PauseReading, prediction: PausePrediction, fences: readonly string[], otherReports: boolean): string[] => {\n const found: string[] = [];\n const { commit, fence, takeover } = reading;\n if (prediction.fence === null) {\n if (fences.length > 0) found.push(`the group removed a member: ${fences[0]}`);\n if (otherReports) found.push(\"the other member reported the partition\");\n } else {\n if (fence === null) found.push(\"no log line tells of a fence, and the other member did not report the partition\");\n else if (!isInside(fence, prediction.fence)) found.push(`the fence is ${valueIn(fence, \"s\")} s, outside ${bandText(prediction.fence)}`);\n if (reading.otherFirst !== reading.lastAck) found.push(`the other member started at offset ${reading.otherFirst}, and the last commit is ${reading.lastAck}`);\n }\n if (prediction.takeover !== null) {\n if (takeover === null) found.push(\"the other member did not report the partition\");\n else if (!isInside(takeover, prediction.takeover)) found.push(`the other member reported the partition at ${valueIn(takeover, \"s\")} s, outside ${bandText(prediction.takeover)}`);\n }\n if (commit === null) {\n found.push(\"the member made no commit after the stop\");\n return found;\n }\n switch (prediction.thaw) {\n case \"fails\":\n if (commit.name !== \"CommitFailedException\") found.push(`the commit after the stop gave ${commit.name ?? \"an acknowledgment\"}, not CommitFailedException`);\n break;\n case \"acknowledged\":\n if (!commit.acked) found.push(`the commit after the stop failed with ${commit.name}`);\n if (commit.epoch !== reading.epochBefore) found.push(`the epoch changed from ${reading.epochBefore} to ${commit.epoch}`);\n break;\n case \"rejoin\": {\n const within = prediction.rejoinWithin;\n if (reading.rejoin === null) found.push(\"the member did not get a new epoch\");\n else if (within !== undefined && valueIn(reading.rejoin, \"s\") > valueIn(within, \"s\")) found.push(`the new epoch came at ${valueIn(reading.rejoin, \"s\")} s, above ${valueIn(within, \"s\")} s`);\n if (!commit.acked) found.push(`the stale commit failed with ${commit.name}`);\n if (reading.reassigned) found.push(\"the member held the partition again before its commit\");\n if (reading.committed !== reading.stale) found.push(`the committed offset is ${reading.committed}, and the stale commit named ${reading.stale}`);\n if (reading.stale === null || reading.otherLast === null || reading.stale >= reading.otherLast) found.push(`the stale commit ${reading.stale} is not below the progress ${reading.otherLast} of the other member`);\n break;\n }\n }\n return found;\n};\n\n/** This function reads one run of a paused consumer against its law. */\nexport const measurePause = (run: Run, prediction: PausePrediction): Measured => {\n const retransmissions = run.kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length;\n const base = {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions,\n acks: 0,\n };\n const voided = (why: string): Measured => ({ ...base, void: why, finding: null });\n\n const { fault, heal, pause } = run;\n if (fault === null || pause === undefined) return voided(\"the partitions were not one for each member before the stop\");\n if (heal === undefined || heal === null) return voided(\"the stop did not end\");\n const stop = fault.t0;\n const thaw = heal.t0;\n const before = run.events.filter((event) => event.t < stop);\n const after = run.events.filter((event) => event.t >= stop);\n const start = run.events.find((event) => event.ev === \"start\");\n if (start === undefined) return voided(\"the member wrote no start line\");\n\n const mine = lastChange(before);\n const theirs = lastChange(pause.other.filter((event) => event.t < stop));\n const held = mine === undefined ? [] : partitionsOf(mine, \"held\");\n const others = theirs === undefined ? [] : partitionsOf(theirs, \"held\");\n const partition = held[0];\n if (partition === undefined || held.length !== 1 || others.length !== 1 || others[0] === partition)\n return voided(\"the partitions were not one for each member before the stop\");\n if (after.find((event) => event.ev === \"pause\")?.[\"in\"] !== \"process\") return voided(\"the stop landed outside the processing of a batch\");\n if (before.findLast((event) => event.ev === \"read\")?.[\"partition\"] !== partition) return voided(\"the last read before the stop was on another partition\");\n const lastCommit = before.findLast((event) => event.ev === \"commit\" && offsetOf(event, partition) !== null);\n if (lastCommit === undefined) return voided(\"the member had no acknowledged commit on its partition before the stop\");\n\n const member = String(mine?.[\"member\"]);\n const fenceLines = pause.fences.filter((line) => line.includes(member));\n const fenceAt = fenceLines.map((line) => logTimeOf(line, start)).find((time) => time !== null && time >= stop) ?? null;\n const taken = pause.other.find((event) => event.ev === \"assigned\" && event.t >= stop && partitionsOf(event, \"partitions\").includes(partition));\n if (prediction.fence !== null && fenceAt === null && taken !== undefined) return voided(\"the broker log lost the line of the fence\");\n\n const thawed = after.find((event) => event.ev === \"commit\" || event.ev === \"commit-fail\");\n const rejoined = after.find((event) => event.ev === \"rejoined\");\n const ackAt = thawed?.t ?? Number.POSITIVE_INFINITY;\n const otherCommit = pause.other.findLast((event) => event.ev === \"commit\" && event.t < ackAt && offsetOf(event, partition) !== null);\n const committed = after.find((event) => event.ev === \"committed\");\n const epochOf = (event: ProbeEvent | undefined): number | null => (typeof event?.[\"epoch\"] === \"number\" ? event[\"epoch\"] : null);\n\n const pauseReading: PauseReading = {\n partition,\n fence: fenceAt === null ? null : secondsBetween(stop, fenceAt),\n takeover: taken === undefined ? null : secondsBetween(stop, taken.t),\n commit:\n thawed === undefined\n ? null\n : {\n acked: thawed.ev === \"commit\",\n name: typeof thawed[\"name\"] === \"string\" ? thawed[\"name\"] : null,\n message: typeof thawed[\"message\"] === \"string\" ? thawed[\"message\"] : null,\n epoch: epochOf(thawed),\n },\n epochBefore: epochOf(lastCommit),\n lastAck: offsetOf(lastCommit, partition)!,\n otherFirst: (pause.other.find((event) => event.ev === \"read\" && event.t >= stop && event[\"partition\"] === partition)?.[\"first\"] as number | undefined) ?? null,\n otherLast: otherCommit === undefined ? null : offsetOf(otherCommit, partition),\n rejoin: rejoined === undefined ? null : secondsBetween(thaw, rejoined.t),\n reassigned: after.some((event) => event.ev === \"assigned\" && event.t >= thaw && event.t <= ackAt && partitionsOf(event, \"partitions\").includes(partition)),\n committed: committed === undefined ? null : offsetOf(committed, partition),\n stale: thawed === undefined ? null : offsetOf(thawed, partition),\n };\n const findings = findingsOf(pauseReading, prediction, pause.fences, taken !== undefined);\n return { ...base, void: null, finding: findings.length === 0 ? null : findings.join(\". \"), pause: pauseReading };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { PortsPrediction, ProbeEvent, Run } from \"./cell.ts\";\nimport type { Measured } from \"./observe.ts\";\nimport { bandWords, between, inside } from \"./queue.ts\";\n\n/** This errno ends a search that found no port. */\nconst NO_PORT = \"EADDRNOTAVAIL\";\n\n/** This record is what a run of a port cell measured. */\nexport interface PortsReading {\n /** This count is the rounds of the run, each destination once. */\n readonly rounds: number;\n /** This record gives the count of searches for each count of connects, by that count. */\n readonly counts: Readonly<Record<string, number>>;\n /** These offsets from the low port are the ports that the run used, in rising order. */\n readonly seen: readonly number[];\n /** These errnos ended the searches of the run, each one time. */\n readonly errnos: readonly string[];\n /** This time is the longest connect that failed. */\n readonly refusal: Quantity;\n /** This time is from the `closing` line to the first `freed` line. */\n readonly firstFreed: Quantity | null;\n /** This time is from the `closing` line to the last `freed` line. */\n readonly lastFreed: Quantity | null;\n /** This count is the `freed` lines of the run. */\n readonly freed: number;\n /** This count is the connects that failed before the last `freed` line. */\n readonly tries: number;\n}\n\nconst portsOf = (line: ProbeEvent): readonly number[] =>\n Array.isArray(line[\"ports\"]) ? line[\"ports\"].filter((port): port is number => typeof port === \"number\") : [];\n\n/** This function says if the ports of the parity of the low port come first in one search. */\nconst lowFirst = (ports: readonly number[], low: number): boolean => {\n const odd = ports.findIndex((port) => (port - low) % 2 !== 0);\n return odd < 0 || ports.slice(odd).every((port) => (port - low) % 2 !== 0);\n};\n\n/**\n * This function reads one run of a port cell. The `round` lines give each search. The `closing` and\n * `freed` lines give when each held port comes back. The records of the prober give the\n * retransmissions.\n */\nexport const measurePorts = (run: Run, expected: PortsPrediction): Measured => {\n const { events, kernel } = run;\n const retransmissions = kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length;\n const base = {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions,\n acks: 0,\n };\n const voided = (why: string): Measured => ({ ...base, void: why, finding: null });\n if (events.find((event) => event.ev === \"done\") === undefined) return voided(\"the client did not reach its end\");\n if (run.lost === null) return voided(\"the prober wrote no clock line after the run, so nothing says what it dropped\");\n if (run.lost > 0) return voided(`the prober dropped ${run.lost} records`);\n\n const rounds = events.filter((event) => event.ev === \"round\");\n const closing = events.find((event) => event.ev === \"closing\");\n const freedLines = events.filter((event) => event.ev === \"freed\");\n const counts: Record<string, number> = {};\n for (const round of rounds) {\n const count = String(portsOf(round).length);\n counts[count] = (counts[count] ?? 0) + 1;\n }\n const seen = [...new Set(rounds.flatMap((round) => portsOf(round).map((port) => port - expected.low)))].sort((a, b) => a - b);\n const refusal = Math.max(0, ...rounds.map((round) => (typeof round[\"refusal\"] === \"number\" ? round[\"refusal\"] : 0)));\n const first = freedLines[0];\n const last = freedLines.at(-1);\n const ports: PortsReading = {\n rounds: rounds.length,\n counts,\n seen,\n errnos: [...new Set(rounds.map((round) => String(round[\"errno\"])))],\n refusal: quantity(Math.round(refusal / 1e3) / 1e6, \"s\"),\n firstFreed: closing === undefined || first === undefined ? null : between(closing.t, first.t),\n lastFreed: closing === undefined || last === undefined ? null : between(closing.t, last.t),\n freed: freedLines.length,\n tries: last === undefined || typeof last[\"tries\"] !== \"number\" ? 0 : last[\"tries\"],\n };\n\n const found: string[] = [];\n const searches = expected.rounds * expected.destinations;\n if (ports.rounds !== searches) found.push(`${ports.rounds} searches, not ${searches}`);\n const stray = Object.keys(counts).filter((count) => !expected.counts.includes(Number(count)));\n if (stray.length > 0) found.push(`a search gave ${stray.join(\" or \")} connects, outside ${expected.counts.join(\" or \")}`);\n if (seen.join() !== expected.seen.join()) found.push(`the ports at offsets ${seen.join(\" \")} were used, not ${expected.seen.join(\" \")}`);\n if (ports.errnos.join() !== NO_PORT) found.push(`the searches ended with ${ports.errnos.join(\" and \")}, not ${NO_PORT}`);\n if (valueIn(ports.refusal, \"s\") > valueIn(expected.refusedWithin, \"s\"))\n found.push(`a refused connect took ${valueIn(ports.refusal, \"s\")} s, above ${valueIn(expected.refusedWithin, \"s\")} s`);\n if (expected.share !== undefined) {\n const { count, low, high } = expected.share;\n const share = (counts[String(count)] ?? 0) / Math.max(1, ports.rounds);\n if (share < low || share > high) found.push(`the share of ${count} connects is ${share}, outside [${low}, ${high}]`);\n }\n if (expected.lowFirst === true && !rounds.every((round) => lowFirst(portsOf(round), expected.low)))\n found.push(\"a search got a port of the other parity before each port of the parity of the low port\");\n if (expected.retransmissions !== undefined && retransmissions !== expected.retransmissions)\n found.push(`${retransmissions} retransmissions, not ${expected.retransmissions}`);\n if (expected.freed !== undefined) {\n const held = Math.max(...expected.counts);\n if (ports.freed !== held) found.push(`${ports.freed} ports came back, not ${held}`);\n for (const [name, time] of [[\"first\", ports.firstFreed], [\"last\", ports.lastFreed]] as const) {\n if (time === null || !inside(time, expected.freed))\n found.push(`the ${name} port came back at ${time === null ? \"no time\" : `${valueIn(time, \"s\")} s`}, outside ${bandWords(expected.freed)}`);\n }\n if (ports.tries === 0) found.push(\"no connect was refused before the ports came back\");\n }\n return { ...base, void: null, finding: found.length === 0 ? null : found.join(\". \"), ports };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Drill, ProbeEvent, ReplicaSet, Run } from \"./cell.ts\";\nimport type { Writes } from \"./timeline.ts\";\n\n/**\n * This module holds the pure parts of a recovery drill. These are the scripts of the shell, the reader\n * of the output of `bsondump`, and the set check of a recovery. It has no container, thus unit tests\n * run it. `drill.ts` does the drill on a lab.\n *\n * A dump with `--oplog` reads the oplog from the start of the dump to its end. A slice reads the\n * oplog after the last entry of the backup before it. Thus the backups together hold each write up\n * to the last entry of the last backup, and no write after it. One writer sends the writes one at a\n * time, thus the highest sequence number is also the latest write.\n */\n\n/** This size is one document of generated data. A tenant holds as many documents as its size needs. */\nexport const SEED_DOCUMENT = 65_536;\n/** This count is how far the lost writes can be from the writes after the last backup: the writes in flight at the fault. */\nexport const LOSS_MARGIN = 2;\n/** This time is how long a script waits for a server to stop, in tenths of a second. */\nconst STOP_TENTHS = 600;\n\n/** This function gives the time of a drill from the start of the backups to the fault, in seconds. */\nexport const drillSpan = (drill: Drill): number => drill.slices * valueIn(drill.sliceEvery, \"s\") + valueIn(drill.age, \"s\");\n\n/**\n * This script writes the generated data of each tenant into the collection `tenants`. Each write\n * waits for `copies` members, thus each member holds the data when the script ends.\n */\nexport const seedScript = (drill: Drill, copies: number): string => {\n const documents = Math.ceil(valueIn(drill.perTenant, \"B\") / SEED_DOCUMENT);\n const blob = `BinData(0, require(\"crypto\").randomBytes(${SEED_DOCUMENT}).toString(\"base64\"))`;\n return (\n 'const c = db.getSiblingDB(\"cells\"); ' +\n `c.tenants.drop({ writeConcern: { w: ${copies} } }); ` +\n `for (let t = 1; t <= ${drill.tenants}; t += 1) { const docs = []; ` +\n `for (let d = 1; d <= ${documents}; d += 1) docs.push({ _id: \"t\" + t + \".d\" + d, tenant: t, blob: ${blob} }); ` +\n `c.tenants.insertMany(docs, { writeConcern: { w: ${copies}, wtimeout: 60000 } }); } ` +\n \"print(JSON.stringify({ ok: true }))\"\n );\n};\n\n/** This script prints the hash of the collection `tenants`. It takes locks, thus a run reads it with no writer. */\nexport const HASH_SCRIPT: string =\n 'print(JSON.stringify({ hash: db.getSiblingDB(\"cells\").runCommand({ dbHash: 1, collections: [\"tenants\"] }).collections.tenants }))';\n\n/** This function gives the hash from the output of `HASH_SCRIPT`. */\nexport const hashOf = (text: string): string => {\n const line = text.split(\"\\n\").filter((each) => each.trim() !== \"\").at(-1) ?? \"\";\n const { hash } = JSON.parse(line) as { readonly hash?: unknown };\n if (typeof hash !== \"string\" || hash === \"\") throw new Error(`no hash of the tenants in: ${line}`);\n return hash;\n};\n\n/** This function gives the command of a server with no set, on its own port. A client of the set cannot reach that server, and a restore writes to it. */\nexport const standaloneCommand = (set: ReplicaSet, port: number): string =>\n `${set.programs.server} --bind_ip_all --port ${port} ${(set.args ?? []).join(\" \")}`.trim();\n\n/**\n * This script waits for the end of the server of a box, and it can stop the server first. `kill -0`\n * also succeeds on a zombie, and the shell of the box can leave its child as a zombie for a long\n * time. Thus the script reads the state of the process, and a zombie has ended.\n */\nexport const stopScript = (terminate: boolean): string =>\n \"pid=$(cat /tmp/server.pid); \" +\n (terminate ? 'kill -TERM \"$pid\"; ' : \"\") +\n `for i in $(seq 1 ${STOP_TENTHS}); do s=$(cut -d' ' -f3 /proc/$pid/stat 2>/dev/null); ` +\n 'if [ -z \"$s\" ] || [ \"$s\" = Z ]; then exit 0; fi; sleep 0.1; done; exit 1';\n\n/** This function gives a number from Extended JSON, in its relaxed form or in its canonical form, or null. */\nconst numberOf = (value: unknown): number | null => {\n if (typeof value === \"number\") return value;\n if (typeof value !== \"object\" || value === null) return null;\n const wrapped = value as { readonly $numberInt?: unknown; readonly $numberLong?: unknown; readonly $numberDouble?: unknown };\n const text = wrapped.$numberInt ?? wrapped.$numberLong ?? wrapped.$numberDouble;\n return typeof text === \"string\" && text !== \"\" && Number.isFinite(Number(text)) ? Number(text) : null;\n};\n\n/** This function gives each document of the output of `bsondump`. A line that is not a document does not count. */\nconst documentsOf = (text: string): Array<Record<string, unknown>> =>\n text.split(\"\\n\").flatMap((line) => {\n if (!line.trim().startsWith(\"{\")) return [];\n try {\n return [JSON.parse(line) as Record<string, unknown>];\n } catch {\n return [];\n }\n });\n\n/** An oplog time is the `ts` of an oplog entry: a time in seconds, and the count of the entry in that second. */\nexport interface OplogTime {\n readonly t: number;\n readonly i: number;\n}\n\n/** This function gives the `ts` of an oplog entry, or null. */\nconst timeOf = (entry: Record<string, unknown>): OplogTime | null => {\n const stamp = (entry[\"ts\"] as { readonly $timestamp?: { readonly t?: unknown; readonly i?: unknown } } | undefined)?.$timestamp;\n const t = numberOf(stamp?.t);\n const i = numberOf(stamp?.i);\n return t === null || i === null ? null : { t, i };\n};\n\n/** An oplog read is what an oplog file holds: its last entry, and the highest sequence number that it inserts. */\nexport interface OplogRead {\n readonly last: OplogTime | null;\n readonly highest: number | null;\n}\n\n/** This function reads an oplog file from the output of `bsondump`. Only an insert into `cells.w` is a write of a client. */\nexport const readOplog = (text: string): OplogRead => {\n let last: OplogTime | null = null;\n let highest: number | null = null;\n for (const entry of documentsOf(text)) {\n const time = timeOf(entry);\n if (time !== null && (last === null || time.t > last.t || (time.t === last.t && time.i > last.i))) last = time;\n if (entry[\"op\"] !== \"i\" || entry[\"ns\"] !== \"cells.w\") continue;\n const n = numberOf((entry[\"o\"] as { readonly n?: unknown } | undefined)?.n);\n if (n !== null && (highest === null || n > highest)) highest = n;\n }\n return { last, highest };\n};\n\n/** This function gives the highest sequence number of the file of the writes in a dump, from the output of `bsondump`, or null. */\nexport const highestHeld = (text: string): number | null => {\n const held = documentsOf(text).flatMap((document) => {\n const n = numberOf(document[\"n\"]);\n return n === null ? [] : [n];\n });\n return held.length === 0 ? null : Math.max(...held);\n};\n\n/** This function gives the query of a slice of the oplog: each entry after an oplog time, in Extended JSON. */\nexport const sliceQuery = (after: OplogTime): string => JSON.stringify({ ts: { $gt: { $timestamp: { t: after.t, i: after.i } } } });\n\n/** A recovery measurement is what a drill found, beside the writes of the run. */\nexport interface RecoveryMeasured {\n /** This time is from the reply to the last accepted write that the store kept to the fault, or null with no such write. */\n readonly rpo: Quantity | null;\n /** This time is `rpo` less the age of the drill: what a schedule adds to its interval. It is null for a control and for an election. */\n readonly excess: Quantity | null;\n /** These are the accepted writes that the store lost, below a write that it kept. A restore must leave none. */\n readonly holes: readonly number[];\n /** This count is the number of accepted writes after the last write of the last backup, or null without a backup. */\n readonly afterBackup: number | null;\n /** This flag tells if the tenants have the same data after the recovery, or null when that is not known. */\n readonly sameData: boolean | null;\n}\n\nconst rounded = (value: number): number => Math.round(value * 1e6) / 1e6;\n\n/** This function gives the acknowledgement time of each accepted write of the first client of a run. */\nconst firstAcks = (events: readonly ProbeEvent[], second: number | null): Map<number, number> => {\n const acks = new Map<number, number>();\n for (const event of events) {\n const n = Number(event[\"n\"]);\n if (event.ev === \"ack\" && (second === null || n < second)) acks.set(n, event.t);\n }\n return acks;\n};\n\n/** This function gives the measurement of a drill, from its run. `t0` is the fault. */\nexport const recoveryOf = (drill: Drill, run: Run, t0: number): RecoveryMeasured => {\n const record = run.group?.drill;\n const sameData = record === undefined || record.after === null ? null : record.after === record.before;\n if (drill.recovery === \"election\" || record === undefined) return { rpo: null, excess: null, holes: [], afterBackup: null, sameData };\n const acks = firstAcks(run.events, record.second);\n const accepted = [...acks.keys()].sort((a, b) => a - b);\n const cutoff = record.backups.at(-1)?.last?.n ?? 0;\n const afterBackup = accepted.filter((n) => n > cutoff).length;\n const holds = run.group?.holds ?? null;\n if (holds === null) return { rpo: null, excess: null, holes: [], afterBackup, sameData };\n const kept = new Set(holds);\n const ownKept = holds.filter((n) => record.second === null || n < record.second);\n const highest = ownKept.length === 0 ? 0 : Math.max(...ownKept);\n const holes = accepted.filter((n) => n < highest && !kept.has(n));\n const lastKept = accepted.filter((n) => kept.has(n)).at(-1);\n const rpo = lastKept === undefined ? null : rounded((t0 - acks.get(lastKept)!) / 1e9);\n return {\n rpo: rpo === null ? null : { value: rpo, unit: \"s\" },\n excess: rpo === null || drill.quiet === true ? null : { value: rounded(rpo - valueIn(drill.age, \"s\")), unit: \"s\" },\n holes,\n afterBackup,\n sameData,\n };\n};\n\n/** This function gives the findings of a drill: each rule of a recovery that its run broke. */\nexport const recoveryFindings = (measured: RecoveryMeasured, writes: Writes): string[] => {\n const findings: string[] = [];\n if (measured.sameData === null) findings.push(\"the set did not converge, thus nothing compared the data of the tenants\");\n else if (!measured.sameData) findings.push(\"the data of the tenants changed in the recovery\");\n if (measured.holes.length > 0)\n findings.push(`the restore lost ${measured.holes.length} accepted writes below a write that it kept, the first at ${measured.holes[0]}`);\n const lost = writes.lost?.length ?? null;\n if (measured.afterBackup !== null && lost !== null && Math.abs(lost - measured.afterBackup) > LOSS_MARGIN)\n findings.push(`the restore lost ${lost} accepted writes, and ${measured.afterBackup} came after the last backup`);\n return findings;\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, ClusterStage, KernelRecord, ProbeEvent, ReplicaSetStage, Run, SentinelEvent, SentinelStage, Stage } from \"./cell.ts\";\nimport { socketsOf } from \"./driver.ts\";\nimport type { RecoveryMeasured } from \"./recovery.ts\";\nimport { recoveryFindings, recoveryOf } from \"./recovery.ts\";\nimport { INJECT, noiseOf } from \"./verdict.ts\";\n\n/**\n * This module measures a run of a group cell. It gives the first write that a primary accepted\n * after the fault, and the timeline of the group. The Sentinels of a group announce its timeline.\n * The logs of the members of a replica set or of the nodes of a cluster, and its client, tell it. The\n * module also gives what became of each write.\n */\n\n/** These are the stages of a timeline under Sentinels, in their sequence after a fault. */\nexport const STAGES: readonly SentinelStage[] = [\n \"+sdown\",\n \"+odown\",\n \"+try-failover\",\n \"+elected-leader\",\n \"+selected-slave\",\n \"+promoted-slave\",\n \"+switch-master\",\n \"+convert-to-slave\",\n];\n\n/** An error on the way is one kind of error that the client met after the fault. It has its first time from the fault, and its count. */\nexport interface ErrorOnTheWay {\n readonly name: string;\n readonly first: Quantity;\n readonly count: number;\n}\n\n/**\n * A writes record tells what became of the writes of a run, by their sequence numbers:\n * - `old` counts the writes that the primary of the start of the run accepted after the fault. A\n * cluster counts none: its client publishes through one node, not through the leader of the queue.\n * - `lost` are the writes that a primary accepted and the group did not keep. They are the cost\n * of a split brain. It is null when the group did not converge after the run.\n * - `unknown` are the writes that the client sent and did not see accepted: an error, or no answer.\n * `held` tells if the group kept each one, or null when it did not converge.\n * - `duplicates` has one entry for each extra copy that the group holds: a write held three times\n * has two entries. It is null when the group did not converge. A key holds one copy by\n * construction, thus only a list can show a copy.\n */\nexport interface Writes {\n readonly sent: number;\n readonly acked: number;\n readonly old: number;\n readonly lost: readonly number[] | null;\n readonly unknown: ReadonlyArray<{ readonly n: number; readonly held: boolean | null }>;\n readonly duplicates?: readonly number[] | null;\n /** These are the counts of a pair (`Cell.pair`), from its two final reads. */\n readonly sets?: PairSets;\n}\n\n/** These are the counts that the bands of `Outcomes` judge: each one has the same name there. */\nexport interface PairSets {\n readonly unknown: number;\n readonly kept: number;\n readonly stranded: number;\n readonly absent: number;\n readonly missing: number;\n readonly warnings: number;\n}\n\n/** A group measurement is what one run of a group cell measured, beside its time. */\nexport interface GroupMeasured {\n /** These are the member that was the primary at the start, and the member of the first accepted write after the fault. */\n readonly from: string;\n readonly to: string | null;\n /** These are the times of each stage from the fault: the first announcement by any Sentinel. A stage that no Sentinel announced is absent. */\n readonly stages: Partial<Record<Stage, Quantity>>;\n readonly writes: Writes;\n readonly errors: readonly ErrorOnTheWay[];\n /** These are the delays of the stamps of the observer after the writes of the Sentinels, for a calibration. */\n readonly lags?: readonly Quantity[];\n /** This is what a recovery drill measured, for a drill only. */\n readonly recovery?: RecoveryMeasured;\n}\n\nconst between =(from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\n/** This function gives the member whose address and port is `at`, or null. */\nconst memberAt = (run: Run, at: unknown): string | null => {\n if (typeof at !== \"string\") return null;\n const ip = at.split(\":\")[0];\n return Object.entries(run.group?.members ?? {}).find(([, part]) => part.ip === ip)?.[0] ?? null;\n};\n\n/** This function gives the time of each stage of a timeline from an instant: the first announcement of each, after the instant. */\nexport const stagesOf = (timeline: readonly SentinelEvent[], from: number): Partial<Record<Stage, Quantity>> => {\n const out: Partial<Record<Stage, Quantity>> = {};\n for (const line of timeline) {\n if (line.ev !== \"sentinel\" || line.t < from) continue;\n const stage = STAGES.find((each) => each === line.event);\n if (stage === undefined || out[stage] !== undefined) continue;\n // the down states count for the primary only, not for a replica or a Sentinel\n if ((stage === \"+sdown\" || stage === \"+odown\") && !String(line.detail ?? \"\").startsWith(\"master \")) continue;\n out[stage] = between(from, line.t);\n }\n return out;\n};\n\n/** These are the stages of the timeline of a replica set, in their usual sequence after a fault. */\nexport const REPLICA_SET_STAGES: readonly ReplicaSetStage[] = [\n \"member-down\",\n \"election-start\",\n \"elected\",\n \"caught-up\",\n \"writable\",\n \"old-primary-steps-down\",\n \"discovered\",\n \"written-off\",\n \"first-write\",\n];\n\n/**\n * A member mark is how a log line of mongod marks a stage: by its id, or by its message. The\n * message is the fallback for a version whose ids differ. `at` tells where the line comes from:\n * the old primary, or another member.\n */\ninterface MemberMark {\n readonly ids: readonly number[];\n readonly message: RegExp;\n readonly at: \"old\" | \"other\";\n}\n\n/** These are the log lines of mongod that mark each stage of a member. */\nexport const MEMBER_MARKS: Readonly<Record<Exclude<ReplicaSetStage, \"discovered\" | \"written-off\" | \"first-write\">, MemberMark>> = {\n \"member-down\": { ids: [21216], message: /now in state DOWN/, at: \"other\" },\n \"election-start\": { ids: [4615652, 21437], message: /^Starting an election|Skipping dry run|Conducting a dry run/, at: \"other\" },\n elected: { ids: [21450], message: /^Election succeeded/, at: \"other\" },\n \"caught-up\": { ids: [21363], message: /^Exited primary catch-up mode/, at: \"other\" },\n writable: { ids: [21331], message: /^Transition to primary complete/, at: \"other\" },\n \"old-primary-steps-down\": { ids: [21809, 21475, 962660], message: /relinquishing primary|Stepping down from primary/, at: \"old\" },\n};\n\n/** This function tells if a log line of a member marks a stage, with the old primary of the run. */\nconst marks = (line: SentinelEvent, stage: keyof typeof MEMBER_MARKS, old: string, oldAddress: string): boolean => {\n const mark = MEMBER_MARKS[stage];\n const member = String(line[\"member\"] ?? \"\");\n if ((mark.at === \"old\") !== (member === old)) return false;\n const attr = (line[\"attr\"] ?? {}) as Record<string, unknown>;\n // the DOWN state counts for the old primary only, as another member sees it\n if (stage === \"member-down\" && !JSON.stringify(attr).includes(oldAddress)) return false;\n // the generic state change of the old primary: PRIMARY to another state\n if (stage === \"old-primary-steps-down\" && Number(line[\"id\"]) === 21358 && attr[\"oldState\"] === \"PRIMARY\") return true;\n return mark.ids.includes(Number(line[\"id\"])) || mark.message.test(String(line[\"msg\"] ?? \"\"));\n};\n\n/**\n * This function gives the time of each stage of a replica set from an instant, in a run. The stages\n * of the members come from their log lines (`ev` \"mongod\"), whose times the lab puts on the\n * monotonic clock. The stages of the client come from its lines:\n * - `discovered`: a member other than the old primary becomes RSPrimary in the view of the client.\n * - `written-off`: the first heartbeat of the client to the old primary that fails.\n * - `first-write`: the first write that a primary accepts, of a write that the client sent after\n * the commit of the fault (`sentAfter`). It is on a new primary when `lands` is `new`.\n */\nexport const replicaSetStagesOf = (\n run: Run,\n from: number,\n sentAfter: number,\n lands: \"new\" | \"same\",\n): Partial<Record<Stage, Quantity>> => {\n const out: Partial<Record<Stage, Quantity>> = {};\n const old = run.group?.primary ?? \"\";\n const oldIp = run.group?.members[old]?.ip ?? \"\";\n const oldAddress = `${oldIp}:`;\n for (const line of run.group?.timeline ?? []) {\n if (line.ev !== \"mongod\" || line.t < from) continue;\n for (const stage of Object.keys(MEMBER_MARKS) as Array<keyof typeof MEMBER_MARKS>)\n if (out[stage] === undefined && marks(line, stage, old, oldAddress)) out[stage] = between(from, line.t);\n }\n const isOld = (address: unknown): boolean => typeof address === \"string\" && address.startsWith(oldAddress);\n for (const event of run.events) {\n if (event.t < from) continue;\n if (out.discovered === undefined && event.ev === \"sdam\" && event[\"event\"] === \"server-changed\" && !isOld(event[\"address\"])) {\n const next = event[\"next\"] as { readonly type?: string } | null;\n if (next?.type === \"RSPrimary\") out.discovered = between(from, event.t);\n }\n if (out[\"written-off\"] === undefined && event.ev === \"sdam\" && event[\"event\"] === \"heartbeat-failed\" && isOld(event[\"address\"]))\n out[\"written-off\"] = between(from, event.t);\n }\n const accepted = acceptedAfter(run, sentAfter, lands);\n if (accepted !== undefined) out[\"first-write\"] = between(from, accepted.t);\n return out;\n};\n\n/** These are the stages of the timeline of a cluster of RabbitMQ, in their usual sequence after a fault. */\nexport const CLUSTER_STAGES: readonly ClusterStage[] = [\"monitor-down\", \"elected\", \"followed\", \"old-leader-steps-down\", \"first-write\"];\n\n/**\n * These are the log lines of RabbitMQ that mark each stage of a cluster, by their message (ra 3.1.10,\n * ra_server_proc.erl:871, :1336-1345 and :1974). `at` tells where the line comes from: the node of the\n * old leader, or another node.\n */\nexport const NODE_MARKS: Readonly<Record<Exclude<ClusterStage, \"first-write\">, { readonly message: RegExp; readonly at: \"old\" | \"other\" }>> = {\n \"monitor-down\": { message: /Leader monitor down/, at: \"other\" },\n elected: { message: /: candidate -> leader in term/, at: \"other\" },\n followed: { message: /detected a new leader/, at: \"other\" },\n \"old-leader-steps-down\": { message: /: leader -> \\w+ in term/, at: \"old\" },\n};\n\n/**\n * This function gives the time of each stage of a cluster from an instant, in a run. The stages of\n * the nodes come from their log lines (`ev` \"rabbit\"), whose times the lab puts on the monotonic\n * clock. `first-write` is the first confirm of a publish that the client sent after the commit of\n * the fault (`sentAfter`), through any node.\n */\nexport const clusterStagesOf = (run: Run, from: number, sentAfter: number): Partial<Record<Stage, Quantity>> => {\n const out: Partial<Record<Stage, Quantity>> = {};\n const old = run.group?.primary ?? \"\";\n for (const line of run.group?.timeline ?? []) {\n if (line.ev !== \"rabbit\" || line.t < from) continue;\n const member = String(line[\"member\"] ?? \"\");\n for (const stage of Object.keys(NODE_MARKS) as Array<keyof typeof NODE_MARKS>) {\n const mark = NODE_MARKS[stage];\n if (out[stage] === undefined && (mark.at === \"old\") === (member === old) && mark.message.test(String(line[\"msg\"] ?? \"\"))) out[stage] = between(from, line.t);\n }\n }\n const accepted = acceptedAfter(run, sentAfter, \"same\");\n if (accepted !== undefined) out[\"first-write\"] = between(from, accepted.t);\n return out;\n};\n\n/** This function gives the first write that a primary accepted, of a write sent after an instant. It is on a new primary for `new`. */\nconst acceptedAfter = (run: Run, sentAfter: number, lands: \"new\" | \"same\"): ProbeEvent | undefined => {\n const sent = new Map<number, number>();\n for (const event of run.events) if (event.ev === \"sent\") sent.set(Number(event[\"n\"]), event.t);\n const primary = run.group?.primary ?? \"\";\n return run.events.find((event) => {\n if (event.ev !== \"ack\" || (sent.get(Number(event[\"n\"])) ?? -Infinity) <= sentAfter) return false;\n const member = memberAt(run, event[\"at\"]);\n return member !== null && (lands === \"new\" ? member !== primary : true);\n });\n};\n\n/** This function gives what became of each write of a run, from the lines of the client and the keys that the group kept. */\nexport const writesOf = (run: Run, after: number, primary: string): Writes => {\n const { events } = run;\n const sent = events.filter((event) => event.ev === \"sent\");\n // without its done line, the stop ended the last write that the client sent\n const done = events.find((event) => event.ev === \"done\")?.t ?? sent.at(-1)?.t ?? Infinity;\n const acks = new Map<number, ProbeEvent>();\n for (const event of events) if (event.ev === \"ack\") acks.set(Number(event[\"n\"]), event);\n const holds = run.group?.holds ?? null;\n const kept = holds === null ? null : new Set(holds);\n const old = [...acks.values()].filter((event) => event.t > after && memberAt(run, event[\"at\"]) === primary).length;\n const lost = kept === null ? null : [...acks.keys()].filter((n) => !kept.has(n)).sort((a, b) => a - b);\n // a write in flight when the client stopped is not on the way: the stop ended it\n const unknown = sent\n .filter((event) => event.t < done && !acks.has(Number(event[\"n\"])))\n .map((event) => {\n const n = Number(event[\"n\"]);\n return { n, held: kept === null ? null : kept.has(n) };\n });\n // each entry that repeats the one before it, in order, is one extra copy\n const duplicates = holds === null ? null : [...holds].sort((a, b) => a - b).filter((n, at, all) => all[at - 1] === n);\n const oldHolds = run.group?.oldHolds;\n return { sent: sent.length, acked: acks.size, old, lost, unknown, duplicates, ...(oldHolds === undefined ? {} : { sets: setsOf(run, acks.keys(), unknown, new Set(oldHolds)) }) };\n};\n\n/**\n * This function splits the writes of a pair by its two final reads. A write with no reply is `kept`\n * on the new primary. It is `stranded` on the old primary alone, or `absent` from each server.\n */\nconst setsOf = (run: Run, acked: Iterable<number>, unknown: Writes[\"unknown\"], old: ReadonlySet<number>): PairSets => {\n const kept = unknown.filter((each) => each.held === true).length;\n const stranded = unknown.filter((each) => each.held !== true && old.has(each.n)).length;\n return {\n unknown: unknown.length,\n kept,\n stranded,\n absent: unknown.length - kept - stranded,\n missing: [...acked].filter((n) => !old.has(n)).length,\n warnings: run.events.filter((event) => event.ev === \"notice\" && event[\"severity\"] === \"WARNING\").length,\n };\n};\n\n/** This function gives the errors that the client met after an instant: each kind, its first time, and its count. */\nexport const errorsOf = (events: readonly ProbeEvent[], after: number): ErrorOnTheWay[] => {\n const done = events.find((event) => event.ev === \"done\")?.t ?? Infinity;\n const kinds = new Map<string, { first: number; count: number }>();\n for (const event of events) {\n if (event.t <= after || event.t >= done) continue;\n const name =\n event.ev === \"error\"\n ? String(event[\"errno\"] ?? event[\"name\"] ?? \"error\")\n : event.ev === \"fail\"\n ? String(event[\"name\"] ?? \"fail\")\n : event.ev === \"sentinel-error\"\n ? \"sentinel-error\"\n : null;\n if (name === null) continue;\n const seen = kinds.get(name);\n if (seen === undefined) kinds.set(name, { first: event.t, count: 1 });\n else seen.count += 1;\n }\n return [...kinds].map(([name, { first, count }]) => ({ name, first: between(after, first), count }));\n};\n\n/**\n * This function gives the delay of each stamp of the observer after the write of its Sentinel that\n * the observer read. That write is the latest write of the Sentinel's socket toward the observer,\n * at the stamp or before it. The prober records each write (`tx`) on the clock of the stamps.\n */\nexport const lagsOf = (run: Run, kernel: readonly KernelRecord[]): Quantity[] => {\n const timeline = run.group?.timeline ?? [];\n const locals = new Map<string, string>();\n for (const line of timeline) if (line.ev === \"subscribed\") locals.set(String(line.sentinel), String(line[\"local\"]));\n const out: Quantity[] = [];\n for (const line of timeline) {\n if (line.ev !== \"sentinel\") continue;\n const sentinel = String(line.sentinel);\n const local = locals.get(sentinel);\n if (local === undefined) continue;\n const write = kernel\n .filter((record) => record.ev === \"tx\" && record.src === sentinel && record.dst === local && record.mono <= line.t)\n .at(-1);\n if (write !== undefined) out.push(between(write.mono, line.t));\n }\n return out;\n};\n\n/** This type is the measurement of observe.ts, which a group run fills. */\nexport interface GroupReading {\n readonly outcome: { readonly kind: \"answered\" } | { readonly kind: \"silent\" };\n readonly elapsed: Quantity | null;\n readonly socket: Quantity | null;\n readonly noticed: Quantity | null;\n readonly void: string | null;\n readonly finding: string | null;\n readonly group: GroupMeasured;\n}\n\n/**\n * This function reads one run of a group cell.\n * - The reference is the start of the commit of the fault, as the injector stamped it. For a\n * stall, it is the first write into the fault, as for the stall of a direct pair.\n * - The outcome is the first write that a primary accepted after the fault. The prediction says\n * which primary: a new one, or the same one after the lift. In a replica set, it is the first\n * accepted write of a write that the client sent after the commit of the fault.\n * - The stages come from the Sentinels, or from the logs of the members of a replica set and the\n * lines of its client (`replicaSetStagesOf`).\n * - Its time is the last segment with data that the client's socket to that primary received\n * before the client saw the acceptance. The stamp of the client is the fallback.\n * - A run is void when the prober lost records, or when the client did not become ready. It is\n * also void when a Sentinel entered its TILT mode, or when the election split its votes. A band\n * from the fault whose commit took longer than δ_abs is void too. So is a band whose hold lifted\n * more than δ_abs late.\n */\nexport const measureGroup = (cell: Cell, run: Run): GroupReading => {\n const { events, kernel } = run;\n const { prediction } = cell;\n const expected = prediction.group;\n const primary = run.group?.primary ?? \"\";\n const ready = events.find((event) => event.ev === \"ready\");\n const t0 = run.fault?.t0;\n const empty: GroupMeasured = {\n from: primary,\n to: null,\n stages: {},\n writes: { sent: 0, acked: 0, old: 0, lost: null, unknown: [] },\n errors: [],\n };\n const silent = { outcome: { kind: \"silent\" } as const, elapsed: null, socket: null, noticed: null, finding: null };\n if (ready === undefined) return { ...silent, void: \"the client never became ready\", group: empty };\n if (t0 === undefined || run.fault === null) return { ...silent, void: \"the fault never committed\", group: empty };\n if (run.lost === null)\n return { ...silent, void: \"the prober wrote no clock line after the run, so nothing says what it dropped\", group: empty };\n if (run.lost > 0) return { ...silent, void: `the prober dropped ${run.lost} records`, group: empty };\n const timeline = run.group?.timeline ?? [];\n const heal = run.heal ?? null;\n const lands = expected?.lands ?? \"new\";\n // a replica set and a cluster have no authority: their members and the client tell their stages. The\n // client of a cluster publishes through one node, and the leader of the queue can be on another one\n const cluster = cell.cluster !== undefined;\n // a Kafka group has no log lines in its record: the client and the whole partition tell its run\n const kafka = cell.kafka !== undefined;\n const replica = cell.replicaSet !== undefined || cluster || kafka;\n const stall = prediction.detects === false && prediction.recovers !== undefined;\n const stages = kafka ? {} : cluster ? clusterStagesOf(run, t0, run.fault.t1) : replica ? replicaSetStagesOf(run, t0, run.fault.t1, lands) : stagesOf(timeline, t0);\n // the first write that a primary accepted after the fault: on a new primary, or on the same one\n // after the lift. In a replica set, it is the first write sent after the commit of the fault\n // that a primary accepts: a partial cut leaves the old primary its writes\n const after = lands === \"same\" && heal !== null && (!replica || stall) ? heal.t0 : t0;\n const sentAt = new Map<number, number>();\n for (const event of events) if (event.ev === \"sent\") sentAt.set(Number(event[\"n\"]), event.t);\n const accepted = events.find((event) => {\n if (event.ev !== \"ack\" || event.t <= after) return false;\n if (replica && (sentAt.get(Number(event[\"n\"])) ?? -Infinity) <= run.fault!.t1) return false;\n const member = memberAt(run, event[\"at\"]);\n return member !== null && (lands === \"new\" && !cluster ? member !== primary : true);\n });\n const to = accepted === undefined ? null : memberAt(run, accepted[\"at\"]);\n // the first write of a replica set is the outcome itself: a stall's first write is the write into it\n if (replica) {\n delete stages[\"first-write\"];\n if (accepted !== undefined) stages[\"first-write\"] = between(t0, accepted.t);\n }\n const group: GroupMeasured = {\n from: primary,\n to,\n stages,\n writes: writesOf(run, t0, cluster ? \"\" : primary),\n errors: errorsOf(events, t0),\n ...(cell.calibrates === \"sentinels\" ? { lags: lagsOf(run, kernel) } : {}),\n ...(cell.drill === undefined ? {} : { recovery: recoveryOf(cell.drill, run, t0) }),\n };\n let voided: string | null = null;\n const tilt = timeline.find((line) => line.ev === \"sentinel\" && line.event === \"+tilt\" && line.t >= t0);\n if (tilt !== undefined) voided = `a Sentinel entered TILT ${between(t0, tilt.t).value} s after the fault: the host delayed it, not its timers`;\n const split = timeline.find((line) => line.ev === \"sentinel\" && line.event === \"-failover-abort-not-elected\" && line.t >= t0);\n const elected = timeline.find((line) => line.ev === \"sentinel\" && line.event === \"+elected-leader\" && line.t >= t0);\n if (voided === null && split !== undefined && (elected === undefined || elected.t > split.t))\n voided = \"the election split its votes and runs again after 2 × failover-timeout, which the band does not bound\";\n // a Sentinel starts a failover in the tick of its +odown, unless an attempt of its own came less\n // than 2 × failover-timeout before: then the run measured an earlier run, not its own fault\n const odown = stages[\"+odown\"];\n if (voided === null && odown !== undefined && stages[\"+try-failover\"] === undefined)\n voided = \"no Sentinel started a failover after +odown: each was in the hold-off of 2 × failover-timeout after an earlier attempt\";\n // a hold lifts at its instant in the VM: a band assumes that instant, and a lift later than the\n // noise moved each stage after it\n if (voided === null && cell.hold !== undefined && (prediction.detects !== null || kafka)) {\n if (heal === null) voided = \"the fault never lifted\";\n else {\n const late = (heal.t0 - t0) / 1e9 - valueIn(cell.hold, \"s\");\n if (late > valueIn(INJECT, \"s\"))\n voided = `the lift came ${Math.round(late * 1e4) / 10} ms after its hold: the injector was late, not the group`;\n }\n }\n // a band holds for the round trips that it assumes: the first one of the client's socket to the old\n // primary, or to the first node of a cluster\n const firstAddress = cluster\n ? String(events.find((event) => event.ev === \"connected\")?.[\"at\"] ?? \"\")\n : `${run.group?.members[primary]?.ip}:${(cell.group ?? cell.replicaSet ?? cell.kafka)?.port}`;\n const assumed = prediction.detects === null ? undefined : prediction.rtt;\n const first = kernel.find(\n (record) =>\n record.netns === run.netns &&\n record.dst === firstAddress &&\n record.tcp?.srtt !== undefined,\n );\n const rtt = first?.tcp?.srtt === undefined ? null : valueIn(first.tcp.srtt, \"us\") / 1000;\n if (voided === null && assumed !== undefined && rtt !== null && rtt > valueIn(assumed.high, \"ms\"))\n voided = `rtt-over-assumption: its first round trip was ${rtt} ms, above the ${valueIn(assumed.high, \"ms\")} ms that the prediction assumes`;\n if (voided === null && prediction.detects === true && prediction.from === \"fault\" && (run.fault.t1 - run.fault.t0) / 1e6 > valueIn(INJECT, \"ms\"))\n voided = `the commit of the fault took ${Math.round((run.fault.t1 - run.fault.t0) / 1e5) / 10} ms, longer than the noise of the pipeline: its start is not known`;\n\n // the reference: the fault, or for a stall the first write into it\n let reference = t0;\n if (prediction.detects === false && prediction.recovers !== undefined) {\n const into = events.find((event) => event.ev === \"sent\" && event.t > run.fault!.t1);\n if (into === undefined || (heal !== null && into.t > heal.t0)) {\n voided ??= \"the write in flight went out before the fault held\";\n } else {\n reference = into.t;\n // the stall must end where the prediction assumed: after the firing before, and before its own\n const { heal: bounds } = prediction.recovers;\n if (heal === null) voided ??= \"the stall never ended\";\n else if (\n valueIn(between(reference, heal.t0), \"s\") <= valueIn(bounds.low, \"s\") ||\n valueIn(between(reference, heal.t1), \"s\") >= valueIn(bounds.high, \"s\")\n )\n voided ??= `the stall ended ${between(reference, heal.t0).value}–${between(reference, heal.t1).value} s after the write, outside the ${bounds.low.value}–${bounds.high.value} s its prediction assumed`;\n }\n }\n\n // findings: a failover where none should be, a client on the wrong primary, an error out of its band\n const findings: string[] = [];\n // a failover: a Sentinel switches the primary, or another member of a replica set wins an election\n const switched = replica ? stages[\"elected\"] : stages[\"+switch-master\"];\n if (expected?.failover === false && switched !== undefined)\n findings.push(`the group failed over ${switched.value} s after the fault, where it should not`);\n // a Kafka run has no line of an election: the leader after the run tells if the leader changed\n const leaderAfter = run.group?.after ?? null;\n if (kafka && expected !== undefined && leaderAfter !== null && expected.failover !== (leaderAfter !== primary))\n findings.push(expected.failover ? `the leader stayed on ${primary}, where it should change` : `the leader moved to ${leaderAfter}, where it should stay on ${primary}`);\n for (const stage of expected?.quiet ?? []) {\n const at = stages[stage];\n if (at !== undefined) findings.push(`${stage} came ${at.value} s after the fault, where it should not`);\n }\n if (accepted !== undefined && lands === \"same\" && !cluster && !kafka && to !== primary)\n findings.push(`the client wrote to ${to ?? String(accepted[\"at\"])}, where it should stay on ${primary}`);\n for (const error of expected?.errors ?? []) {\n const met = group.errors.find((each) => each.name === error.name);\n const noise = valueIn(noiseOf(cell), \"s\");\n if (met === undefined) findings.push(`the client never met ${error.name}`);\n else if (met.first.value < valueIn(error.low, \"s\") - noise || met.first.value > valueIn(error.high, \"s\") + noise)\n findings.push(`the client met ${error.name} ${met.first.value} s after the fault, outside [${valueIn(error.low, \"s\")}, ${valueIn(error.high, \"s\")}] s`);\n }\n if (expected?.lost !== undefined) {\n const { low, high } = expected.lost;\n const lost = group.writes.lost;\n if (lost === null) findings.push(\"the group did not converge, thus the count of its lost writes is not known\");\n else if (lost.length < low || lost.length > high) findings.push(`the group lost ${lost.length} accepted writes, outside [${low}, ${high}]`);\n }\n if (expected?.duplicates !== undefined) {\n const { low, high } = expected.duplicates;\n const copies = group.writes.duplicates ?? null;\n if (copies === null) findings.push(\"the group did not converge, thus the count of its extra copies is not known\");\n // a read that found no write counts no copy: that zero says nothing\n else if (run.group?.holds?.length === 0) findings.push(\"the group holds no write, thus the count of its extra copies says nothing\");\n else if (copies.length < low || copies.length > high) findings.push(`the group holds ${copies.length} extra copies, outside [${low}, ${high}]`);\n }\n const { sets } = group.writes;\n for (const [name, band] of Object.entries(expected?.outcomes ?? {})) {\n const count = sets?.[name as keyof PairSets];\n if (count === undefined) findings.push(`the run has no count of ${name}`);\n else if (count < band.low || count > band.high) findings.push(`the count of ${name} is ${count}, outside [${band.low}, ${band.high}]`);\n }\n if (group.recovery !== undefined) findings.push(...recoveryFindings(group.recovery, group.writes));\n if (accepted === undefined) {\n if (prediction.detects !== null || kafka)\n findings.push(lands === \"new\" ? \"the client never wrote to a new primary in the window\" : \"the client never wrote again in the window\");\n return { ...silent, void: voided, finding: findings[0] ?? null, group };\n }\n // the kernel's time of the acceptance: the last segment with data from that primary at the\n // client's stamp or before it. The monitor and the pinger of a driver have their own sockets to\n // each member, thus only the sockets of the pool count\n const address = String(accepted[\"at\"]);\n const others = new Set(socketsOf(events).filter((socket) => socket.role !== \"pool\").map((socket) => socket.local));\n const segment = kernel\n .filter(\n (record) =>\n record.netns === run.netns &&\n record.ev === \"rx\" &&\n record.dst === address &&\n !others.has(String(record.src)) &&\n (record.seg?.len.value ?? 0) > 0 &&\n record.mono <= accepted.t &&\n record.mono > after,\n )\n .at(-1);\n const at = segment?.mono ?? accepted.t;\n return {\n outcome: { kind: \"answered\" },\n elapsed: between(reference, at),\n socket: between(reference, accepted.t),\n noticed: segment === undefined ? null : between(segment.mono, accepted.t),\n void: voided,\n finding: findings[0] ?? null,\n group,\n };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { CallReading, ReconnectReading } from \"./application.ts\";\nimport type { RunLoad } from \"./load.ts\";\nimport {\n callOf,\n closeOrExit,\n dropFinding,\n dropOf,\n exitOf,\n firstUnanswered,\n leftAfter,\n jitterOfLines,\n pingsOf,\n programLines,\n reconnectFinding,\n reconnectOf,\n} from \"./application.ts\";\nimport type { Cell, Jitter, KernelRecord, ProbeEvent, Reference, Run } from \"./cell.ts\";\nimport { requestFirst } from \"./cell.ts\";\nimport type { DriverStepTime } from \"./driver.ts\";\nimport { countFinding, measureDriver, proxiedClose } from \"./driver.ts\";\nimport type { ConntrackReading } from \"./conntrack.ts\";\nimport { measureConntrack } from \"./conntrack.ts\";\nimport { loadOf, streamsLoadOf } from \"./load.ts\";\nimport type { PauseReading } from \"./pause.ts\";\nimport { measurePause } from \"./pause.ts\";\nimport type { GroupMeasured } from \"./timeline.ts\";\nimport type { PortsReading } from \"./ports.ts\";\nimport { measurePorts } from \"./ports.ts\";\nimport type { QueueReading } from \"./queue.ts\";\nimport { measureQueue } from \"./queue.ts\";\nimport { measureGroup } from \"./timeline.ts\";\nimport type { Pairing } from \"./verdict.ts\";\nimport { INJECT, delayVoids, noiseOf, pairingOf, requestWords } from \"./verdict.ts\";\n\n/**\n * An outcome tells how the wait of a run ended. The socket failed with an errno, or it read the\n * end of the file. Or nothing came, or the reply came back after a stall. The observer can also\n * close the connection itself (`closed`), or its program can drop it on its own timer (`dropped`).\n */\nexport type Outcome =\n | { readonly kind: \"error\"; readonly errno: string }\n | { readonly kind: \"eof\" }\n | { readonly kind: \"silent\" }\n | { readonly kind: \"answered\" }\n | { readonly kind: \"closed\" }\n | { readonly kind: \"dropped\" };\n\n/**\n * A request reading is what the second request of an HTTP client met, from the lines of the\n * client. It holds the connection of its first try, a new try, and its outcome. `gap` is the time\n * from the end of the first reply to the send of the second request.\n */\nexport interface RequestReading {\n readonly connection: \"reused\" | \"new\";\n readonly retried: boolean;\n readonly error: string | null;\n readonly pending: boolean;\n readonly gap: Quantity | null;\n}\n\n/** A measurement is what one run measured, against the prediction of its cell. */\nexport interface Measured {\n readonly environment: number;\n readonly index: number;\n readonly outcome: Outcome;\n /**\n * This time is from the reference event of the prediction to the detection, both as the kernel\n * stamped them in the records of the prober. It is null when nothing detected the fault.\n */\n readonly elapsed: Quantity | null;\n /** This time is the same interval from the TCP_INFO samples of the client, the second vantage. */\n readonly socket: Quantity | null;\n /** This time is how long the client took to see the error after the kernel reported it. */\n readonly noticed: Quantity | null;\n /**\n * These are the steps of the kernel after the reference: each keepalive probe, or each firing of\n * the RTO timer. After a stall, they are each retransmission from the send, the loss probe first.\n */\n readonly steps: readonly Quantity[];\n /**\n * These are the reply times of a measurement-only cell. For each request after the first, a\n * sample is the time from its send to the first data after it.\n */\n readonly samples?: readonly Quantity[];\n /** This measure is the run of an open-loop cell against its schedule (`Run.schedule`), with its failed replies. Its times are in ms. */\n readonly load?: RunLoad;\n /** This count is the number of keepalive probes that the kernel sent. */\n readonly probes: number;\n /** This count is the number of segments that the kernel sent again. */\n readonly retransmissions: number;\n /** This count is the number of segments that the socket received after the request. */\n readonly acks: number;\n /** This count is the number of bytes that the client read after the request. */\n readonly bytes?: number;\n /**\n * This time is when a router of the topology forgot the flow of the client. It counts from the\n * last segment that the client received before the fault. It is null when no router forgot the flow.\n */\n readonly forgot?: Quantity | null;\n /**\n * This time is the first round trip of the socket of the observer. It is the smoothed round trip\n * in its first record, which is the sample of the handshake. It is null when no record has it.\n */\n readonly rtt?: Quantity | null;\n /** This record tells what reordering did in a run of a measurement-only cell, from the records of its two ends. */\n readonly reordering?: Reordering;\n /** These are the times of the proxy of a calibration cell, one for each request and its reply. */\n readonly crossings?: Crossings;\n /** This record is what a run of a group cell measured: the stages of its timeline, and what became of each write. */\n readonly group?: GroupMeasured;\n /** This record is what a run of a queue cell measured: the count of the queue, its counters, and each connection. */\n readonly queue?: QueueReading;\n /** This record is what a run of a port cell measured: the count of each search, and when each port came back. */\n readonly ports?: PortsReading;\n /** This record is what a run of a conntrack cell measured: the flows, the count, and when a slot came back. */\n readonly conntrack?: ConntrackReading;\n /** This record is what the second request of an HTTP client met, for a cell whose prediction says it. */\n readonly request?: RequestReading | null;\n /** This record is the time of each later band of a driver cell (`DriverBand.then`). */\n readonly driver?: { readonly steps: readonly DriverStepTime[] };\n /** This record is what the client did after the detection, for a prediction that says when it reconnects. */\n readonly reconnect?: ReconnectReading;\n /** This record is what the call in flight of a WebSocket client met. */\n readonly call?: CallReading;\n /**\n * This time is from the drop line of the program to the close of its socket by its own side: a\n * FIN or an abort. A prediction that says how the program drops (`drop`) gets it. It is null\n * when the socket did not close itself in the run. A prediction can say that the client process\n * ends with the run (`exits`). Then a close at that end is no close by the program, and `left` is null.\n */\n readonly left?: Quantity | null;\n /**\n * This time is from the drop line of the program to the end of the client process. A socket gets\n * it when it stayed open until that end. The kernel closed it then, not the program (`exits`).\n */\n readonly exited?: Quantity;\n /**\n * This record is the pairing window of the run: the jitter bound that it measured, and the\n * window that its pairings used (`pairingOf`). A run that has a jitter record gets it. Thus a\n * reader can check each pairing of the run again.\n */\n readonly pairing?: Pairing;\n /** This record is what a run of a paused consumer measured. */\n readonly pause?: PauseReading;\n /** This text is the reason that the run cannot count, or null. A void run is not a pass and not a finding. */\n readonly void: string | null;\n /** This text tells what in the run disagrees with the prediction, other than its timing, or null. */\n readonly finding: string | null;\n}\n\n/**\n * A reordering record is what reordering, duplicates and losses did to the data of a run. The\n * receiver is the client, and the sender is the socket of its peer.\n * - `outOfOrder` counts the arrivals at the client beyond a hole, and `duplicates` counts the\n * arrivals whose data the client had. The prober reads the two from each arrival, against `rcv_nxt`.\n * - An arrival can hold more than one segment. The kernel joins the segments that wait in the\n * backlog of a socket while its owner holds it.\n * - `ooo` is the count of the kernel of the client in segments (`rcv_ooopack`).\n * - `sacked` and `lost` are the most segments that the sender held as SACKed and as lost.\n * - `dsacks` is the DSACK blocks that the sender received, and `fast` its fast retransmissions.\n * - `degree` is the highest reordering degree of the sender (`tp->reordering`), and `seen` the\n * reorderings that it detected (`reord_seen`).\n *\n * The counts of the kernel are null for a record of the prober before version 0.2.\n */\nexport interface Reordering {\n readonly outOfOrder: number;\n readonly duplicates: number;\n readonly ooo: number | null;\n readonly sacked: number | null;\n readonly lost: number | null;\n readonly dsacks: number | null;\n readonly fast: number;\n readonly degree: number | null;\n readonly seen: number | null;\n}\n\n/**\n * A crossings record is the time of a proxy for each request (`up`) and for each reply (`down`).\n * The time of a request starts at its arrival on the socket toward the client. It stops at the\n * write on the socket toward the target. The time of a reply goes the other way. A write is a\n * `tx` record of the prober.\n */\nexport interface Crossings {\n readonly hop: string;\n readonly up: readonly Quantity[];\n readonly down: readonly Quantity[];\n}\n\n/** These are the errno numbers that the kernel reports to a socket, by the names that predictions use. */\nconst ERRNO: Readonly<Record<number, string>> = {\n 32: \"EPIPE\",\n 101: \"ENETUNREACH\",\n 103: \"ECONNABORTED\",\n 104: \"ECONNRESET\",\n 110: \"ETIMEDOUT\",\n 111: \"ECONNREFUSED\",\n 113: \"EHOSTUNREACH\",\n};\n\n/** This function gives the interval between two instants on the one clock, in seconds to the microsecond. */\nconst between = (from: number, to: number): Quantity =>\n quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\n/** These functions give the states of a state record: before the change, and after it. TCP_ESTABLISHED is 1, TCP_CLOSE_WAIT 8. */\nconst oldState = (record: KernelRecord): number | undefined => (record as { readonly old?: number }).old;\nconst newState = (record: KernelRecord): number | undefined => (record as { readonly new?: number }).new;\n\nconst count = (event: ProbeEvent | undefined, field: string): number =>\n event === undefined ? 0 : Number(event[field] ?? 0);\n\n/** This function gives the view of the client on the same interval: TCP_INFO, with a sample each 2 ms. */\nconst socketVantage = (\n cell: Cell,\n events: readonly ProbeEvent[],\n ready: ProbeEvent,\n request: ProbeEvent,\n): Quantity | null => {\n const { from } = cell.prediction.detects === true ? cell.prediction : { from: undefined };\n if (from === undefined || from === \"peer-closed\" || from === \"fault\" || from === \"ping-sent\" || from === \"first-sent\" || from === \"last-data\" || from === \"last-reply\") return null;\n const ended = events.find((event) => event.ev === \"error\" || event.ev === \"eof\");\n const reference =\n from === \"last-received\"\n ? ready\n : from === \"request-sent\"\n ? request\n : events.find(\n (event) =>\n event.ev === \"kernel\" && event.t >= request.t && count(event, \"retransmits\") > 0,\n );\n return ended === undefined || reference === undefined ? null : between(reference.t, ended.t);\n};\n\n/** A socket place is a socket of a run: its namespace and its cookie. */\nexport interface SocketPlace {\n readonly netns: number;\n readonly cookie: number;\n}\n\nconst ipOf = (address: string): string => address.split(\":\")[0]!;\n\n/**\n * This function finds the socket that became ESTABLISHED in a run, in a namespace, whose peer\n * matches. In a topology, an address of a hop serves each run, thus only the socket that the\n * run opened is the socket of the run.\n */\nconst opened = (\n run: Run,\n netns: number,\n peer: (dst: string) => boolean,\n): SocketPlace | undefined => {\n const record = run.kernel.find(\n (each) =>\n each.netns === netns &&\n each.ev === \"state\" &&\n newState(each) === 1 &&\n each.dst !== undefined &&\n peer(each.dst),\n );\n return record?.cookie === undefined ? undefined : { netns, cookie: record.cookie };\n};\n\n/**\n * This function finds the socket of a hop that carries the request of a run toward the target. It is\n * the first socket of the hop that sends data to the target after the send of the request. A pooler can\n * reuse a server that it opened before the run, in the warm-up of the environment. Then the first\n * socket that it opens in the run is another one (run 39160356281).\n */\nconst carried = (run: Run, netns: number, target: string): SocketPlace | undefined => {\n const request = run.events.filter((event) => event.ev === \"sent\")[1];\n if (request === undefined) return undefined;\n const record = run.kernel.find(\n (each) => each.netns === netns && each.ev === \"tx\" && each.dst === target && (each.seg?.len.value ?? 0) > 0 && each.mono >= request.t,\n );\n return record?.cookie === undefined ? undefined : { netns, cookie: record.cookie };\n};\n\n/** This function finds the socket of the target for the connection of a run. In a topology, its peer is the last hop. */\nconst targetSocket = (run: Run, local: unknown): SocketPlace | undefined => {\n if (run.topology === undefined) {\n const cookie = run.kernel.find(\n (record) => record.netns === run.targetNetns && record.dst === local,\n )?.cookie;\n return cookie === undefined ? undefined : { netns: run.targetNetns, cookie };\n }\n const peer = run.topology.targetPeer;\n return opened(run, run.targetNetns, (dst) => ipOf(dst) === peer);\n};\n\n/**\n * This function finds the socket of the observer of a cell in a run:\n * - the client socket, by the address that it connected from, in its namespace.\n * - the socket of the target for the same connection, in its namespace.\n * - a socket of a proxy of the topology, toward the client or toward the target. Toward the target,\n * it is the socket that carries the request, else the first socket that the run opens.\n */\nexport const socketOf = (cell: Cell, run: Run): SocketPlace | undefined => {\n const local = run.events.find((event) => event.ev === \"connected\")?.[\"local\"];\n const observer = cell.observer ?? \"client\";\n if (observer === \"client\") {\n const cookie = run.kernel.find((record) => record.netns === run.netns && record.src === local)?.cookie;\n return cookie === undefined ? undefined : { netns: run.netns, cookie };\n }\n if (observer === \"server\") return targetSocket(run, local);\n const hop = run.topology?.hops[observer.hop];\n if (hop === undefined) return undefined;\n return observer.toward === \"client\"\n ? opened(run, hop.netns, (dst) => ipOf(dst) === hop.client)\n : (carried(run, hop.netns, hop.target) ?? opened(run, hop.netns, (dst) => dst === hop.target));\n};\n\n/**\n * This function finds the socket of the peer of the observer: its close is the reference of a FIN.\n * In a direct pair, it is the other end of the connection. In a topology, it is the socket of the\n * target, for the client.\n */\nconst peerOf = (cell: Cell, run: Run): SocketPlace | undefined => {\n const local = run.events.find((event) => event.ev === \"connected\")?.[\"local\"];\n const server = cell.observer === \"server\";\n if (run.topology !== undefined) return server ? undefined : targetSocket(run, local);\n const netns = server ? run.netns : run.targetNetns;\n const cookie = run.kernel.find(\n (record) => record.netns === netns && (server ? record.src : record.dst) === local,\n )?.cookie;\n return cookie === undefined ? undefined : { netns, cookie };\n};\n\n/** This function tells if sequence number a is after b, in the 32-bit space of TCP (`after` in include/net/tcp.h). */\nconst after32 = (a: number, b: number): boolean => ((a - b) | 0) > 0;\n\n/** This function gives the largest value of a count of the kernel in records, or null when no record has it. */\nconst most = (records: readonly KernelRecord[], count: (record: KernelRecord) => number | undefined): number | null =>\n records.reduce<number | null>((top, record) => {\n const value = count(record);\n return value === undefined ? top : Math.max(top ?? 0, value);\n }, null);\n\n/** This function gives what reordering did in a run, from the records of the receiver and of the sender. */\nexport const reorderingOf = (\n receiver: readonly KernelRecord[],\n sender: readonly KernelRecord[],\n): Reordering => {\n const arrivals = receiver.filter(\n (record) => record.ev === \"rx\" && (record.seg?.len.value ?? 0) > 0 && record.tcp?.rcv_nxt !== undefined,\n );\n const outOfOrder = arrivals.filter((record) => after32(record.seg!.seq, record.tcp!.rcv_nxt!)).length;\n const duplicates = arrivals.filter(\n (record) => !after32(record.seg!.seq + record.seg!.len.value, record.tcp!.rcv_nxt!),\n ).length;\n return {\n outOfOrder,\n duplicates,\n ooo: most(receiver, (record) => record.tcp?.rcv_ooopack),\n sacked: most(sender, (record) => record.tcp?.sacked),\n lost: most(sender, (record) => record.tcp?.lost),\n dsacks: most(sender, (record) => record.tcp?.dsack_dups),\n fast: sender.filter((record) => record.ev === \"retrans\" && record.why === \"fast\").length,\n degree: most(sender, (record) => record.tcp?.reordering),\n seen: most(sender, (record) => record.tcp?.reord_seen),\n };\n};\n\n/**\n * This function gives the times of a proxy in a run, for each request after the first. The time\n * of a request starts at its arrival on the socket of the proxy toward the client. It stops at the\n * next write on the socket toward the target. The time of its reply starts at its arrival on the\n * socket toward the target, and it stops at the next write toward the client. A request without\n * each record gives no time.\n */\nexport const crossingsOf = (\n run: Run,\n hop: string,\n toClient: SocketPlace | undefined,\n toTarget: SocketPlace | undefined,\n): Crossings => {\n const up: Quantity[] = [];\n const down: Quantity[] = [];\n if (toClient === undefined || toTarget === undefined) return { hop, up, down };\n const of = (place: SocketPlace) =>\n run.kernel.filter((record) => record.netns === place.netns && record.cookie === place.cookie);\n const near = of(toClient);\n const far = of(toTarget);\n const arrival = (records: readonly KernelRecord[], from: number, to: number) =>\n records.find((record) => record.ev === \"rx\" && (record.seg?.len.value ?? 0) > 0 && record.mono > from && record.mono < to);\n const write = (records: readonly KernelRecord[], from: number, to: number) =>\n records.find((record) => record.ev === \"tx\" && record.mono >= from && record.mono < to);\n const sends = run.events.filter((event) => event.ev === \"sent\").slice(1);\n sends.forEach((send, n) => {\n const next = sends[n + 1]?.t ?? Infinity;\n const request = arrival(near, send.t, next);\n const relayed = request === undefined ? undefined : write(far, request.mono, next);\n if (request === undefined || relayed === undefined) return;\n up.push(between(request.mono, relayed.mono));\n const reply = arrival(far, relayed.mono, next);\n const answered = reply === undefined ? undefined : write(near, reply.mono, next);\n if (reply !== undefined && answered !== undefined) down.push(between(reply.mono, answered.mono));\n });\n return { hop, up, down };\n};\n\n/**\n * This function reads one run against its cell, from the records of the kernel first.\n * - The socket of the run is the socket of its observer. It is the socket that the client connected\n * from, in its namespace, or the socket of the target or of a proxy for that connection.\n * - The fault must hold before the event that it must meet. That is before the request goes into\n * it, and before the first keepalive probe. A live peer answers that probe, and the answer\n * starts the idle time again. A run where the fault was late is void. A run whose records the\n * prober lost is also void.\n * - For an HTTP client, it also reads what the second request met (`requestOf`). An outcome other\n * than the one that the prediction gives is a finding.\n */\nexport const measure = (cell: Cell, run: Run): Measured => {\n const socketRead = measureSocket(cell, run);\n // a run with a jitter record says the window of its pairings. A record from before SYS-25 has none\n const read: Measured = run.jitter === undefined ? socketRead : { ...socketRead, pairing: pairingOf(cell, run) };\n const expected = cell.prediction.request;\n if (cell.probe.http === undefined && expected === undefined) return read;\n const request = requestOf(run.events);\n if (expected === undefined || read.void !== null) return { ...read, request };\n const differs = requestFinding(expected, request);\n const finding = read.finding === null ? differs : differs === null ? read.finding : `${read.finding}. ${differs}`;\n return { ...read, request, finding };\n};\n\n/**\n * This function measures the jitter of the program of the observer in a run, from its records\n * (`Jitter`). The acts count up to the start of the fault, or up to the reply of the client when\n * the fault has no stamp. A run with no lines of a program, or no socket of the observer, has no act.\n */\nexport const jitterOf = (cell: Cell, run: Run): Jitter => {\n const lines = programLines(cell, run);\n const ready = run.events.find((event) => event.ev === \"ready\");\n const place = lines.length === 0 || ready === undefined ? undefined : socketOf(cell, run);\n if (ready === undefined || place === undefined) return { acts: 0, bound: null };\n const socket = run.kernel.filter((record) => record.netns === place.netns && record.cookie === place.cookie);\n const local = run.events.find((event) => event.ev === \"connected\")?.[\"local\"];\n // a line of a server names its connection by its peer: the peer of the socket of the server\n const named = cell.observer === \"server\" ? (socket.find((record) => record.dst !== undefined)?.dst ?? local) : local;\n return jitterOfLines(lines, socket, named, run.fault?.t0 ?? ready.t);\n};\n\n/** This function tells how a request reading differs from its prediction, or gives null. */\nconst requestFinding = (expected: NonNullable<Cell[\"prediction\"][\"request\"]>, read: RequestReading | null): string | null => {\n if (read === null) return `the second request never went out, where it should meet: ${requestWords(expected)}`;\n const same =\n read.connection === expected.connection &&\n read.retried === expected.retried &&\n read.error === expected.error &&\n read.pending === (expected.pending === true);\n return same ? null : `the second request met: ${requestWords(read)}, not ${requestWords(expected)}`;\n};\n\n/**\n * This function reads the second request of an HTTP client from its lines. Its first try is its\n * first `request` line, and each `retry` line is a new try. Its end is its `error` line, or its\n * `replied` line. A request with neither is pending. It gives null when the client wrote no try.\n *\n * A new try that gets no connection writes no `retry` line. Its dial writes a `dial-error` line.\n * Thus a `dial-error` line after the first try and before the end is also a new try.\n */\nexport const requestOf = (events: readonly ProbeEvent[]): RequestReading | null => {\n const of = (event: ProbeEvent) => Number(event[\"i\"]) === 2;\n const tries = events.filter((event) => (event.ev === \"request\" || event.ev === \"retry\") && of(event));\n const first = tries[0];\n if (first === undefined) return null;\n const failed = events.find((event) => event.ev === \"error\" && of(event));\n const replied = events.some((event) => event.ev === \"replied\" && of(event));\n const ready = events.find((event) => event.ev === \"ready\");\n const sent = events.find((event) => event.ev === \"sent\" && of(event));\n const end = failed ?? events.find((event) => event.ev === \"done\" && of(event));\n const dialed = events.some(\n (event) => event.ev === \"dial-error\" && event.t > first.t && (end === undefined || event.t <= end.t),\n );\n return {\n connection: first[\"reused\"] === true ? \"reused\" : \"new\",\n retried: dialed || tries.some((each) => each.ev === \"retry\"),\n error: failed === undefined ? null : String(failed[\"errno\"]),\n pending: failed === undefined && !replied,\n gap: ready === undefined || sent === undefined ? null : between(ready.t, sent.t),\n };\n};\n\n/** This function reads the socket of one run against its cell, as `measure` does without the second request of an HTTP client. */\nconst measureSocket = (cell: Cell, run: Run): Measured => {\n if (run.missing !== undefined)\n return {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" },\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions: 0,\n acks: 0,\n void: `the environment cannot do this cell: ${run.missing}`,\n finding: null,\n };\n if (cell.prediction.detects === null && cell.prediction.pause !== undefined) return measurePause(run, cell.prediction.pause);\n if (cell.group !== undefined || cell.replicaSet !== undefined || cell.cluster !== undefined || cell.pair !== undefined || cell.kafka !== undefined) {\n const read = measureGroup(cell, run);\n return {\n environment: run.environment,\n index: run.index,\n outcome: read.outcome,\n elapsed: read.elapsed,\n socket: read.socket,\n noticed: read.noticed,\n steps: [],\n probes: 0,\n retransmissions: run.kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length,\n acks: read.group.writes.acked,\n void: read.void,\n finding: read.finding,\n group: read.group,\n };\n }\n if (cell.prediction.detects === null && cell.prediction.queue !== undefined)\n return measureQueue(run, cell.prediction.queue);\n if (cell.prediction.detects === null && cell.prediction.ports !== undefined)\n return measurePorts(run, cell.prediction.ports);\n if (cell.prediction.detects === null && cell.prediction.conntrack !== undefined)\n return measureConntrack(run, cell.prediction.conntrack);\n // a driver with more than one socket: its bands name their socket and their line\n if (cell.prediction.detects !== null && cell.prediction.driver !== undefined) return measureDriver(cell, run);\n const { events, kernel } = run;\n const ready = events.find((event) => event.ev === \"ready\");\n const local = events.find((event) => event.ev === \"connected\")?.[\"local\"];\n // a client in a gap sends its second request by itself, and its idle connection counts from its first reply\n const inflight = cell.probe.mode !== \"idle\" && cell.probe.mode !== \"gap\";\n const request = inflight ? events.filter((event) => event.ev === \"sent\")[1] : ready;\n const server = cell.observer === \"server\";\n const place = socketOf(cell, run);\n const netns = place?.netns;\n const cookie = place?.cookie;\n const socket = kernel.filter((record) => record.netns === netns && record.cookie === cookie);\n // the socket of the peer for the same connection: a FIN counts from the change of state that its close makes\n const peerPlace = peerOf(cell, run);\n const peerNetns = peerPlace?.netns;\n const peerCookie = peerPlace?.cookie;\n // the bytes that the client read after its request, and the first and last time that data came\n const after = request === undefined ? [] : events.filter((event) => event.ev === \"data\" && event.t > request.t);\n const bytes = after.reduce((sum, event) => sum + Number(event[\"n\"] ?? 0), 0);\n // the end of the flow in a router of the topology: its DESTROY line, by the address of the client\n const forgotten = (run.middlebox ?? []).find(\n (line) =>\n line.ev === \"ct\" &&\n line[\"type\"] === \"DESTROY\" &&\n typeof line[\"orig\"] === \"string\" &&\n (line[\"orig\"] as string).startsWith(`${String(local)}>`),\n );\n const keepalives = socket.filter(\n (record) => record.ev === \"probe\" && record.what === \"keepalive\",\n );\n const retransmitted = socket.filter((record) => record.ev === \"retrans\");\n /**\n * This function examines the timer that drives the measurement: keepalive or retransmit. It\n * finds the first firing in an interval that was two jiffies or more behind its wheel slot. The\n * wheel does a slot in the tick when it is due, thus such a delay comes from the CPU: the host\n * stopped a vCPU. The prediction is about the timing of the kernel, and that firing measured\n * the timing of the host. One jiffy is a tick that occurred while the wheel worked, and δ_abs\n * includes it. The function ignores the other timer: the retransmit timer fires one time, idle,\n * after a reply, and it does not move a keepalive.\n */\n const delayed = (from: number, to: number, timer: \"keepalive\" | \"retransmit\"): string | null => {\n const firings = socket.filter(\n (record) =>\n record.ev === \"timer\" && record.what === timer && record.mono >= from && record.mono <= to,\n );\n const late = firings.find((record) => delayVoids(record.behind?.value ?? 0, run.hz, noiseOf(cell)));\n if (late !== undefined)\n return `its ${timer} timer ran ${late.behind!.value} jiffies behind its wheel slot: the VM delayed it, not the kernel`;\n // a keepalive timer that finds its socket held by its owner sends nothing, and it tries again\n // HZ/20 later (tcp_keepalive_timer). The retransmit timer only gives its work to the release\n // by the owner, some microseconds later\n const held = firings.find((record) => timer === \"keepalive\" && record.owned === true);\n return held === undefined\n ? null\n : \"its keepalive timer found the socket held by its owner and put itself off by HZ/20: the run measured the owner, not the timer\";\n };\n const acks =\n request === undefined\n ? 0\n : socket.filter((record) => record.ev === \"rx\" && record.mono > request.t).length;\n // the first round trip of the observer: the smoothed round trip in its first record, the sample of the handshake\n const srtt = socket.find((record) => record.tcp?.srtt !== undefined)?.tcp?.srtt;\n const rtt = srtt === undefined ? null : quantity(valueIn(srtt, \"us\") / 1000, \"ms\");\n const base = {\n environment: run.environment,\n index: run.index,\n probes: keepalives.length,\n retransmissions: retransmitted.length,\n acks,\n rtt,\n };\n const nothing = {\n outcome: { kind: \"silent\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n finding: null,\n };\n\n if (ready === undefined) return { ...base, ...nothing, void: \"the client never had its reply\" };\n if (request === undefined)\n return { ...base, ...nothing, void: \"the request was never sent into the fault\" };\n if (run.lost === null)\n return {\n ...base,\n ...nothing,\n void: \"the prober wrote no clock line after the run, so nothing says what it dropped\",\n };\n if (run.lost > 0) return { ...base, ...nothing, void: `the prober dropped ${run.lost} records` };\n if (cookie === undefined)\n return { ...base, ...nothing, void: \"the prober saw nothing of this connection\" };\n let voided: string | null = null;\n if (run.fault !== null) {\n // the request of a client must go into the fault. The request of a cell on the server side must\n // reach the server first, and its reply must not reach the client before the fault holds. An\n // mtu-blackhole drops only the long reply, thus its request goes after the fault, as a client's does.\n // An event at a hop that comes while the request is in flight comes after the request too\n const replyFirst = (server && inflight && cell.fault !== \"mtu-blackhole\") || requestFirst(cell);\n const replied = events.some(\n (event) => event.ev === \"data\" && event.t > request.t && event.t < run.fault!.t1,\n );\n if (inflight && !replyFirst && run.fault.t1 > request.t)\n voided = \"the request went out before the fault held\";\n else if (replyFirst && run.fault.t1 < request.t)\n voided = \"the request went out into the fault, so the server never had it\";\n else if (replyFirst && replied)\n voided = \"the server's reply arrived before the fault held\";\n else if (keepalives[0] !== undefined && keepalives[0].mono < run.fault.t1)\n voided = \"a keepalive probe went out before the fault held\";\n }\n // a band holds for the first round trips that its prediction assumes. Above them, the run measured another path\n const assumed = cell.prediction.detects === null ? undefined : cell.prediction.rtt;\n if (voided === null && assumed !== undefined && rtt !== null && valueIn(rtt, \"ms\") > valueIn(assumed.high, \"ms\"))\n voided = `rtt-over-assumption: its first round trip was ${rtt.value} ms, above the ${valueIn(assumed.high, \"ms\")} ms that the prediction assumes`;\n\n // the detection as the kernel reported it to the owner of the socket, and as the client saw it.\n // The process of a server or of a proxy tells nothing that the harness reads, thus its kernel tells all\n const remote = cell.observer !== undefined && cell.observer !== \"client\";\n // the run stops the client at its end: what the own close of the client draws after its done line is\n // not a detection. A broker with linger 0, as RabbitMQ, resets each connection that its client closes\n const stop = events.find((event) => event.ev === \"done\")?.t ?? Number.POSITIVE_INFINITY;\n const anError = socket.find((record) => record.ev === \"error\" && (record.err ?? 0) !== 0 && record.mono < stop);\n const seen = remote\n ? undefined\n : events.find((event) => (event.ev === \"error\" || event.ev === \"eof\") && event.t < stop);\n // an end of file without an error is the change of state that the FIN of the peer makes, from\n // ESTABLISHED to CLOSE_WAIT, as the kernel stamps it\n const closeWait = socket.find((record) => record.ev === \"state\" && newState(record) === 8 && record.mono < stop);\n // a close of the observer itself, for a prediction that says it: from ESTABLISHED to FIN_WAIT1,\n // the FIN that its pool sends when it closes an idle connection\n const own =\n (cell.prediction.detects === true && cell.prediction.errno === \"CLOSED\") ||\n (cell.prediction.detects === null && cell.prediction.ends === \"own-close\")\n ? socket.find((record) => record.ev === \"state\" && oldState(record) === 1 && newState(record) === 4 && record.mono < stop)\n : undefined;\n // an error after that own close is what the close draws, not a detection. The run lifts its fault\n // after the outcome: a frozen broker then thaws, sees the FIN, and resets the socket (linger 0)\n const reported = anError !== undefined && own !== undefined && own.mono < anError.mono ? undefined : anError;\n // a drop by the program of the observer on its own timer: its `drop` line, at the kernel's stamp\n // of its close frame or its close. It counts when it comes before each report of the kernel\n const lines = programLines(cell, run);\n // a line of the client names the connection by its local address, and a line of a server by its\n // peer. That peer is the peer of the socket of the server: the last hop of a topology\n const named = server ? (socket.find((record) => record.dst !== undefined)?.dst ?? local) : local;\n const kernelEnded = reported?.mono ?? closeWait?.mono ?? own?.mono ?? seen?.t;\n // the window of each pairing of a line with its act: δ_abs, or the jitter of the program in this run\n const paired = pairingOf(cell, run).delta;\n const first = dropOf(lines, socket, named, paired);\n const drop = first !== undefined && (kernelEnded === undefined || first.at <= kernelEnded) ? first : undefined;\n const dropped = drop !== undefined;\n const outcome: Outcome = dropped\n ? { kind: \"dropped\" }\n : reported !== undefined\n ? { kind: \"error\", errno: ERRNO[reported.err!] ?? `E${reported.err}` }\n : closeWait !== undefined || seen?.ev === \"eof\"\n ? { kind: \"eof\" }\n : own !== undefined\n ? { kind: \"closed\" }\n : seen !== undefined\n ? { kind: \"error\", errno: String(seen[\"errno\"]) }\n : { kind: \"silent\" };\n const ended = drop?.at ?? kernelEnded;\n const noticed =\n reported !== undefined && seen !== undefined && !dropped ? between(reported.mono, seen.t) : null;\n const { prediction } = cell;\n // the pings of a heartbeat of the program, at the kernel's stamps of their writes\n const pings = pingsOf(lines, socket, named, paired);\n // keepalive counts from the last segment received before the fault. The budget of the give-up\n // counts from the first retransmission of the RTO timer after the fault holds, not from the tail\n // loss probe before it. A retransmission before the fault is of an earlier segment, for example\n // the SYN of the connect of a proxy in a fresh environment. A reset counts from the send of the client. The kernel has no record of that send, thus the\n // stamp is the stamp of the client. A toxic counts from the start of its commit. A heartbeat\n // counts from the write of its first ping that got no answer before the detection\n const before = run.fault?.t1 ?? ready.t;\n const referenceAt = (from: Reference): number | undefined => {\n if (from === \"request-sent\") return request.t;\n if (from === \"fault\") return run.fault?.t0;\n if (from === \"client-start\") return (events.find((event) => event.ev === \"connecting\") ?? events[0])?.t;\n if (from === \"ping-sent\") return firstUnanswered(pings, socket, ended)?.at;\n const record: KernelRecord | undefined =\n from === \"last-received\"\n ? socket.filter((each) => each.ev === \"rx\" && each.mono <= before).at(-1)\n : from === \"last-data\"\n ? // the receive check of a heartbeat counts bytes, not an ACK: the last segment with data before the end\n socket.filter((each) => each.ev === \"rx\" && (each.seg?.len.value ?? 0) > 0 && each.mono <= (ended ?? before)).at(-1)\n : from === \"last-reply\"\n ? // a retry counts from the refusal before it: the last segment with data before the end\n socket.filter((each) => each.ev === \"rx\" && (each.seg?.len.value ?? 0) > 0 && each.mono < (ended ?? Infinity)).at(-1)\n : from === \"first-retransmission\"\n ? retransmitted.find((each) => each.why === \"rto\" && each.mono > before)\n : from === \"first-sent\"\n ? socket.find((each) => each.ev === \"tx\" && each.mono > before && (each.seg?.len.value ?? 0) > 0)\n : from === \"syn-sent\"\n ? socket.find((each) => each.ev === \"state\" && newState(each) === 2)\n : from === \"peer-closed\"\n ? kernel.find(\n (each) =>\n each.netns === peerNetns &&\n each.cookie === peerCookie &&\n each.ev === \"state\" &&\n oldState(each) === 1,\n )\n : // a reference that this judge does not know does not come: its band is a finding\n undefined;\n // behind a proxy, a pooler keeps its connection to the target across its clients: the run can\n // reuse one that it did not open, and the close of the target closes each of them at once\n if (record === undefined && from === \"peer-closed\" && peerCookie === undefined) return proxiedClose(run);\n return record?.mono;\n };\n // in a topology, the bytes after the request and the instant that a router forgot the flow\n const lastRx =\n kernel\n .filter((each) => each.netns === run.netns && each.src === local && each.ev === \"rx\" && each.mono <= before)\n .at(-1)?.mono ?? ready.t;\n const chain =\n run.topology === undefined\n ? {}\n : { bytes, forgot: forgotten === undefined ? null : between(lastRx, forgotten.t) };\n\n // a measurement-only cell: each request of the run and the time to its reply, and the time from\n // its reference to the end of the connection, or to the last data\n if (prediction.detects === null) {\n // an open-loop client names the arrival of each line, and each time counts from its planned time\n // the client load has one schedule for each stream, and its measure is the pool of the streams\n const load =\n run.streams !== undefined\n ? (streamsLoadOf(events, run.streams)?.pool ?? null)\n : run.schedule === undefined\n ? undefined\n : loadOf(events, run.schedule);\n if (load === null) return { ...base, ...nothing, void: \"the client never started its schedule\" };\n const sends = load === undefined ? events.filter((event) => event.ev === \"sent\").slice(1) : [];\n // a reply ends at its last byte when the client says so (`replied`), and at its first data otherwise\n const answers = events.some((event) => event.ev === \"replied\") ? \"replied\" : \"data\";\n const samples = sends.flatMap((send, n) => {\n const next = sends[n + 1]?.t ?? Infinity;\n const reply = events.find((event) => event.ev === answers && event.t > send.t && event.t < next);\n return reply === undefined ? [] : [between(send.t, reply.t)];\n });\n const from = prediction.from === undefined ? undefined : referenceAt(prediction.from);\n const until = ended ?? after.at(-1)?.t;\n // the data of the client comes from its peer: the receiver and the sender of each reply\n const peerRecords =\n peerCookie === undefined\n ? []\n : kernel.filter((record) => record.netns === peerNetns && record.cookie === peerCookie);\n const proxy = cell.calibrates === undefined ? undefined : run.topology?.hops[cell.calibrates];\n const crossings =\n cell.calibrates === undefined\n ? {}\n : {\n crossings: crossingsOf(\n run,\n cell.calibrates,\n proxy === undefined ? undefined : socketOf({ ...cell, observer: { hop: cell.calibrates, toward: \"client\" } }, run),\n proxy === undefined ? undefined : socketOf({ ...cell, observer: { hop: cell.calibrates, toward: \"target\" } }, run),\n ),\n };\n // the reconnect after the end of the connection, against the bands of its waits. The end has no band\n const reconnect =\n prediction.reconnects === undefined || ended === undefined ? undefined : reconnectOf(run, ended, cookie, drop?.line.t ?? ended);\n const late = reconnect === undefined || prediction.reconnects === undefined ? null : reconnectFinding(prediction.reconnects, reconnect, noiseOf(cell));\n // the exact counts of the lines of the target: a count reads no timer\n const counted = prediction.counts === undefined ? null : countFinding(prediction.counts, run.server ?? []);\n return {\n ...base,\n ...nothing,\n ...chain,\n ...(reconnect === undefined ? {} : { reconnect }),\n finding: late ?? counted,\n outcome: ended !== undefined ? outcome : { kind: \"answered\" },\n ...(from === undefined || until === undefined ? {} : { elapsed: between(from, until) }),\n noticed: prediction.from === undefined ? null : noticed,\n steps: retransmitted\n .filter((record) => record.mono > request.t)\n .map((record) => between(request.t, record.mono)),\n samples,\n ...(load === undefined ? {} : { load }),\n reordering: reorderingOf(\n socket.filter((record) => record.mono > request.t),\n peerRecords.filter((record) => record.mono > request.t),\n ),\n ...crossings,\n void: voided,\n };\n }\n\n // a stall: nothing must detect it, and the connection must move again at the first\n // retransmission after it stops, timed from the send of the request, or of the first ping\n if (!prediction.detects && prediction.recovers !== undefined) {\n const { recovers } = prediction;\n // an idle client sends only the pings of its heartbeat: its stall counts from its first ping into it\n const start =\n cell.probe.mode === \"idle\"\n ? (lines.find((line) => line.ev === \"ping\" && line.t >= (run.fault?.t1 ?? 0)) ?? request)\n : request;\n const heal = run.heal ?? null;\n if (voided === null && heal === null) voided = \"the stall never ended\";\n else if (voided === null && heal !== null) {\n const from = between(start.t, heal.t0);\n const to = between(start.t, heal.t1);\n if (\n valueIn(from, \"s\") <= valueIn(recovers.heal.low, \"s\") ||\n valueIn(to, \"s\") >= valueIn(recovers.heal.high, \"s\")\n )\n voided = `the stall ended ${from.value}–${to.value} s after the send, outside the ${recovers.heal.low.value}–${recovers.heal.high.value} s its prediction assumed`;\n }\n const steps = retransmitted\n .filter((record) => record.mono > start.t)\n .map((record) => between(start.t, record.mono));\n if (ended !== undefined)\n return {\n ...base,\n ...nothing,\n outcome,\n steps,\n void: voided,\n finding: `detected after ${between(start.t, ended).value} s, where it should recover`,\n };\n // the first segment back after the stall stopped: the answer of the server to the\n // retransmission that got through, and the read of the reply by the client\n const answer =\n heal === null\n ? undefined\n : socket.find((record) => record.ev === \"rx\" && record.mono > heal.t0);\n if (answer === undefined)\n return {\n ...base,\n ...nothing,\n steps,\n void: voided,\n finding: \"it never moved again: nothing came back after the stall ended\",\n };\n const reply = events.find((event) => event.ev === \"data\" && event.t > start.t);\n voided ??= delayed(start.t, answer.mono, \"retransmit\");\n return {\n ...base,\n outcome: { kind: \"answered\" },\n elapsed: between(start.t, answer.mono),\n socket: reply === undefined ? null : between(start.t, reply.t),\n noticed: reply === undefined ? null : between(answer.mono, reply.t),\n steps,\n void: voided,\n finding: null,\n };\n }\n\n // a reply in a band: nothing must detect the fault, and the reply must come back in its time,\n // from the send of the request to the first segment that the socket receives after it\n if (!prediction.detects && prediction.replies !== undefined) {\n const window = valueIn(prediction.window, \"s\") * 1e9;\n if (ended !== undefined && ended - request.t <= window)\n return {\n ...base,\n ...nothing,\n ...chain,\n outcome,\n elapsed: between(request.t, ended),\n void: voided,\n finding: `detected after ${between(request.t, ended).value} s, where the reply should come`,\n };\n // the first segment with data: a proxy can acknowledge the request first, with no data\n const answer = socket.find(\n (record) => record.ev === \"rx\" && record.mono > request.t && (record.seg?.len.value ?? 0) > 0,\n );\n const reply = after[0];\n if (answer === undefined)\n return { ...base, ...nothing, ...chain, void: voided, finding: \"the reply never came\" };\n return {\n ...base,\n ...chain,\n outcome: { kind: \"answered\" },\n elapsed: between(request.t, answer.mono),\n socket: reply === undefined ? null : between(request.t, reply.t),\n noticed: reply === undefined ? null : between(answer.mono, reply.t),\n steps: [],\n void: voided,\n finding: null,\n };\n }\n\n if (!prediction.detects) {\n // the test of silence covers the window from the send of the request\n const window = valueIn(prediction.window, \"s\") * 1e9;\n if (ended === undefined || ended - request.t > window) {\n // the router keeps the flow in the window, unless the prediction says that it forgets it,\n // and when. Either way, nothing detects it\n const forgetIn = forgotten !== undefined && forgotten.t - request.t <= window ? forgotten : undefined;\n const expected = prediction.middlebox?.forgets;\n const after = forgetIn === undefined ? null : between(lastRx, forgetIn.t);\n let finding: string | null = null;\n if (expected === undefined) {\n if (after !== null) finding = `a router forgot the flow ${after.value} s after the last segment, where it should keep it`;\n } else if (after === null) {\n finding = \"no router forgot the flow in the window, where it should forget it\";\n } else {\n const noise = valueIn(noiseOf(cell), \"s\");\n const low = valueIn(expected.low, \"s\") - noise;\n const high = valueIn(expected.high, \"s\") + noise;\n if (after.value < low || after.value > high)\n finding = `a router forgot the flow ${after.value} s after the last segment, outside [${Math.round(low * 1e6) / 1e6}, ${Math.round(high * 1e6) / 1e6}] s`;\n }\n return { ...base, ...nothing, ...chain, void: voided, finding };\n }\n return {\n ...base,\n ...nothing,\n ...chain,\n outcome,\n elapsed: between(request.t, ended),\n void: voided,\n finding: `detected after ${between(request.t, ended).value} s, where nothing should`,\n };\n }\n\n if (ended === undefined)\n return {\n ...base,\n ...nothing,\n ...chain,\n void: voided,\n finding: `nothing detected it: ${prediction.timer} never fired`,\n };\n const reference = referenceAt(prediction.from);\n if (reference === undefined) {\n return {\n ...base,\n ...nothing,\n ...chain,\n outcome,\n noticed,\n void: voided,\n finding: `it ended without its reference event (${prediction.from})`,\n };\n }\n // the steps of a heartbeat are its later pings, each from the first ping that got no answer\n const steps =\n prediction.from === \"ping-sent\"\n ? pings.filter((ping) => ping.at > reference && ping.at <= ended).map((ping) => between(reference, ping.at))\n : (prediction.from === \"last-received\"\n ? keepalives\n : prediction.from === \"first-retransmission\"\n ? retransmitted.filter((record) => record.why === \"rto\" && record.mono > reference)\n : []\n ).map((record) => between(reference, record.mono));\n const matches =\n prediction.errno === \"EOF\"\n ? outcome.kind === \"eof\"\n : prediction.errno === \"CLOSED\"\n ? outcome.kind === \"closed\"\n : prediction.errno === \"DROPPED\"\n ? outcome.kind === \"dropped\"\n : outcome.kind === \"error\" && outcome.errno === prediction.errno;\n const words =\n outcome.kind === \"error\"\n ? outcome.errno\n : outcome.kind === \"closed\"\n ? \"its own close\"\n : outcome.kind === \"dropped\"\n ? \"a drop by its own program\"\n : \"end of file\";\n // the reconnect of the client after the detection, against the bands of its waits\n const reconnect = prediction.reconnects === undefined ? undefined : reconnectOf(run, ended, cookie, drop?.line.t ?? ended);\n const late = reconnect === undefined || prediction.reconnects === undefined ? null : reconnectFinding(prediction.reconnects, reconnect, noiseOf(cell));\n // a drop of the program against the way that the prediction gives: a close frame or a close\n const closed = prediction.drop === undefined || drop === undefined ? undefined : leftAfter(socket, drop.line);\n // the end of the client process closes each socket that is still open: that close is not the program's\n const { left, exited } =\n closed === undefined || drop === undefined || prediction.exits !== true\n ? { left: closed, exited: undefined }\n : closeOrExit(drop.line, closed, exitOf(run, cookie), noiseOf(cell));\n const how = prediction.drop === undefined || drop === undefined || left === undefined ? null : dropFinding(prediction.drop, drop, left, paired, exited);\n const found = [matches ? null : `it ended with ${words}, not ${prediction.errno}`, late, how].filter((each) => each !== null);\n const finding = found.length === 0 ? null : found.join(\". \");\n // the timer of an HTTP client or server is a timer of the program, not of the kernel: the kernel\n // timers of its socket do not drive the measurement\n const programTimer = cell.probe.http !== undefined && prediction.from === \"last-received\" && prediction.timer !== \"keepalive\";\n // a firing at the reference itself only moves the start of the interval. A reset meets the send\n // with no timer, a FIN arrives with none, and a toxic has its own clock\n if ((prediction.from === \"last-received\" && !programTimer) || prediction.from === \"first-retransmission\")\n voided ??= delayed(\n reference,\n ended,\n prediction.from === \"last-received\" ? \"keepalive\" : \"retransmit\",\n );\n // a heartbeat is a timer of the program. The retransmit timer of its ping fires in the same\n // interval, thus a delay of that timer behind its wheel slot tells that the VM stopped a vCPU\n if (prediction.from === \"ping-sent\") voided ??= delayed(reference, ended, \"retransmit\");\n // a timer of conntrack (expire_…) reaches its DESTROY through the listing of the router. A slow\n // listing between the expiry and the detection breaks the bound of its lag: the run measured the\n // pump, not the router. The expiry is at most the width of the band before the detection\n const lag = (valueIn(prediction.high, \"s\") - valueIn(prediction.low, \"s\")) * 1e9;\n const slow = prediction.timer.startsWith(\"expire_\")\n ? (run.middlebox ?? []).find(\n (line) =>\n line.ev === \"pump-slow\" &&\n line.t <= ended &&\n line.t + Number(line[\"took\"]) * 1e9 >= ended - lag,\n )\n : undefined;\n if (slow !== undefined)\n voided ??= `a listing of the router took ${Math.round(Number(slow[\"took\"]) * 1e4) / 10} ms, longer than the bound of its prediction`;\n // a toxic starts somewhere in the commit of its request. A commit longer than the noise of the\n // pipeline leaves its start unknown within δ_abs\n const commit = run.fault === null ? 0 : (run.fault.t1 - run.fault.t0) / 1e6;\n if (prediction.from === \"fault\" && commit > valueIn(INJECT, \"ms\"))\n voided ??= `the commit of the fault took ${Math.round(commit * 10) / 10} ms, longer than the noise of the pipeline: its start is not known`;\n // the view of the program of a heartbeat: from the line of its first ping without an answer to\n // the line of its drop, or to the line of the error that it saw\n const unanswered = prediction.from === \"ping-sent\" ? firstUnanswered(pings, socket, ended) : undefined;\n const endLine = drop?.line ?? seen;\n const view =\n unanswered !== undefined\n ? endLine === undefined\n ? null\n : between(unanswered.line.t, endLine.t)\n : remote\n ? null\n : socketVantage(cell, events, ready, request);\n return {\n ...base,\n ...chain,\n outcome,\n elapsed: between(reference, ended),\n socket: view,\n noticed,\n steps,\n ...(reconnect === undefined ? {} : { reconnect }),\n ...(left === undefined ? {} : { left }),\n ...(exited === undefined ? {} : { exited }),\n ...(cell.probe.ws !== undefined && inflight ? { call: callOf(events, request, ended) } : {}),\n void: voided,\n finding,\n };\n};\n","import { execFile } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { StartedTestContainer } from \"testcontainers\";\nimport type { Fabric, FabricManifest, RunRoute } from \"./cell.ts\";\n\n/**\n * A fabric is a routed network between the client and the target, on layer E3 (docs/S7.md). Four\n * routers of FRRouting, two leaves and two spines, run real BGP over veth pairs that containerlab\n * makes. The client hangs off leaf1 and the target off leaf2. The path between them goes through\n * spine1 by a weight, and spine2 holds the other path. A cell silences spine1, and the routes of\n * the leaves move to spine2 when a detector of the routers fires.\n *\n * This file holds the plan of the fabric as pure functions, and `openFabric` that starts it. A lab\n * opens a fabric with `Topology.fabric`. Thus the client, the target, the prober and the verdict\n * stay the same as on layer E1. The fabric needs a Linux host with containerlab and sudo.\n */\n\n/** This image is FRRouting 10.7.1, pinned by digest. */\nexport const FRR_IMAGE =\n \"quay.io/frrouting/frr:10.7.1@sha256:e995beaa50fdc9edb35eadcfefa29b7f062cc06f2b812613789b68fa541554d2\";\n\n/** This device is the side of the fabric in the client and in the target. Docker keeps eth0. */\nexport const FABRIC_DEVICE = \"eth1\";\n/** This address is the client on its network behind leaf1. */\nexport const FABRIC_CLIENT = \"10.1.0.2\";\n/** This address is the target on its network behind leaf2. */\nexport const FABRIC_TARGET = \"10.2.0.2\";\n\n/** This device of a leaf goes to spine1, thus a route on it is on the preferred path. */\nconst PREFERRED_DEVICE = \"eth1\";\n/** This limit is the time that the sessions and the routes get to come back before a run. */\nconst READY_MS = 90_000;\nconst READY_POLL_MS = 250;\n\n/** A router is one box of the fabric, as data. */\ninterface Router {\n readonly name: string;\n readonly as: number;\n readonly id: string;\n readonly interfaces: Readonly<Record<string, string>>;\n readonly neighbors: ReadonlyArray<{ readonly address: string; readonly as: number; readonly weight?: number }>;\n /** This prefix is the network behind a leaf, which its BGP advertises. */\n readonly network?: string;\n /** This prefix is the network behind the other leaf. A move is a change of its route. */\n readonly remote?: string;\n}\n\nconst CLIENT_NET = \"10.1.0.0/24\";\nconst TARGET_NET = \"10.2.0.0/24\";\n\n/** These are the routers. Each leaf prefers spine1 by a weight of 100, thus the path of each run is known. */\nexport const ROUTERS: readonly Router[] = [\n {\n name: \"leaf1\",\n as: 65001,\n id: \"10.255.0.1\",\n interfaces: { eth1: \"10.0.1.0/31\", eth2: \"10.0.2.0/31\", eth3: \"10.1.0.1/24\" },\n neighbors: [\n { address: \"10.0.1.1\", as: 65101, weight: 100 },\n { address: \"10.0.2.1\", as: 65102 },\n ],\n network: CLIENT_NET,\n remote: TARGET_NET,\n },\n {\n name: \"leaf2\",\n as: 65002,\n id: \"10.255.0.2\",\n interfaces: { eth1: \"10.0.3.0/31\", eth2: \"10.0.4.0/31\", eth3: \"10.2.0.1/24\" },\n neighbors: [\n { address: \"10.0.3.1\", as: 65101, weight: 100 },\n { address: \"10.0.4.1\", as: 65102 },\n ],\n network: TARGET_NET,\n remote: CLIENT_NET,\n },\n {\n name: \"spine1\",\n as: 65101,\n id: \"10.255.1.1\",\n interfaces: { eth1: \"10.0.1.1/31\", eth2: \"10.0.3.1/31\" },\n neighbors: [\n { address: \"10.0.1.0\", as: 65001 },\n { address: \"10.0.3.0\", as: 65002 },\n ],\n },\n {\n name: \"spine2\",\n as: 65102,\n id: \"10.255.1.2\",\n interfaces: { eth1: \"10.0.2.1/31\", eth2: \"10.0.4.1/31\" },\n neighbors: [\n { address: \"10.0.2.0\", as: 65001 },\n { address: \"10.0.4.0\", as: 65002 },\n ],\n },\n];\n\nconst LEAVES = ROUTERS.filter((router) => router.remote !== undefined);\n\n/** These are the links between the routers. The links to the client and the target come from `topologyOf`. */\nconst LINKS: ReadonlyArray<readonly [string, string]> = [\n [\"leaf1:eth1\", \"spine1:eth1\"],\n [\"leaf1:eth2\", \"spine2:eth1\"],\n [\"leaf2:eth1\", \"spine1:eth2\"],\n [\"leaf2:eth2\", \"spine2:eth2\"],\n];\n\n/** This text is the `daemons` file of each router: BGP and BFD, on top of what FRRouting always starts. */\nexport const DAEMONS: string = [\n \"bgpd=yes\",\n \"bfdd=yes\",\n \"vtysh_enable=yes\",\n 'zebra_options=\" -A 127.0.0.1 -s 90000000\"',\n 'mgmtd_options=\" -A 127.0.0.1\"',\n 'bgpd_options=\" -A 127.0.0.1\"',\n 'bfdd_options=\" -A 127.0.0.1\"',\n 'staticd_options=\"-A 127.0.0.1\"',\n \"\",\n].join(\"\\n\");\n\n/**\n * This function gives the configuration of a router. Graceful restart is off: after a hold expiry,\n * a helper can keep the stale routes, and the move that a cell measures does not come.\n * `maximum-paths 1` keeps one path, thus a move is one change of one route.\n */\nexport const frrConf = (router: Router, fabric: Fabric): string => {\n const keepalive = valueIn(fabric.keepalive, \"s\");\n const hold = valueIn(fabric.hold, \"s\");\n const out = [\"frr defaults traditional\", `hostname ${router.name}`, \"ip forwarding\", \"!\"];\n for (const [name, address] of Object.entries(router.interfaces))\n out.push(`interface ${name}`, ` ip address ${address}`, \"!\");\n if (fabric.bfd !== null) {\n const interval = valueIn(fabric.bfd.interval, \"ms\");\n out.push(\n \"bfd\",\n \" profile fast\",\n ` receive-interval ${interval}`,\n ` transmit-interval ${interval}`,\n ` detect-multiplier ${fabric.bfd.multiplier}`,\n \" exit\",\n \"exit\",\n \"!\",\n );\n }\n out.push(\n `router bgp ${router.as}`,\n ` bgp router-id ${router.id}`,\n \" no bgp ebgp-requires-policy\",\n \" no bgp network import-check\",\n \" bgp graceful-restart-disable\",\n );\n for (const neighbor of router.neighbors) {\n out.push(\n ` neighbor ${neighbor.address} remote-as ${neighbor.as}`,\n ` neighbor ${neighbor.address} timers ${keepalive} ${hold}`,\n ` neighbor ${neighbor.address} timers connect 1`,\n ` neighbor ${neighbor.address} advertisement-interval 0`,\n );\n if (fabric.bfd !== null) out.push(` neighbor ${neighbor.address} bfd profile fast`);\n }\n out.push(\" !\", \" address-family ipv4 unicast\");\n if (router.network !== undefined) out.push(` network ${router.network}`);\n out.push(\" maximum-paths 1\");\n for (const neighbor of router.neighbors)\n if (neighbor.weight !== undefined) out.push(` neighbor ${neighbor.address} weight ${neighbor.weight}`);\n out.push(\" exit-address-family\", \"exit\", \"\");\n return out.join(\"\\n\");\n};\n\n/**\n * This function gives the topology file of containerlab. The client and the target are containers\n * of the lab, and the fabric adds a device to each. Each link has the MTU of a Docker network, thus\n * a segment is as long as on layer E1. The default of containerlab is 9500. The management network\n * belongs to the lab, and Docker chooses its subnet.\n */\nexport const topologyOf = (lab: string, dir: string, client: string, target: string): string => {\n const nodes = ROUTERS.flatMap((router) => [\n ` ${router.name}:`,\n \" kind: linux\",\n ` image: ${FRR_IMAGE}`,\n \" binds:\",\n ` - ${dir}/${router.name}.conf:/etc/frr/frr.conf`,\n ` - ${dir}/daemons:/etc/frr/daemons`,\n \" sysctls:\",\n \" net.ipv4.ip_forward: 1\",\n \" net.ipv4.conf.all.rp_filter: 0\",\n \" net.ipv4.conf.default.rp_filter: 0\",\n ]);\n const links = [...LINKS, [\"leaf1:eth3\", `${client}:${FABRIC_DEVICE}`], [\"leaf2:eth3\", `${target}:${FABRIC_DEVICE}`]];\n return [\n `name: ${lab}`,\n \"mgmt:\",\n ` network: clab-${lab}`,\n \" ipv4-subnet: auto\",\n \"topology:\",\n \" nodes:\",\n ...nodes,\n ` ${client}:`,\n \" kind: ext-container\",\n ` ${target}:`,\n \" kind: ext-container\",\n \" links:\",\n ...links.flatMap(([a, b]) => [` - endpoints: [\"${a}\", \"${b}\"]`, \" mtu: 1500\"]),\n \"\",\n ].join(\"\\n\");\n};\n\n/** A route line is one line of `ip -ts -o monitor route`, with its time on the wall clock in ms. */\nexport interface RouteLine {\n readonly wall: number;\n readonly deleted: boolean;\n readonly prefix: string;\n readonly via: string | null;\n readonly dev: string | null;\n}\n\n/** This function reads a line of `ip -ts -o monitor route`, or it gives null for another line. The clock of a container is UTC. */\nexport const routeLine = (text: string): RouteLine | null => {\n const line = text.trim();\n const found = /^\\[(\\d{4})-(\\d\\d)-(\\d\\d)T(\\d\\d):(\\d\\d):(\\d\\d)\\.(\\d{6})\\] /.exec(line);\n if (found === null) return null;\n const [stamp, year, month, day, hour, minute, second, micro] = found;\n const words = line.slice(stamp.length).split(\" \").filter((word) => word !== \"\");\n const change = words[0] === \"Deleted\" || words[0] === \"Replaced\" ? words[0] : null;\n const prefix = words[change === null ? 0 : 1];\n if (prefix === undefined) return null;\n const after = (name: string): string | null => {\n const at = words.indexOf(name);\n return at === -1 ? null : (words[at + 1] ?? null);\n };\n return {\n wall:\n Date.UTC(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute), Number(second)) +\n Number(micro) / 1_000,\n deleted: change === \"Deleted\",\n prefix,\n via: after(\"via\"),\n dev: after(\"dev\"),\n };\n};\n\n/** A clock pair is one instant on the monotonic clock in ns and on the wall clock in ms. */\nexport interface ClockPair {\n readonly mono: number;\n readonly wall: number;\n}\n\n/**\n * This function takes a time on the wall clock to the monotonic clock. The harness runs on the host\n * of the containers, thus `process.hrtime` reads the CLOCK_MONOTONIC of the injector and the\n * prober. The error of the pair is approximately 1 ms, the step of `Date.now`.\n */\nexport const monotonicAt = (wall: number, pair: ClockPair): number => pair.mono + (wall - pair.wall) * 1e6;\n\n/** This function gives the state of the BGP sessions from `show bgp neighbors json`. */\nexport const sessionsOf = (json: string): { readonly up: number; readonly established: number } => {\n const views = Object.values(JSON.parse(json) as Record<string, { bgpState?: string; connectionsEstablished?: number }>);\n return {\n up: views.filter((view) => view.bgpState === \"Established\").length,\n established: views.reduce((sum, view) => sum + (view.connectionsEstablished ?? 0), 0),\n };\n};\n\n/** These are the views of a leaf that tell if a run can start on it. */\nexport interface LeafViews {\n readonly neighbors: string;\n /** This text is the kernel's route to the far network, from `ip -o route show`. */\n readonly route: string;\n /** This text is `show bgp ipv4 unicast PREFIX json`. */\n readonly paths: string;\n /** This text is `show bfd peers json`, or null when the fabric has no BFD. */\n readonly bfd: string | null;\n}\n\n/**\n * This function tells what a leaf still lacks before a run, or it gives null. The two sessions must\n * be up and the route must be on spine1. Spine2 must hold the other path. Without these, the fault\n * of a run acts on another path, or nothing can take over.\n */\nexport const leafLacks = (views: LeafViews): string | null => {\n const { up } = sessionsOf(views.neighbors);\n if (up < 2) return `${up} of 2 BGP sessions are up`;\n if (!views.route.includes(` dev ${PREFERRED_DEVICE} `)) return `the route is not on spine1: ${views.route || \"no route\"}`;\n const paths = (JSON.parse(views.paths) as { paths?: unknown[] }).paths?.length ?? 0;\n if (paths < 2) return `BGP holds ${paths} of 2 paths`;\n if (views.bfd !== null) {\n const peers = JSON.parse(views.bfd) as Array<{ status?: string }>;\n const live = peers.filter((peer) => peer.status === \"up\").length;\n if (live < 2) return `${live} of 2 BFD peers are up`;\n }\n return null;\n};\n\n/**\n * This function gives the later move of the leaves after an instant: for each leaf, the first route\n * to its far network that leaves spine1. It gives null when a leaf has no move. The later move ends\n * the outage in the two directions.\n */\nexport const laterMove = (routes: readonly RunRoute[], after: number): number | null => {\n const firsts = LEAVES.map(\n (leaf) =>\n routes.find(\n (route) =>\n route.leaf === leaf.name && route.prefix === leaf.remote && route.t > after && !route.deleted && route.dev !== PREFERRED_DEVICE,\n )?.t,\n );\n return firsts.every((t) => t !== undefined) ? Math.max(...(firsts as number[])) : null;\n};\n\n/** A fabric lab is the open fabric of a lab. */\nexport interface FabricLab {\n /** These are the lines of the route monitors of the leaves, on the monotonic clock. */\n readonly routes: readonly RunRoute[];\n /** This method drops each packet of spine1 in one commit, and the links stay up. */\n silence(): Promise<{ t0: number; t1: number }>;\n /** This method ends a silence. */\n clear(): Promise<{ t0: number; t1: number }>;\n /** This method waits until each leaf is on spine1 with each session up. */\n ready(): Promise<void>;\n /** This method gives the count of established sessions of each leaf so far. */\n sessions(): Promise<Readonly<Record<string, number>>>;\n /** This method gives the record of the fabric for a manifest. */\n manifest(): FabricManifest;\n /** This method destroys the routers. */\n close(): Promise<void>;\n}\n\n/** These are the parts of a lab that a fabric uses. */\nexport interface FabricParts {\n readonly fabric: Fabric;\n readonly image: string;\n readonly client: StartedTestContainer;\n readonly server: StartedTestContainer;\n readonly admin: StartedTestContainer;\n readonly injector: StartedTestContainer;\n readonly opened: StartedTestContainer[];\n readonly output: (container: StartedTestContainer, argv: string[]) => Promise<string>;\n}\n\n/** This function runs a program on the host and gives its output. Its error holds the stderr of the program. */\nconst host = (program: string, args: readonly string[]): Promise<string> =>\n new Promise((resolve, reject) => {\n execFile(program, [...args], { maxBuffer: 16 * 1024 * 1024 }, (error, stdout, stderr) => {\n if (error === null) resolve(stdout);\n else reject(new Error(`${program} ${args.join(\" \")}: ${error.message}\\n${stderr}`));\n });\n });\n\nconst nameOf = (container: StartedTestContainer): string => container.getName().replace(/^\\//, \"\");\n\n/** This function gives a clock pair at this instant. */\nconst clockPair = (): ClockPair => ({ mono: Number(process.hrtime.bigint()), wall: Date.now() });\n\n/**\n * This function deploys the routers of a lab and joins the client and the target to them. It also\n * starts the sidecars: the injector of spine1 and a route monitor on each leaf. The caller stops the\n * sidecars with the other containers of the lab, and it calls `close` first.\n */\nexport const openFabric = async (parts: FabricParts): Promise<FabricLab> => {\n const { fabric, image, admin, injector, opened, output } = parts;\n const { GenericContainer } = await import(\"testcontainers\");\n const lab = `e3-${randomBytes(4).toString(\"hex\")}`;\n const dir = await mkdtemp(join(tmpdir(), \"fabric-\"));\n const file = join(dir, \"lab.clab.yml\");\n await writeFile(join(dir, \"daemons\"), DAEMONS);\n for (const router of ROUTERS) await writeFile(join(dir, `${router.name}.conf`), frrConf(router, fabric));\n await writeFile(file, topologyOf(lab, dir, nameOf(parts.client), nameOf(parts.server)));\n const close = async (): Promise<void> => {\n await host(\"sudo\", [\"containerlab\", \"destroy\", \"-t\", file, \"--cleanup\"]).catch(() => undefined);\n await rm(dir, { recursive: true, force: true }).catch(() => undefined);\n };\n const node = (name: string) => `clab-${lab}-${name}`;\n try {\n await host(\"sudo\", [\"containerlab\", \"deploy\", \"-t\", file]);\n const version = /version:\\s*(\\S+)/.exec(await host(\"containerlab\", [\"version\"]))?.[1] ?? \"unknown\";\n await output(admin, [\"ip\", \"addr\", \"add\", `${FABRIC_CLIENT}/24`, \"dev\", FABRIC_DEVICE]);\n await output(admin, [\"ip\", \"route\", \"replace\", TARGET_NET, \"via\", \"10.1.0.1\", \"dev\", FABRIC_DEVICE]);\n await output(injector, [\"ip\", \"addr\", \"add\", `${FABRIC_TARGET}/24`, \"dev\", FABRIC_DEVICE]);\n await output(injector, [\"ip\", \"route\", \"replace\", CLIENT_NET, \"via\", \"10.2.0.1\", \"dev\", FABRIC_DEVICE]);\n\n const silencer = await new GenericContainer(image)\n .withNetworkMode(`container:${node(\"spine1\")}`)\n .withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\")\n .start();\n opened.push(silencer);\n const routes: RunRoute[] = [];\n const monitors = new Map<string, StartedTestContainer>();\n for (const leaf of LEAVES) {\n const monitor = await new GenericContainer(image)\n .withNetworkMode(`container:${node(leaf.name)}`)\n .withCommand([\"ip\", \"-ts\", \"-o\", \"monitor\", \"route\"])\n .withLogConsumer((stream) => {\n let rest = \"\";\n stream.on(\"data\", (chunk: Buffer | string) => {\n const text = (rest + chunk.toString()).split(\"\\n\");\n rest = text.pop() ?? \"\";\n for (const each of text) {\n const line = routeLine(each);\n if (line === null) continue;\n const { wall, ...route } = line;\n routes.push({ ...route, leaf: leaf.name, t: monotonicAt(wall, clockPair()) });\n }\n });\n })\n .start();\n opened.push(monitor);\n monitors.set(leaf.name, monitor);\n }\n const stamp = async (action: string): Promise<{ t0: number; t1: number }> => {\n const last = (await output(silencer, [\"/opt/harness/inject\", action])).split(\"\\n\").at(-1)!;\n const { t0, t1 } = JSON.parse(last) as { t0: number; t1: number };\n return { t0, t1 };\n };\n const vtysh = (leaf: string, view: string) => host(\"docker\", [\"exec\", node(leaf), \"vtysh\", \"-c\", view]);\n return {\n routes,\n silence: () => stamp(\"silence\"),\n clear: () => stamp(\"clear-silence\"),\n async ready() {\n const deadline = Date.now() + READY_MS;\n for (;;) {\n const lacks: string[] = [];\n for (const leaf of LEAVES) {\n const prefix = leaf.remote!;\n // a daemon that still starts refuses vtysh: that is one more reason to wait\n const lacking = await (async () =>\n leafLacks({\n neighbors: await vtysh(leaf.name, \"show bgp neighbors json\"),\n route: `${await output(monitors.get(leaf.name)!, [\"ip\", \"-o\", \"route\", \"show\", prefix])} `,\n paths: await vtysh(leaf.name, `show bgp ipv4 unicast ${prefix} json`),\n bfd: fabric.bfd === null ? null : await vtysh(leaf.name, \"show bfd peers json\"),\n }))().catch((error: unknown) => String(error));\n if (lacking !== null) lacks.push(`${leaf.name}: ${lacking}`);\n }\n if (lacks.length === 0) return;\n if (Date.now() > deadline) throw new Error(`the fabric is not ready: ${lacks.join(\"; \")}`);\n await new Promise((resolve) => setTimeout(resolve, READY_POLL_MS));\n }\n },\n async sessions() {\n const out: Record<string, number> = {};\n for (const leaf of LEAVES) out[leaf.name] = sessionsOf(await vtysh(leaf.name, \"show bgp neighbors json\")).established;\n return out;\n },\n manifest: () => ({ ...fabric, image: FRR_IMAGE, containerlab: version }),\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { release } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * A layer is a rung of the laboratory (`docs/S7.md`). E1 is containers on one kernel, and E2 is a\n * cluster of containers on one kernel. A lab with `Topology.fabric` writes E3: routers in containers.\n * A lab in a guest of QEMU writes E4 (`substrateHere`). The other layers do not have a runner at this\n * time.\n */\nexport type Layer = \"E0\" | \"E1\" | \"E2\" | \"E3\" | \"E4\" | \"E5\" | \"E6\";\n\n/** A cloud is where the runner operates. GitHub can schedule a standard Linux job on Azure or on AWS. */\nexport type Cloud = \"azure\" | \"aws\" | \"unknown\";\n\n/** A host is what a process reads about its own machine. */\nexport interface Host {\n /** This text is the kernel release. */\n readonly kernel: string | null;\n /** This number is `CONFIG_HZ` from the configuration of the kernel, or null without that file. */\n readonly hz: number | null;\n /** This text is the DMI system vendor, for example `Microsoft Corporation`, or null without that file. */\n readonly vendor: string | null;\n /** This value tells if `/dev/kvm` exists. A later VM layer needs it. */\n readonly kvm: boolean;\n /** This text is `$ImageOS $ImageVersion` of a hosted runner, or null elsewhere. */\n readonly image: string | null;\n}\n\n/**\n * A substrate tells where a record comes from. The rules of comparison in `docs/S7.md` read it: no\n * statistic pools two layers, two kernels or two clouds. The digest of each image stays in the\n * manifest. A value is null in a record from before this block.\n */\nexport interface Substrate {\n readonly layer: Layer;\n readonly cloud: Cloud;\n readonly vendor: string | null;\n readonly kernel: string | null;\n readonly hz: number | null;\n readonly kvm: boolean | null;\n readonly image: string | null;\n}\n\n/** GitHub announced Linux jobs on AWS on this date. Each earlier hosted job ran on Azure. */\nexport const AWS_FROM = \"2026-10-28\";\n\n/** This function gives the cloud of a DMI vendor. A kernel name does not tell: one image can start on each cloud. */\nexport const cloudOf = (vendor: string | null): Cloud => {\n if (vendor === null) return \"unknown\";\n if (/microsoft/i.test(vendor)) return \"azure\";\n if (/amazon/i.test(vendor)) return \"aws\";\n return \"unknown\";\n};\n\nconst textOf = (path: string): string | null => {\n try {\n return readFileSync(path, \"utf8\").trim();\n } catch {\n return null;\n }\n};\n\n/** This function reads the host. `root` and `env` are for tests. */\nexport const readHost = (root = \"/\", env: Readonly<Record<string, string | undefined>> = process.env, kernel: string = release()): Host => {\n const config = textOf(join(root, \"boot\", `config-${kernel}`));\n const hz = config === null ? undefined : /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1];\n const os = env[\"ImageOS\"];\n const version = env[\"ImageVersion\"];\n return {\n kernel,\n hz: hz === undefined ? null : Number(hz),\n vendor: textOf(join(root, \"sys\", \"class\", \"dmi\", \"id\", \"sys_vendor\")),\n kvm: existsSync(join(root, \"dev\", \"kvm\")),\n image: os === undefined || version === undefined ? null : `${os} ${version}`,\n };\n};\n\n/** This function gives the substrate of a layer on a host. */\nexport const substrateOn = (layer: Layer, host: Host = readHost()): Substrate => ({ layer, cloud: cloudOf(host.vendor), ...host });\n\n/**\n * This function gives the substrate of a lab at this place. A guest cannot read its own runner: its\n * DMI vendor is QEMU, and `ImageOS` is not set. Thus the runner writes its host to `LAB_RUNNER`, and\n * the guest keeps only its own kernel and HZ. A value of that variable makes the layer E4.\n */\nexport const substrateHere = (layer: Layer, host: Host = readHost(), env: Readonly<Record<string, string | undefined>> = process.env): Substrate => {\n const runner = env[\"LAB_RUNNER\"];\n if (runner === undefined || runner === \"\") return substrateOn(layer, host);\n return substrateOn(\"E4\", { ...(JSON.parse(runner) as Host), kernel: host.kernel, hz: host.hz });\n};\n\n/** A CPU reading is two counters of `/proc/stat`, in ticks of the clock. */\nexport interface CpuTime {\n /** This count is the time that the host gave to another guest while this one had work. */\n readonly steal: number;\n /** This count is the sum of all states of each CPU. */\n readonly total: number;\n}\n\n/** This function reads the CPU time of this machine, or gives null without `/proc/stat`. `root` is for tests. */\nexport const readCpu = (root = \"/\"): CpuTime | null => {\n const line = textOf(join(root, \"proc\", \"stat\"))?.split(\"\\n\")[0];\n if (line === undefined || !line.startsWith(\"cpu \")) return null;\n // user, nice, system, idle, iowait, irq, softirq, steal: the guest counters that follow are in user\n const ticks = line.trim().split(/\\s+/).slice(1, 9).map(Number);\n const steal = ticks[7];\n if (steal === undefined || ticks.some(Number.isNaN)) return null;\n return { steal, total: ticks.reduce((sum, tick) => sum + tick, 0) };\n};\n\n/**\n * This function gives the share of the CPU time between two readings that the host took. The share\n * goes from zero to one. It is null if no tick passed. A guest sees only the host above it. On a hosted\n * runner that host is itself a guest, and this number does not show the contention of the layer below it.\n */\nexport const stealShare = (before: CpuTime, after: CpuTime): number | null => {\n const total = after.total - before.total;\n return total <= 0 ? null : (after.steal - before.steal) / total;\n};\n\n/** A part of a record that can hold a substrate: a manifest of the harness, or the fields of a kind manifest. */\nexport interface SubstrateSource {\n readonly substrate?: Substrate;\n readonly kernel?: string;\n readonly hz?: string | null;\n}\n\n/**\n * This function reads the substrate of a record, the upgrade of a record from before this block.\n * Nothing rewrites such a record. It reads as the given layer. Its cloud is Azure if the record is\n * from before `AWS_FROM`, and unknown after that date, because its runner did not record the cloud.\n */\nexport const substrateOf = (source: SubstrateSource, at: string, layer: Layer = \"E1\"): Substrate =>\n source.substrate ?? {\n layer,\n cloud: at.slice(0, AWS_FROM.length) < AWS_FROM ? \"azure\" : \"unknown\",\n vendor: null,\n kernel: source.kernel ?? null,\n hz: source.hz === undefined || source.hz === null ? null : Number(source.hz),\n kvm: null,\n image: null,\n };\n\nconst differ = <T>(a: T | null, b: T | null, unknown?: T): boolean => a !== null && b !== null && a !== unknown && b !== unknown && a !== b;\n\n/**\n * This function tells if a statistic can pool two substrates. They must have one layer, one kernel\n * and one cloud. An unknown value does not refuse a pair, because an old record cannot tell. The\n * reader of such a pair says so with `substrateKey`.\n */\nexport const comparable = (a: Substrate, b: Substrate): boolean =>\n a.layer === b.layer && !differ(a.kernel, b.kernel) && !differ<Cloud>(a.cloud, b.cloud, \"unknown\");\n\n/** This function gives the one-line name of a substrate, for a summary. */\nexport const substrateKey = (substrate: Substrate): string => `${substrate.layer} ${substrate.cloud} ${substrate.kernel ?? \"unknown\"}`;\n\n/**\n * This function gives the first two substrates that a statistic cannot pool, or undefined. It\n * examines each pair. An unknown value matches Azure and AWS, thus one comparison with the first\n * substrate can miss a pair.\n */\nexport const unpoolable = (substrates: readonly Substrate[]): readonly [Substrate, Substrate] | undefined => {\n for (const [index, a] of substrates.entries()) {\n const b = substrates.slice(index + 1).find((other) => !comparable(a, other));\n if (b !== undefined) return [a, b];\n }\n return undefined;\n};\n","import { createHash } from \"node:crypto\";\nimport type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport type * as Testcontainers from \"testcontainers\";\nimport type { Quantity } from \"@mark1russell7/quantity\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport { isHopPlace } from \"./cell.ts\";\nimport type {\n Client,\n ClientCapability,\n ClientImage,\n FabricManifest,\n FaultPlace,\n Hop,\n HopEvent,\n HopPlace,\n HostSysctl,\n ImageSource,\n KernelRecord,\n MiddleboxEvent,\n ProbeEvent,\n ProxyHop,\n RunTopology,\n Target,\n Topology,\n Toxic,\n} from \"./cell.ts\";\nimport type { FabricLab } from \"./fabric.ts\";\nimport { FABRIC_CLIENT, FABRIC_DEVICE, FABRIC_TARGET, openFabric } from \"./fabric.ts\";\nimport { SHIPPED_CLIENTS, buildRecordOf, harnessImage, harnessVersion, imageOf, routerImage, shippedSource, targetImageOf, targetSourceOf, type BuildRecord } from \"./image.ts\";\nimport type { Substrate } from \"./substrate.ts\";\nimport { substrateHere } from \"./substrate.ts\";\n\n/** This function loads Testcontainers when a lab first opens. Code that only measures and judges does not load it. */\nexport const containers = (): Promise<typeof Testcontainers> => import(\"testcontainers\");\n\n/**\n * This time is the interval of the listing of a router, when its hop does not set one. A listing\n * evicts each expired flow that it walks past, and the DESTROY event of that flow follows.\n */\nexport const PUMP: Quantity = { value: 0.1, unit: \"s\" };\n/**\n * This time is the longest listing of the conntrack table of a router that a prediction assumes.\n * A DESTROY follows an expiry within the interval of the pump and two listings. On 2026-10-15,\n * the slowest of 500 listings in an idle router took 19.4 ms, and the median took 5.5 ms. A\n * longer listing writes a `pump-slow` line, and a run with one near its detection is void.\n */\nexport const LISTING: Quantity = { value: 20, unit: \"ms\" };\n/**\n * This time is how late the pump of a router can be beyond its interval and its two listings. The\n * pump sleeps after each listing, and the sleep can end late. The watcher also reads and stamps each\n * event within a millisecond. Thus a DESTROY follows an expiry within the interval of the pump, two\n * listings and this slack. It is an assumption: in run 39116866471, two of 11 forgets came 1.6 ms\n * and 2.2 ms after the pump and two listings.\n */\nexport const PUMP_SLACK: Quantity = { value: 5, unit: \"ms\" };\n\n/** This count is how many of the last lines of a proxy hop the lab keeps. The error of a hop that does not start gives them. */\nconst TAIL_LINES = 60;\n\n/** This count is how many lines of the output of a proxy hop the lab keeps, for a write that the proxy confirms. */\nconst OUTPUT_LINES = 2000;\n\n/** This time is how long a write of a hop waits for the line that confirms it, in milliseconds. */\nconst CONFIRM_MS = 10_000;\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * A network fault is a fault that the injector applies as a filter rule. It is a black hole (both\n * directions, or one), or a reset on the next segment. It can also be an ICMP unreachable for each\n * segment, or a drop of each segment that is longer than a length.\n */\nexport type NetworkFault = \"blackhole\" | \"rst\" | \"reject\" | \"mtu\";\n\n/** These are the options of a network fault: the direction of a black hole, the code of a reject, the length of an MTU drop. */\nexport interface FaultOptions {\n /** This direction is relative to the namespace of the rule: `in` drops what comes from the peer, `out` what goes to it. */\n readonly direction?: \"in\" | \"out\";\n readonly code?: \"host\" | \"net\" | \"port\" | \"admin\";\n /** This length is the longest segment in bytes that an MTU drop lets through. */\n readonly above?: number;\n /** These are the addresses that the rule faces, in place of the peer of its place. */\n readonly peers?: readonly string[];\n}\n\n/** This function gives the arguments of the injector for the options of a fault. */\nexport const optionArgs = (options: FaultOptions): string[] => [\n ...(options.direction === undefined ? [] : [\"--direction\", options.direction]),\n ...(options.code === undefined ? [] : [\"--code\", options.code]),\n ...(options.above === undefined ? [] : [\"--above\", String(options.above)]),\n];\n\n/** These are the actions of the injector that lift each network fault. */\nexport const LIFT: Readonly<Record<NetworkFault, string>> = {\n blackhole: \"clear\",\n rst: \"clear-rst\",\n reject: \"clear-reject\",\n mtu: \"clear-mtu\",\n};\n\n/**\n * A fault side is the namespace that gets the rules of a fault: the namespace of the peer of the\n * observer. For the client, it is the namespace of the target (the injector). For the server, it\n * is the namespace of the client (its privileged admin). Rules in the namespace of the observer\n * make its sends fail locally, with EPERM, and the network does not lose them. Thus its\n * retransmissions do not go out. The retransmission tracepoint of the kernel then records none,\n * because it fires only for a retransmission that went out.\n */\nexport type FaultSide = \"target\" | \"client\";\n\n/** A hop of a manifest is one hop of a topology, as the lab started it. */\nexport interface ManifestHop {\n readonly name: string;\n readonly kind: \"router\" | \"proxy\";\n readonly image: string;\n readonly id: string;\n /** These are the settings of the hop: the form and the idle timeout of a router, the files and settings of a proxy. */\n readonly settings: Readonly<Record<string, string>>;\n /** These are the sysctls of the namespace of the hop, as read back after the harness set them. */\n readonly sysctls: Readonly<Record<string, string>>;\n}\n\n/** This record is one sysctl of the host for one environment, as the harness read it. */\nexport interface HostSetting {\n readonly name: string;\n readonly before: string;\n readonly set: string;\n /** This value is the read after the restore. It is null until the restore. */\n readonly restored: string | null;\n}\n\n/** A manifest is what a lab records about its machine, its images and its settings. */\nexport interface Manifest {\n readonly kernel: string;\n /** This text is the architecture of the machine, as uname -m gives it: x86_64. */\n readonly architecture: string;\n readonly hz: string | null;\n /**\n * This text tells where the HZ came from: the configuration of the kernel, or a measurement. A\n * host without /proc/config.gz (a hosted runner) gets a measurement of jiffies against the clock.\n */\n readonly hzFrom?: \"config\" | \"measured\";\n readonly boot_id: string;\n readonly docker: string;\n /** This block tells the layer, the cloud and the kernel of the record. A record from before it reads through `substrateOf`. */\n readonly substrate?: Substrate;\n /** This record is the fabric of a cell with `Topology.fabric`. */\n readonly fabric?: FabricManifest;\n /** This record is the target, and its settings as it read them back. */\n readonly target: {\n readonly image: string;\n /** This source is the image of the subject that the target operates (`Target.subject`), with its stock base. */\n readonly subject?: ImageSource;\n readonly base?: string;\n readonly id: string;\n readonly settings: Readonly<Record<string, string>>;\n /** These are the sysctls of its namespace, as read back after the harness set them. */\n readonly sysctls: Readonly<Record<string, string>>;\n /** These are the files that went into the target, by their path, each with the sha256 of its content. */\n readonly files?: Readonly<Record<string, string>>;\n /** This line is the first line of a target that writes them: a server that tells its settings as it reads them. */\n readonly first?: ProbeEvent;\n /** This record tells what the image of a target holds when the harness builds it: the image of a subject (`buildRecordOf`). */\n readonly build?: BuildRecord;\n };\n /**\n * This record is the harness: its image, the id of that image and its Alpine packages. It also\n * has the version of the package of the harness, and the build of its image. The record of a\n * cell gives the commit of the code that operated.\n */\n readonly harness: { readonly image: string; readonly id: string; readonly packages: string[]; readonly version?: string; readonly build?: BuildRecord };\n /**\n * This record is the client of each run: the TCP client of the harness, a driver, or an image that\n * the cell gives. `source` is the source of its image, when it is not a stock image by its name.\n */\n readonly client: {\n readonly kind: Client | \"image\";\n readonly image: string;\n readonly capabilities?: readonly ClientCapability[];\n readonly source?: ImageSource;\n readonly build?: BuildRecord;\n };\n /** These are the namespaces that the prober watched, by inode. */\n readonly netns: {\n readonly client: number;\n readonly target: number;\n readonly hops?: Readonly<Record<string, number>>;\n };\n /** These are the sysctls of the client namespace, as read back after the harness set them. */\n readonly sysctls: Readonly<Record<string, string>>;\n /** These are the sysctls of the host that the cell set: each value before, as set, and as restored. */\n readonly host?: readonly HostSetting[];\n /** These are the hops of a topology, in sequence from the client. */\n readonly hops?: readonly ManifestHop[];\n /** These are the parts of a group, with their settings as each part read them back. */\n readonly group?: {\n readonly members: ReadonlyArray<{ readonly name: string; readonly ip: string; readonly id: string; readonly settings: Readonly<Record<string, string>> }>;\n readonly sentinels: ReadonlyArray<{ readonly name: string; readonly ip: string; readonly id: string; readonly settings: Readonly<Record<string, string>> }>;\n readonly observer: { readonly image: string };\n };\n}\n\n/** These are the JSON lines of a program, as they arrive. */\nexport interface Lines<T extends { readonly ev: string }> {\n readonly seen: T[];\n /** These are the other lines that it wrote, for example an error. They explain a program that stopped its output. */\n readonly other: string[];\n consume: (stream: NodeJS.ReadableStream) => void;\n /** This method gives the first line of one of these kinds, or it rejects after `within` ms. */\n until(kinds: readonly string[], within: number, who: string): Promise<T>;\n}\n\n/** This function collects the JSON lines of a program. It gives each line to `also` too, when the caller gives it. */\nexport const lines = <T extends { readonly ev: string }>(also?: (line: T) => void): Lines<T> => {\n const seen: T[] = [];\n const other: string[] = [];\n const waiting: Array<{ kinds: readonly string[]; resolve: (line: T) => void }> = [];\n let partial = \"\";\n const take = (text: string) => {\n if (!text.startsWith(\"{\")) {\n if (text.length > 0) other.push(text);\n return;\n }\n let line: T;\n try {\n line = JSON.parse(text) as T;\n } catch {\n // not whole JSON, for example an object that the program printed: a throw here stops the lines of the stream\n other.push(text);\n return;\n }\n seen.push(line);\n also?.(line);\n for (const wait of waiting.splice(0)) {\n if (wait.kinds.includes(line.ev)) wait.resolve(line);\n else waiting.push(wait);\n }\n };\n return {\n seen,\n other,\n consume: (stream) =>\n stream.on(\"data\", (chunk: Buffer | string) => {\n partial += chunk.toString();\n const split = partial.split(\"\\n\");\n partial = split.pop() ?? \"\";\n for (const text of split) take(text.trim());\n }),\n until(kinds, within, who) {\n const found = seen.find((line) => kinds.includes(line.ev));\n if (found !== undefined) return Promise.resolve(found);\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n // its last lines tell why: a fail line of a client that could not connect, or a text that is not a line\n const failed = seen.filter((line) => line.ev === \"fail\" || line.ev === \"error\").slice(0, 3);\n const last = [...new Set([...failed, ...seen.slice(-3)])].map((line) => JSON.stringify(line));\n const said = [...(last.length === 0 ? [] : [`its last lines: ${last.join(\" | \")}`]), ...(other.length === 0 ? [] : [`it wrote: ${other.slice(-3).join(\" | \")}`])];\n reject(new Error(`no ${kinds.join(\" or \")} from the ${who} in ${within} ms${said.length === 0 ? \"\" : `; ${said.join(\"; \")}`}`));\n }, within);\n waiting.push({\n kinds,\n resolve: (line) => {\n clearTimeout(timer);\n resolve(line);\n },\n });\n });\n },\n };\n};\n\n/** A probe is the client container of one run. */\nexport interface Probe {\n /** This method gives the first event of one of these kinds, or it rejects after `within` ms. */\n until(kinds: readonly string[], within: number): Promise<ProbeEvent>;\n /** This method lets an in-flight probe send its request. */\n go(): Promise<void>;\n /** This method freezes the client with the cgroup freezer: its process stops, and its kernel continues to answer. */\n freeze(): Promise<void>;\n thaw(): Promise<void>;\n /** This method stops the process of the client with SIGKILL. Its kernel then closes its socket with a FIN, or a reset. */\n kill(): Promise<void>;\n readonly events: readonly ProbeEvent[];\n stop(): Promise<void>;\n}\n\n/** An agent is a container that a lab starts in the namespaces of the target, for example a Node process that signals the server. */\nexport interface Agent {\n /** These are the JSON lines that it wrote, as they arrive. */\n readonly lines: Lines<{ readonly ev: string }>;\n /** This method starts a command in the agent, and gives its standard output. */\n exec(argv: readonly string[]): Promise<string>;\n stop(): Promise<void>;\n}\n\n/** A sibling is a server that a lab starts on the network of the target, for example a standby. */\nexport interface Sibling {\n readonly ip: string;\n readonly netns: number;\n /** This method starts a command in the sibling, and gives its standard output. */\n exec(argv: readonly string[]): Promise<string>;\n}\n\n/** A lab is one environment: the target, the client, the hops of a topology, the injectors and the prober. */\nexport interface Lab {\n /** This address is the address of the target on its own network. */\n readonly serverIp: string;\n /** This address is the address that the client connects to: the target, or the first proxy of a topology. */\n readonly targetIp: string;\n /** This port is the port that the client connects to. */\n readonly targetPort: number;\n readonly clientIp: string;\n readonly netns: {\n readonly client: number;\n readonly target: number;\n readonly hops?: Readonly<Record<string, number>>;\n };\n /** This record is where each socket of a topology is, or null for a direct pair. */\n readonly topology: RunTopology | null;\n /** These are the lines of the routers of a topology, in sequence, each with the name of its hop. A direct pair has none. */\n readonly middlebox: readonly MiddleboxEvent[];\n /** These are the lines of a target that writes them (`Target.lines`), in sequence. Another target has none. */\n readonly server: readonly ProbeEvent[];\n /** This method adds a toxic to the Toxiproxy hop of a topology, or removes it with null. The stamps of the injector bracket it. */\n toxic(toxic: Toxic | null): Promise<{ t0: number; t1: number }>;\n /** This method makes the target close the connection of each client, with the command of the target. */\n serverClose(): Promise<void>;\n /**\n * This method starts an agent in the network namespace of the target, and in its process\n * namespace with `pid`. Its command keeps it up, for example `sleep infinity`.\n */\n agent(image: string, command: readonly string[], options?: { readonly pid?: boolean }): Promise<Agent>;\n /** This method starts a sibling, and waits for a line of its log. */\n sibling(image: string, command: readonly string[], ready: string): Promise<Sibling>;\n /** This method starts a command in the target, and gives its standard output. */\n exec(argv: readonly string[]): Promise<string>;\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method sets the settings of the target in it before a client connects, and reads them back. */\n configure(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method sets the sysctls of the target namespace through a privileged sidecar there, and reads them back. */\n targetSysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method runs each command in the namespace of the client and in the namespace of the target. */\n namespaceSetup(commands: readonly (readonly string[])[]): Promise<void>;\n /** This method sets sysctls of the host through a privileged sidecar on the network of the host, and reads them back. */\n hostSysctl(settings: readonly HostSysctl[]): Promise<void>;\n /** This method puts back each value that `hostSysctl` changed, once, and gives the record of each. Closing the lab also does it. */\n restoreHost(): Promise<readonly HostSetting[]>;\n /**\n * This method applies a fault between the client and the target, by default from the namespace\n * of the target. The fault is a black hole, or a reset that answers the next segment of the\n * client. At a proxy of a topology, the rules face the peer of the proxy on one side. The stamps\n * of the injector bracket it.\n */\n fault(\n kind: NetworkFault,\n at?: FaultPlace,\n options?: FaultOptions,\n ): Promise<{ t0: number; t1: number }>;\n /** This method removes a fault. */\n lift(kind: NetworkFault, at?: FaultPlace, options?: FaultOptions): Promise<void>;\n /**\n * This method puts tc netem on the egress of a namespace, for example \"delay 20ms\" or \"loss 5%\",\n * or removes it with null. At a hop, it is the egress of the device of the hop toward one side.\n * The stamps of the injector bracket it.\n */\n netem(spec: string | null, at?: FaultPlace): Promise<{ t0: number; t1: number }>;\n /**\n * This method sets the TSO, GSO and GRO of a namespace. With them off, netem and a length match\n * act on segments, not on GSO super-packets of up to 64 KB. At a hop, it sets the two devices of the hop.\n */\n offload(on: boolean, at?: FaultPlace): Promise<void>;\n /** This method stops the server process in the target with SIGKILL, with the command of the target. */\n kill(): Promise<void>;\n /**\n * This method resolves the neighbors of the path in the two directions, with a ping from each\n * namespace. Without it, the first connection of an environment waits for ARP. Under a netem\n * delay, that wait is one more delayed round, and its round trip and RTO are longer.\n */\n warm(): Promise<void>;\n /** This method runs commands in the target before a client connects, each as argv. */\n setup(commands: ReadonlyArray<readonly string[]>): Promise<void>;\n /**\n * This method stops a black hole at an instant on the monotonic clock of the VM. The injector\n * waits for that instant in the VM, thus the length of a stall does not include the latency of\n * a docker exec. Stamps bracket it, as for a fault.\n */\n heal(at: FaultPlace, when: number): Promise<{ t0: number; t1: number }>;\n /**\n * This method removes what the two kernels learned from their earlier connections. These are\n * the TCP metrics that each kernel keeps for a peer address when a connection closes. These metrics set the\n * first round trip of the next connection, and thus its RTO. A run with these metrics is not\n * independent of the run before it.\n */\n forget(): Promise<void>;\n /** This part is the routed fabric of a lab with `Topology.fabric`. */\n readonly fabric?: FabricLab;\n /** This method freezes the target with the cgroup freezer: its process stops, and its kernel continues to answer. */\n freeze(): Promise<void>;\n thaw(): Promise<void>;\n /**\n * This method sends a signal to the server process of the target (`Target.program`), at once or\n * at an instant of the VM. A sidecar in the network and process namespaces of the target sends\n * it, and the injector stamps it. The lab starts that sidecar at the first signal.\n */\n signal(signal: \"STOP\" | \"CONT\" | \"KILL\", at?: number): Promise<{ t0: number; t1: number }>;\n /**\n * This method applies an event at a proxy hop (`HopEvent`), or its undo. A signal goes from a\n * sidecar in the network and process namespaces of the hop. The lab starts that sidecar at the\n * first signal of the hop. A query goes from the injector of the hop to its console on 127.0.0.1. The\n * injector stamps each one. An event with no undo gives null for its undo. A signal can wait for an\n * instant on CLOCK_MONOTONIC (`at`), as the thaw at the end of a hold does.\n */\n event(event: HopEvent, undo?: boolean, at?: number): Promise<{ t0: number; t1: number } | null>;\n /** This method starts the client with `args`. Each file is in its container before it starts. */\n probe(args: readonly string[], files?: ReadonlyArray<{ readonly content: string; readonly target: string }>): Promise<Probe>;\n /**\n * This method waits for the next clock line of the prober, which gives the count of lost\n * records. It gives null when no clock line comes in 5 s, because then nothing tells the count.\n */\n settle(): Promise<number | null>;\n manifest(\n sysctls: Readonly<Record<string, string>>,\n settings?: Readonly<Record<string, string>>,\n targetSysctls?: Readonly<Record<string, string>>,\n ): Promise<Manifest>;\n close(): Promise<void>;\n}\n\n/** This function makes a container share the process namespace of another container, for example `container:<id>`. */\nexport const withPid = <T extends Testcontainers.GenericContainer>(container: T, mode: string): T => {\n (container as unknown as { hostConfig: { PidMode?: string } }).hostConfig.PidMode = mode;\n return container;\n};\n\n/** This container class can share the process namespace of another container. */\nconst shared = (Base: typeof Testcontainers.GenericContainer) =>\n class extends Base {\n withPidMode(mode: string): this {\n (this as unknown as { hostConfig: { PidMode?: string } }).hostConfig.PidMode = mode;\n return this;\n }\n };\n\n/**\n * This function gives the content of a file of a proxy. Each {{next}} becomes the address and the\n * port of the next hop. Each {{next.host}} and {{next.port}} becomes one of the two.\n */\nexport const templated = (content: string, next: string): string => {\n const at = next.lastIndexOf(\":\");\n return content\n .replaceAll(\"{{next.host}}\", next.slice(0, at))\n .replaceAll(\"{{next.port}}\", next.slice(at + 1))\n .replaceAll(\"{{next}}\", next);\n};\n\n/** This function gives the JSON body of a toxic for the API of Toxiproxy. Each toxic of a cell has the name `fault`. */\nexport const toxicBody = (toxic: Toxic): string =>\n JSON.stringify({\n name: \"fault\",\n type: toxic.type,\n stream: toxic.stream,\n toxicity: 1,\n attributes: toxic.attributes,\n });\n\n/**\n * This function gives the routes of a chain: for each router, the networks after it, which the\n * element before it reaches through it. Element 0 is the client, and element k is hop k - 1. Network\n * j is the network between element j and element j + 1.\n */\nexport const routesOf = (\n hops: readonly Pick<Hop, \"kind\">[],\n): Array<{ readonly from: number; readonly via: number; readonly networks: readonly number[] }> =>\n hops.flatMap((hop, at) =>\n hop.kind === \"router\"\n ? [\n {\n from: at,\n via: at + 1,\n networks: Array.from({ length: hops.length - at }, (_, k) => at + 1 + k),\n },\n ]\n : [],\n );\n\n/**\n * This function gives the endpoint that an element connects to: the first element after it that\n * is not a router. Element 0 is the client, element k is hop k - 1, and the last element is the target.\n */\nexport const endpointAfter = (hops: readonly Pick<Hop, \"kind\">[], element: number): number => {\n let at = element + 1;\n while (at <= hops.length && hops[at - 1]!.kind === \"router\") at += 1;\n return at;\n};\n\n// each container here is a holder, a probe or the prober: nothing drains, thus the stop is immediate\nexport const STOP = { timeout: 0 };\n\n/** These are the values of CONFIG_HZ that Linux offers. */\nconst RATES: readonly number[] = [100, 250, 300, 1000];\n\n/**\n * This function gives HZ from two readings of /proc/timer_list, one second apart: its `now at`\n * time in ns and its jiffies. It gives the nearest rate that Linux offers, or null when the\n * measurement is more than 5 % from each of them.\n */\nexport const hzOf = (first: { now: number; jiffies: number }, second: { now: number; jiffies: number }): string | null => {\n const seconds = (second.now - first.now) / 1e9;\n if (!(seconds > 0)) return null;\n const rate = (second.jiffies - first.jiffies) / seconds;\n const nearest = RATES.reduce((best, each) => (Math.abs(each - rate) < Math.abs(best - rate) ? each : best));\n return Math.abs(nearest - rate) / nearest <= 0.05 ? String(nearest) : null;\n};\n\n/** This function measures HZ in a privileged container: jiffies against the time of the kernel, one second apart. */\nconst measuredHz = async (container: StartedTestContainer): Promise<string | null> => {\n const read = \"awk '/^now at/ {now=$3} /^jiffies:/ {print now, $2; exit}' /proc/timer_list\";\n const text = await output(container, [\"sh\", \"-c\", `${read}; sleep 1; ${read}`]).catch(() => \"\");\n const values = text.split(/\\s+/).filter((each) => each !== \"\").map(Number);\n if (values.length !== 4 || values.some((each) => !Number.isFinite(each))) return null;\n return hzOf({ now: values[0]!, jiffies: values[1]! }, { now: values[2]!, jiffies: values[3]! });\n};\n\nexport const output = async (container: StartedTestContainer, argv: string[]): Promise<string> => {\n const result = await container.exec(argv);\n if (result.exitCode !== 0)\n throw new Error(`${argv.join(\" \")} exited ${result.exitCode}: ${result.output.trim()}`);\n return result.stdout.trim();\n};\n\n/** This function gives the inode of the network namespace of a container: net:[4026532583]. */\nexport const netnsOf = async (container: StartedTestContainer): Promise<number> => {\n const link = await output(container, [\"readlink\", \"/proc/self/ns/net\"]);\n const inode = /^net:\\[(\\d+)\\]$/.exec(link)?.[1];\n if (inode === undefined) throw new Error(`not a network namespace: ${link}`);\n return Number(inode);\n};\n\n/** This function gives the build record of a source as a part of a manifest: `{ build }`, or nothing for an image that the harness pulls. */\nexport const buildOf = (source: Parameters<typeof buildRecordOf>[0]): { readonly build?: BuildRecord } => {\n const build = buildRecordOf(source);\n return build === undefined ? {} : { build };\n};\n\n/** This function gives the version of the harness and the build of its image, as a part of the harness record of a manifest. */\nexport const harnessRecord = (): { readonly version: string; readonly build?: BuildRecord } => ({\n version: harnessVersion(),\n ...buildOf(shippedSource(\"harness\")),\n});\n\n/**\n * This function gives the record of the client of a run that the harness ships, for a manifest:\n * its kind, its image, and its build.\n */\nexport const shippedClientRecord = (kind: Client, image: string): Manifest[\"client\"] => ({ kind, image, ...buildOf(SHIPPED_CLIENTS[kind].image) });\n\n/**\n * This function gives the image and the command of the client of each run, its kind for the\n * manifest, and the source of its image. A client by its name is a client that the harness ships\n * (`SHIPPED_CLIENTS`). A client image gives its own image and command.\n */\nexport const clientOf = async (\n kind: Client | ClientImage,\n): Promise<{\n clientImage: string;\n command: readonly string[];\n clientKind: Client | \"image\";\n capabilities?: readonly ClientCapability[];\n source?: ImageSource;\n}> => {\n const client = typeof kind === \"string\" ? (Object.hasOwn(SHIPPED_CLIENTS, kind) ? SHIPPED_CLIENTS[kind] : undefined) : kind;\n if (client === undefined) throw new Error(`the harness ships no client ${String(kind)}`);\n return {\n clientImage: await imageOf(client.image),\n command: client.command,\n clientKind: typeof kind === \"string\" ? kind : \"image\",\n ...(client.capabilities === undefined || client.capabilities.length === 0 ? {} : { capabilities: client.capabilities }),\n ...(typeof client.image === \"string\" ? {} : { source: client.image }),\n };\n};\n\n/** These are the containers of one hop of a lab, and the addresses that its rules and the measurement read. */\ninterface HopIn {\n readonly hop: Hop;\n /** This container is the hop itself: the router, or the stock proxy. */\n readonly box: StartedTestContainer;\n /** This sidecar shares the namespace of the hop: the injector of its faults and its toxics. */\n readonly injector: StartedTestContainer;\n /** This record is the address of the hop on the network of each of its sides. */\n readonly ip: { readonly client: string; readonly target: string };\n /** These are the peers of the hop: an address on the side of the client, and an address with its port toward the target. */\n readonly peer: { readonly client: string; readonly target: string };\n /** These are the devices of the hop toward each side, as its routes give them. The rules of a router and netem at a hop face one. */\n readonly devices: { readonly client: string; readonly target: string };\n readonly netns: number;\n sysctls: Record<string, string>;\n}\n\n/** This function gives the device of a route from its line in `ip -o route get`: \"10.0.0.2 dev eth0 src …\". */\nexport const deviceOf = (route: string): string => {\n const device = /\\bdev (\\S+)/.exec(route)?.[1];\n if (device === undefined) throw new Error(`no device in the route: ${route}`);\n return device;\n};\n\n/**\n * This function opens one environment:\n * - a chain of new networks, and the stock target on the last one. A direct pair has one network.\n * - a client that holds its own network namespace, with a privileged sidecar in it for its\n * sysctls and its routes. Docker Desktop keeps /proc/sys read-only in a container that operates\n * without privileges.\n * - each hop of the topology, on the network of each of its sides. A hop is a router, or a stock\n * proxy with an injector sidecar in its namespace.\n * - an injector sidecar in the namespace of the target.\n * - the prober, a privileged container that loads the kernel program and watches the namespace of\n * the client, of the target and of each hop.\n *\n * The client of each run is its own container in the namespace of the client. It is the TCP\n * client of the harness, a driver from its own image (ioredis on Node), or an image that the\n * caller gives. Each prints the same lines.\n *\n * The client reaches the networks after a router through that router, by a route that its\n * privileged sidecar adds. A router translates the address of the side of the client, thus the\n * target and each later hop see the router as the peer.\n */\nexport const openLab = async (\n target: Target,\n kind: Client | ClientImage = \"tcp\",\n topology?: Topology,\n): Promise<Lab> => {\n const image = await harnessImage();\n const { clientImage, command, clientKind, capabilities, source } = await clientOf(kind);\n const hops = topology?.hops ?? [];\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n const networks: StartedNetwork[] = [];\n // the lines of a target that writes them, on the clock of the VM\n const serverLines = lines<ProbeEvent>();\n // the values of the host that this lab changed, which each path out of the lab puts back\n let restoreHost: () => Promise<readonly HostSetting[]> = () => Promise.resolve([]);\n let fabric: FabricLab | undefined;\n const close = async () => {\n // a value of the host outlives the lab: the failure of the restore is the failure of the close, after the containers stop\n const restored = await restoreHost().then(\n () => null,\n (error: unknown) => error,\n );\n await fabric?.close();\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n for (const network of networks.reverse()) await network.stop().catch(() => undefined);\n if (restored !== null) throw restored;\n };\n /** This function gives the address of a container on a network, as Docker has it at this time. A container can join a network after its start. */\n const ipOn = async (container: StartedTestContainer, network: StartedNetwork): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network.getName()}`);\n return ip;\n };\n const join = (container: StartedTestContainer, network: StartedNetwork) =>\n runtime.container.connectToNetwork(\n runtime.container.getById(container.getId()),\n runtime.network.getById(network.getId()),\n [],\n );\n const subnetOf = async (network: StartedNetwork): Promise<string> => {\n const info = await runtime.network.getById(network.getId()).inspect();\n const subnet = (info as { IPAM?: { Config?: Array<{ Subnet?: string }> } }).IPAM?.Config?.[0]?.Subnet;\n if (subnet === undefined) throw new Error(`${network.getName()} has no subnet`);\n return subnet;\n };\n try {\n // network j joins element j and element j + 1: 0 is the client, i + 1 is hop i, the last is the target\n for (let at = 0; at <= hops.length; at += 1) networks.push(await new Network().start());\n const last = networks[hops.length]!;\n // a stock image, or an image of the harness that holds the script of the server\n const targetImage = await targetImageOf(target);\n let stock = new GenericContainer(targetImage)\n .withNetwork(last)\n .withWaitStrategy(Wait.forLogMessage(target.ready));\n // the files of the target go in before it starts, for example the script of a server on a stock image\n if (target.files !== undefined)\n stock = stock.withCopyContentToContainer(\n Object.entries(target.files).map(([path, content]) => ({ content, target: path })),\n );\n if (target.lines === true) stock = stock.withLogConsumer(serverLines.consume);\n // a holder command keeps the container up when a fin fault kills the server process\n const server = await (\n target.command === undefined ? stock : stock.withCommand([...target.command])\n ).start();\n opened.push(server);\n const serverIp = await ipOn(server, last);\n\n // the hops, from the target to the client: each proxy gets the address of the endpoint after it\n const middlebox: MiddleboxEvent[] = [];\n // the last lines of the output of each proxy, and their count, for a write that the proxy confirms\n const hopOutput = new Map<string, { lines: string[]; total: number }>();\n const inChain: HopIn[] = [];\n const endpointOf = (element: number): string => {\n const at = endpointAfter(hops, element);\n if (at === hops.length + 1) return `${serverIp}:${target.port}`;\n const proxy = inChain[at - 1]!;\n return `${proxy.ip.client}:${(proxy.hop as ProxyHop).port}`;\n };\n for (let at = hops.length - 1; at >= 0; at -= 1) {\n const hop = hops[at]!;\n const [clientSide, targetSide] = [networks[at]!, networks[at + 1]!];\n if (hop.kind === \"router\") {\n const seen = lines<MiddleboxEvent>((line) => middlebox.push({ ...line, hop: hop.name }));\n // the router is privileged: it sets the sysctls of its own namespace, conntrack's among them\n const box = await new GenericContainer(await routerImage())\n .withNetwork(clientSide)\n .withPrivilegedMode()\n .withEnvironment({\n FORM: hop.form,\n IDLE: String(valueIn(hop.idle, \"s\")),\n PUMP: String(valueIn(hop.pump ?? PUMP, \"s\")),\n SLOW: String(valueIn(LISTING, \"s\")),\n })\n .withLogConsumer(seen.consume)\n .start();\n opened.push(box);\n // the router waits for the network of the side of the target, its eth1\n await join(box, targetSide);\n const ready = await seen.until([\"mbx-ready\"], 30_000, `router ${hop.name}`);\n await seen.until(hop.form === \"reset-both\" ? [\"resetter\"] : [\"ct-watch\"], 30_000, `router ${hop.name}`);\n // the injector of a fault at the router: FORWARD rules and netem in its namespace\n const injector = await new GenericContainer(image)\n .withNetworkMode(`container:${box.getId()}`)\n .withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\")\n .start();\n opened.push(injector);\n inChain[at] = {\n hop,\n box,\n injector,\n ip: { client: await ipOn(box, clientSide), target: await ipOn(box, targetSide) },\n peer: { client: \"\", target: endpointOf(at + 1) },\n devices: { client: \"\", target: \"\" },\n netns: await netnsOf(box),\n sysctls: { \"net.netfilter.nf_conntrack_tcp_timeout_established\": String(ready[\"idle\"]) },\n };\n continue;\n }\n const next = endpointOf(at + 1);\n let proxy = new GenericContainer(await imageOf(hop.image)).withNetwork(targetSide);\n if (hop.command !== undefined) proxy = proxy.withCommand([...hop.command]);\n if (hop.environment !== undefined) proxy = proxy.withEnvironment({ ...hop.environment });\n if (hop.files !== undefined)\n proxy = proxy.withCopyContentToContainer(\n Object.entries(hop.files).map(([path, content]) => ({ content: templated(content, next), target: path })),\n );\n if (hop.ready !== undefined) proxy = proxy.withWaitStrategy(Wait.forLogMessage(hop.ready));\n // the last lines of the output of the hop: a hop that does not start tells why\n const tail: string[] = [];\n const output = { lines: [] as string[], total: 0 };\n hopOutput.set(hop.name, output);\n proxy = proxy.withLogConsumer((stream) => {\n let rest = \"\";\n stream.on(\"data\", (chunk: Buffer | string) => {\n const lines = (rest + chunk.toString()).split(\"\\n\");\n rest = lines.pop() ?? \"\";\n for (const line of lines) {\n tail.push(line);\n if (tail.length > TAIL_LINES) tail.shift();\n output.lines.push(line);\n output.total += 1;\n if (output.lines.length > OUTPUT_LINES) output.lines.shift();\n }\n });\n });\n const box = await proxy.start().catch((error: unknown) => {\n throw new Error(`the hop ${hop.name} did not start: ${error instanceof Error ? error.message : String(error)}. Its last lines:\\n${tail.join(\"\\n\")}`);\n });\n opened.push(box);\n await join(box, clientSide);\n const injector = await new GenericContainer(image)\n .withNetworkMode(`container:${box.getId()}`)\n .withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\")\n .start();\n opened.push(injector);\n inChain[at] = {\n hop,\n box,\n injector,\n ip: { client: await ipOn(box, clientSide), target: await ipOn(box, targetSide) },\n peer: { client: \"\", target: next },\n devices: { client: \"\", target: \"\" },\n netns: await netnsOf(injector),\n sysctls: {},\n };\n }\n\n const client = await new GenericContainer(image).withNetwork(networks[0]!).start();\n opened.push(client);\n const admin = await new GenericContainer(image)\n .withNetworkMode(`container:${client.getId()}`)\n .withPrivilegedMode()\n .start();\n opened.push(admin);\n const injector = await new GenericContainer(image)\n .withNetworkMode(`container:${server.getId()}`)\n .withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\")\n .start();\n opened.push(injector);\n // a fabric joins the client and the target by a device of its own: Docker keeps eth0\n if (topology?.fabric !== undefined)\n fabric = await openFabric({\n fabric: topology.fabric,\n image,\n client,\n server,\n admin,\n injector,\n opened,\n output,\n });\n const device = fabric === undefined ? \"eth0\" : FABRIC_DEVICE;\n const clientIp = fabric === undefined ? await ipOn(client, networks[0]!) : FABRIC_CLIENT;\n // the peer of each hop on the side of the client: the element before it, on the network between them\n for (let at = 0; at < inChain.length; at += 1) {\n const before = at === 0 ? clientIp : inChain[at - 1]!.ip.target;\n inChain[at] = { ...inChain[at]!, peer: { ...inChain[at]!.peer, client: before } };\n }\n\n // a privileged sidecar for each proxy that needs one, for its sysctls and its routes\n const admins = new Map<number, StartedTestContainer>();\n const adminOf = async (element: number): Promise<StartedTestContainer> => {\n if (element === 0) return admin;\n const hop = inChain[element - 1]!;\n if (hop.hop.kind === \"router\") return hop.box;\n let found = admins.get(element);\n if (found === undefined) {\n found = await new GenericContainer(image)\n .withNetworkMode(`container:${hop.box.getId()}`)\n .withPrivilegedMode()\n .start();\n opened.push(found);\n admins.set(element, found);\n }\n return found;\n };\n for (const route of routesOf(hops)) {\n const where = await adminOf(route.from);\n const via = inChain[route.via - 1]!.ip.client;\n for (const network of route.networks)\n await output(where, [\"ip\", \"route\", \"replace\", await subnetOf(networks[network]!), \"via\", via]);\n }\n for (let at = 0; at < inChain.length; at += 1) {\n const hop = inChain[at]!;\n // the device toward each side, as the routes of the hop give it\n const toward = async (address: string) =>\n deviceOf(await output(hop.injector, [\"ip\", \"-o\", \"route\", \"get\", address.split(\":\")[0]!]));\n inChain[at] = { ...hop, devices: { client: await toward(hop.peer.client), target: await toward(hop.peer.target) } };\n if (hop.hop.sysctls === undefined) continue;\n // a router is privileged and sets its own sysctls. A proxy has a privileged sidecar for them\n const where = await adminOf(at + 1);\n const settings = Object.entries(hop.hop.sysctls).map(([key, value]) => `${key}=${value}`);\n await output(where, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n for (const key of Object.keys(hop.hop.sysctls)) hop.sysctls[key] = await output(where, [\"sysctl\", \"-n\", key]);\n }\n\n const netns = {\n client: await netnsOf(admin),\n target: await netnsOf(injector),\n ...(inChain.length === 0\n ? {}\n : { hops: Object.fromEntries(inChain.map((hop) => [hop.hop.name, hop.netns])) }),\n };\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\n \"/opt/harness/prober\",\n String(netns.client),\n String(netns.target),\n ...inChain.map((hop) => String(hop.netns)),\n ])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n const first = endpointAfter(hops, 0);\n const targetIp = fabric !== undefined ? FABRIC_TARGET : first === hops.length + 1 ? serverIp : inChain[first - 1]!.ip.client;\n const targetPort = first === hops.length + 1 ? target.port : (inChain[first - 1]!.hop as ProxyHop).port;\n const targetPeer = inChain.length === 0 ? clientIp : inChain.at(-1)!.ip.target;\n const placed: RunTopology | null =\n inChain.length === 0\n ? null\n : {\n targetPeer,\n hops: Object.fromEntries(\n inChain.map((hop) => [hop.hop.name, { netns: hop.netns, client: hop.peer.client, target: hop.peer.target }]),\n ),\n };\n const paused = runtime.container.getById(server.getId());\n let targetAdmin: StartedTestContainer | undefined;\n let signaller: StartedTestContainer | undefined;\n // the sidecars that signal the program of a hop, by the name of the hop\n const hopSignallers = new Map<string, StartedTestContainer>();\n const hopNamed = (name: string): HopIn => {\n const found = inChain.find((hop) => hop.hop.name === name);\n if (found === undefined) throw new Error(`the topology has no hop ${name}`);\n return found;\n };\n /**\n * This function gives the namespace and the peer of the rules of a fault at a place, and the\n * other arguments of the injector. At a proxy, the rules are INPUT and OUTPUT rules, which act\n * on its sockets. A router forwards past INPUT and OUTPUT, thus its rules are FORWARD rules on\n * its device toward the side (`--via`).\n */\n const hopPlace = (at: FaultPlace): HopPlace => {\n if (!isHopPlace(at)) throw new Error(`a lab of a topology has no part ${JSON.stringify(at)}: a group cell opens a group lab`);\n return at;\n };\n const placeOf = (place: FaultPlace): [StartedTestContainer, string, string[]] => {\n if (place === \"client\") return [admin, targetIp, []];\n if (place === \"target\") return [injector, targetPeer, []];\n const at = hopPlace(place);\n const hop = hopNamed(at.hop);\n const peer = at.toward === \"client\" ? hop.peer.client : hop.peer.target.split(\":\")[0]!;\n const via = hop.hop.kind === \"router\" ? [\"--via\", hop.devices[at.toward]] : [];\n return [hop.injector, peer, via];\n };\n /** This function gives the namespace and the device of netem at a place: an end, or the device of a hop toward a side. */\n const deviceAt = (place: FaultPlace): [StartedTestContainer, string] => {\n if (place === \"client\") return [admin, device];\n if (place === \"target\") return [injector, device];\n const at = hopPlace(place);\n const hop = hopNamed(at.hop);\n return [hop.injector, hop.devices[at.toward]];\n };\n const toxiproxy = (): HopIn & { hop: ProxyHop & { api: { port: number; proxy: string } } } => {\n const found = inChain.find((hop) => hop.hop.kind === \"proxy\" && hop.hop.api !== undefined);\n if (found === undefined) throw new Error(\"the topology has no hop with the API of Toxiproxy\");\n return found as HopIn & { hop: ProxyHop & { api: { port: number; proxy: string } } };\n };\n const stamped = async (where: StartedTestContainer, argv: string[]) => {\n const stamp = JSON.parse((await output(where, argv)).split(\"\\n\").at(-1)!) as { t0: number; t1: number };\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const proxies = inChain.filter((hop) => hop.hop.kind === \"proxy\");\n let hostAdmin: StartedTestContainer | undefined;\n const hostChanges: HostSetting[] = [];\n let hostDone: readonly HostSetting[] | undefined;\n restoreHost = async () => {\n if (hostDone !== undefined) return hostDone;\n const restored: HostSetting[] = [];\n for (const change of [...hostChanges].reverse()) {\n await output(hostAdmin!, [\"sysctl\", \"-q\", \"-w\", `${change.name}=${change.before}`]);\n const read = await output(hostAdmin!, [\"sysctl\", \"-n\", change.name]);\n if (read !== change.before) throw new Error(`${change.name} reads ${read} after the restore, not ${change.before}`);\n restored.unshift({ ...change, restored: read });\n }\n hostDone = restored;\n return restored;\n };\n\n return {\n serverIp,\n targetIp,\n targetPort,\n clientIp,\n netns,\n topology: placed,\n middlebox,\n server: serverLines.seen,\n kernel: records.seen,\n ...(fabric === undefined ? {} : { fabric }),\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values))\n read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n async targetSysctl(values) {\n const read: Record<string, string> = {};\n if (Object.keys(values).length === 0) return read;\n // privileged, and only when a cell asks for it: otherwise the namespace of the target stays as it is\n targetAdmin ??= await new GenericContainer(image)\n .withNetworkMode(`container:${server.getId()}`)\n .withPrivilegedMode()\n .start();\n opened.push(targetAdmin);\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n await output(targetAdmin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n for (const key of Object.keys(values))\n read[key] = await output(targetAdmin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n async namespaceSetup(commands) {\n for (const command of commands) {\n await output(admin, [...command]);\n await output(injector, [...command]);\n }\n },\n async hostSysctl(settings) {\n if (settings.length === 0) return;\n // privileged and on the network of the host, and only when a cell asks for it: a value of the host applies to each container\n if (hostAdmin === undefined) {\n hostAdmin = await new GenericContainer(image).withNetworkMode(\"host\").withPrivilegedMode().start();\n opened.push(hostAdmin);\n }\n for (const { name, value, guard } of settings) {\n if (guard !== undefined) {\n const reads = Number(await output(hostAdmin, [\"sysctl\", \"-n\", guard.name]));\n if (!(reads <= guard.atMost)) throw new Error(`${guard.name} of the host reads ${reads}, above ${guard.atMost}`);\n }\n const before = await output(hostAdmin, [\"sysctl\", \"-n\", name]);\n // recorded first: a write that fails half way still has its restore\n hostChanges.push({ name, before, set: value, restored: null });\n await output(hostAdmin, [\"sysctl\", \"-q\", \"-w\", `${name}=${value}`]);\n const set = await output(hostAdmin, [\"sysctl\", \"-n\", name]);\n if (set !== value) throw new Error(`${name} of the host reads ${set} after the write, not ${value}`);\n }\n },\n restoreHost: () => restoreHost(),\n async configure(values) {\n const read: Record<string, string> = {};\n if (Object.keys(values).length === 0) return read;\n const how = target.settings;\n if (how === undefined) throw new Error(`${target.image} names no way to set its settings`);\n for (const [name, value] of Object.entries(values)) {\n await output(server, [...how.set, name, value]);\n read[name] = (await output(server, [...how.get, name])).split(\"\\n\").at(-1) ?? \"\";\n }\n return read;\n },\n async fault(kind, at = \"target\", options = {}) {\n const [where, peer, via] = placeOf(at);\n return stamped(where, [\"/opt/harness/inject\", kind, options.peers?.join(\",\") ?? peer, ...optionArgs(options), ...via]);\n },\n async lift(kind, at = \"target\", options = {}) {\n const [where, peer, via] = placeOf(at);\n await output(where, [\"/opt/harness/inject\", LIFT[kind], options.peers?.join(\",\") ?? peer, ...optionArgs(options), ...via]);\n },\n async netem(spec, at = \"target\") {\n const [where, device] = deviceAt(at);\n const args =\n spec === null\n ? [\"/opt/harness/inject\", \"clear-netem\", device]\n : [\"/opt/harness/inject\", \"netem\", device, ...spec.split(/\\s+/)];\n return stamped(where, args);\n },\n async offload(on, at = \"target\") {\n // at a hop, the two devices: a router merges what it receives (GRO) and forwards it whole\n const devices = isHopPlace(at) ? Object.values(hopNamed(at.hop).devices) : [deviceAt(at)[1]];\n const [where] = deviceAt(at);\n for (const device of devices)\n await output(where, [\"/opt/harness/inject\", \"offload\", device, on ? \"on\" : \"off\"]);\n },\n async toxic(toxic) {\n const hop = toxiproxy();\n const api = `127.0.0.1:${hop.hop.api.port}`;\n const path = `/proxies/${hop.hop.api.proxy}/toxics`;\n return stamped(\n hop.injector,\n toxic === null\n ? [\"/opt/harness/inject\", \"http\", \"DELETE\", api, `${path}/fault`]\n : [\"/opt/harness/inject\", \"http\", \"POST\", api, path, toxicBody(toxic)],\n );\n },\n async serverClose() {\n if (target.close === undefined) throw new Error(`${target.image} names no way to close its clients`);\n await output(server, [...target.close]);\n },\n async exec(argv) {\n return output(server, [...argv]);\n },\n async sibling(siblingImage, argv, ready) {\n const started = await new GenericContainer(siblingImage)\n .withNetwork(last)\n .withWaitStrategy(Wait.forLogMessage(ready))\n .withCommand([...argv])\n .start();\n opened.push(started);\n return {\n ip: await ipOn(started, last),\n netns: await netnsOf(started),\n exec: (command) => output(started, [...command]),\n };\n },\n async agent(agentImage, argv, options = {}) {\n const Shared = shared(GenericContainer);\n const seen = lines<{ readonly ev: string }>();\n let started = new Shared(agentImage)\n .withNetworkMode(`container:${server.getId()}`)\n .withCommand([...argv])\n .withLogConsumer(seen.consume);\n if (options.pid === true) started = started.withPidMode(`container:${server.getId()}`);\n const container = await started.start();\n opened.push(container);\n return {\n lines: seen,\n exec: (args) => output(container, [...args]),\n stop: () =>\n container\n .stop(STOP)\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n async kill() {\n if (target.kill === undefined) throw new Error(`${target.image} names no way to kill its server`);\n await output(server, [...target.kill]);\n },\n async warm() {\n await output(admin, [\"ping\", \"-c\", \"2\", \"-W\", \"2\", targetIp]);\n await output(injector, [\"ping\", \"-c\", \"2\", \"-W\", \"2\", targetPeer]);\n for (const hop of proxies)\n await output(hop.injector, [\"ping\", \"-c\", \"2\", \"-W\", \"2\", hop.peer.target.split(\":\")[0]!]);\n },\n async setup(commands) {\n for (const argv of commands) await output(server, [...argv]);\n },\n async heal(at, when) {\n const [where, peer, via] = placeOf(at);\n return stamped(where, [\"/opt/harness/inject\", \"clear\", peer, \"--at\", String(Math.round(when)), ...via]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n await output(injector, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n for (const hop of proxies) await output(hop.injector, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n freeze: () => paused.pause().then(() => undefined),\n thaw: () => paused.unpause().then(() => undefined),\n async signal(signal, at) {\n if (target.program === undefined) throw new Error(`${target.image} names no server process to signal`);\n // only when a cell asks for it: otherwise no sidecar shares the process namespace of the target\n signaller ??= await withPid(\n new GenericContainer(image).withNetworkMode(`container:${server.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${server.getId()}`,\n ).start();\n if (!opened.includes(signaller)) opened.push(signaller);\n const when = at === undefined ? [] : [\"--at\", String(Math.round(at))];\n return stamped(signaller, [\"/opt/harness/inject\", \"signal\", target.program, signal, ...when]);\n },\n async event(event, undo = false, at) {\n const hop = hopNamed(event.hop);\n if (hop.hop.kind !== \"proxy\") throw new Error(`the hop ${event.hop} is a router: an event goes to a proxy`);\n const program = hop.hop.program;\n // only when a cell asks for it: otherwise no sidecar shares the process namespace of the hop.\n // SYS_PTRACE lets a write reach the root of the program through /proc/PID/root\n const sidecarOf = async (): Promise<StartedTestContainer> => {\n let sidecar = hopSignallers.get(event.hop);\n if (sidecar === undefined) {\n sidecar = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${hop.box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\", \"SYS_PTRACE\"),\n `container:${hop.box.getId()}`,\n ).start();\n hopSignallers.set(event.hop, sidecar);\n opened.push(sidecar);\n }\n return sidecar;\n };\n if (\"signal\" in event) {\n if (undo) return null;\n if (program === undefined) throw new Error(`the hop ${event.hop} names no program to signal`);\n const when = at === undefined ? [] : [\"--at\", String(Math.round(at))];\n return stamped(await sidecarOf(), [\"/opt/harness/inject\", \"signal\", program, event.signal, ...when]);\n }\n if (\"write\" in event) {\n const content = undo ? event.write.undo : event.write.content;\n if (content === undefined) return null;\n if (program === undefined) throw new Error(`the hop ${event.hop} names no program whose root a write reaches`);\n const output = hopOutput.get(event.hop);\n const before = output?.total ?? 0;\n const stamp = await stamped(await sidecarOf(), [\"/opt/harness/inject\", \"write\", program, event.write.path, content]);\n const confirm = event.write.confirm;\n if (confirm !== undefined) {\n // the hop confirms the change by a new line of its output, for example the log line of its reload\n const started = Date.now();\n const confirmed = (): boolean => {\n if (output === undefined) return false;\n const fresh = Math.min(output.total - before, output.lines.length);\n return output.lines.slice(output.lines.length - fresh).some((line) => line.includes(confirm));\n };\n while (!confirmed()) {\n if (Date.now() - started > CONFIRM_MS)\n throw new Error(`the hop ${event.hop} did not confirm the write of ${event.write.path}: no line \"${confirm}\" in ${CONFIRM_MS / 1000} s`);\n await sleep(50);\n }\n }\n return stamp;\n }\n const query = undo ? event.console.undo : event.console.query;\n if (query === undefined) return null;\n const { port, user, database } = event.console;\n return stamped(hop.injector, [\"/opt/harness/inject\", \"query\", `127.0.0.1:${port}`, user, database, query]);\n },\n async probe(args, files = []) {\n const events = lines<ProbeEvent>();\n const prober = new GenericContainer(clientImage)\n .withNetworkMode(`container:${client.getId()}`)\n .withCommand([...command, ...args])\n .withCopyContentToContainer(files.map((file) => ({ ...file })))\n .withLogConsumer(events.consume);\n const container = await (capabilities === undefined ? prober : prober.withAddedCapabilities(...capabilities)).start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n go: () => output(container, [\"touch\", \"/tmp/go\"]).then(() => undefined),\n freeze: () =>\n runtime.container\n .getById(container.getId())\n .pause()\n .then(() => undefined),\n thaw: () =>\n runtime.container\n .getById(container.getId())\n .unpause()\n .then(() => undefined),\n kill: () =>\n runtime.container\n .getById(container.getId())\n .kill({ signal: \"SIGKILL\" })\n .then(() => undefined),\n // a killed client has no container to stop\n stop: () =>\n container\n .stop(STOP)\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n async settle() {\n // the prober drains its ring each 20 ms, and it writes a clock line each second\n const after = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const started = Date.now();\n const look = () => {\n const line = records.seen.slice(after).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - started > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls, settings = {}, targetSysctls = {}) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) =>\n runtime.container.inspect(runtime.container.getById(container.getId()));\n const hopsOf = async (): Promise<ManifestHop[]> => {\n const out: ManifestHop[] = [];\n for (const hop of inChain) {\n const box = hop.hop;\n out.push({\n name: box.name,\n kind: box.kind,\n image: box.kind === \"router\" ? await routerImage() : await imageOf(box.image),\n id: (await inspect(hop.box)).Image,\n settings:\n box.kind === \"router\"\n ? {\n form: box.form,\n idle: String(valueIn(box.idle, \"s\")),\n pump: String(valueIn(box.pump ?? PUMP, \"s\")),\n slow: String(valueIn(LISTING, \"s\")),\n packages: (await output(hop.box, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort().join(\" \"),\n }\n : { ...box.settings, ...box.files },\n sysctls: hop.sysctls,\n });\n }\n return out;\n };\n return {\n kernel: await output(client, [\"uname\", \"-r\"]),\n architecture: await output(client, [\"uname\", \"-m\"]),\n ...(await (async () => {\n const configured = /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1];\n if (configured !== undefined) return { hz: configured, hzFrom: \"config\" as const };\n const measured = await measuredHz(admin);\n return measured === null ? { hz: null } : { hz: measured, hzFrom: \"measured\" as const };\n })()),\n boot_id: await output(client, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n substrate: substrateHere(fabric === undefined ? \"E1\" : \"E3\"),\n ...(fabric === undefined ? {} : { fabric: fabric.manifest() }),\n target: {\n image: targetImage,\n ...(target.subject === undefined ? {} : { subject: target.subject, base: target.image }),\n id: (await inspect(server)).Image,\n settings,\n sysctls: targetSysctls,\n ...(target.files === undefined\n ? {}\n : {\n files: Object.fromEntries(\n Object.entries(target.files).map(([path, content]) => [path, createHash(\"sha256\").update(content).digest(\"hex\")]),\n ),\n }),\n ...(serverLines.seen[0] === undefined ? {} : { first: serverLines.seen[0] }),\n ...buildOf(targetSourceOf(target)),\n },\n harness: {\n image,\n id: (await inspect(client)).Image,\n packages: (await output(client, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n ...harnessRecord(),\n },\n client: {\n kind: clientKind,\n image: clientImage,\n ...(capabilities === undefined ? {} : { capabilities }),\n ...(source === undefined ? {} : { source, ...buildOf(source) }),\n },\n netns,\n sysctls,\n ...(inChain.length === 0 ? {} : { hops: await hopsOf() }),\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, KernelRecord, Pair, Run } from \"./cell.ts\";\nimport { targetImageOf } from \"./image.ts\";\nimport type { Lab, Probe, Sibling } from \"./lab.ts\";\n\n/**\n * This module is the second server of a pair (`Cell.pair`). The lab of the cell has the primary, the\n * topology in front of it, the injector and the prober. This module adds one standby on the network\n * of the primary, and it does one run:\n *\n * 1. The client writes a stream of sequence numbers through the topology.\n * 2. The fault cuts the primary from the standby, or from each peer. The cut stays to the end.\n * 3. At the end of the hold, the injector stops each process of the primary with SIGKILL.\n * 4. The harness promotes the standby, and reads what it holds.\n * 5. The harness starts the old primary, and reads what its crash recovery gives.\n *\n * The standby has no way to the WAL of the old primary, because the primary stops under the cut. A\n * promotion cannot be undone, thus each run has its own environment (`Cell.fresh`).\n */\n\n/** This table holds one row for each write of the client. */\nconst TABLE = \"writes\";\n/** This time bounds each wait of the setup of the pair, in ms. */\nconst SETUP_MS = 60_000;\n/** This count is the acknowledged writes before the fault: the stream is steady. */\nconst STEADY = 20;\n/** This time is the wait after the stop of the primary, in ms: each writer sends its last write in it. */\nconst LAST_WRITE_MS = 2_000;\n/** This time bounds the wait for the last line of the client, in ms. */\nconst STOP_MS = 5_000;\n\n/** This text is the line of the log of a standby that serves reads (src/backend/postmaster/postmaster.c:3740). */\nexport const STANDBY_READY: string = \"database system is ready to accept read-only connections\";\n/** This text is the write of the client, with its sequence number. */\nexport const INSERT: string = `INSERT INTO ${TABLE} VALUES ($n)`;\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** This function gives the argv of one statement in psql, on the server in the same container. */\nexport const psql = (statement: string): string[] => [\"psql\", \"-h\", \"127.0.0.1\", \"-U\", \"postgres\", \"-At\", \"-c\", statement];\n\n/** This function gives the command of a standby: a base backup of the primary, then the server in recovery. */\nexport const standbyCommand = (primary: string): string[] => [\n \"sh\",\n \"-c\",\n `chown postgres:postgres \"$PGDATA\"; chmod 0700 \"$PGDATA\"; until gosu postgres pg_basebackup -h ${primary} -U postgres -D \"$PGDATA\" -X stream -c fast -R; do gosu postgres sh -c 'rm -rf \"$PGDATA\"/*'; sleep 0.5; done; exec gosu postgres postgres`,\n];\n\n/** This command starts the old primary again, after the stop of each of its processes. Its crash recovery runs before the wait ends. */\nexport const RESTART: readonly string[] = [\"sh\", \"-c\", 'exec gosu postgres pg_ctl -D \"$PGDATA\" -l /tmp/restart.log -w -t 60 start'];\n\n/** This function reads the output of a query for sequence numbers into a sorted list. */\nexport const numbersOf = (text: string): number[] =>\n text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\")\n .map(Number)\n .sort((a, b) => a - b);\n\n/** This function gives the arguments of the client of a run. */\nexport const pairArgs = (cell: Cell, lab: Pick<Lab, \"targetIp\" | \"targetPort\">): string[] => {\n const pair = cell.pair!;\n const hold = cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\");\n return [\n lab.targetIp,\n String(lab.targetPort),\n \"--mode\",\n \"stream\",\n \"--interval-ms\",\n String(valueIn(pair.interval, \"ms\")),\n \"--writers\",\n String(pair.writers),\n \"--query\",\n INSERT,\n \"--max-s\",\n String(Math.ceil(hold) + 60),\n ...(cell.driverOptions === undefined ? [] : [\"--options\", JSON.stringify(cell.driverOptions)]),\n ];\n};\n\n/** This function gives the peers of the cut of a pair: the standby, or the standby and the peer of the primary in the topology. */\nexport const peersOf = (pair: Pair, standby: string, lab: Pick<Lab, \"topology\" | \"clientIp\">): string[] =>\n pair.cuts === \"standby\" ? [standby] : [standby, lab.topology?.targetPeer ?? lab.clientIp];\n\n/** This function gives the instants of the cancels of a hold, in ns from the fault: equal parts of the hold. */\nexport const cancelsOf = (pair: Pair, holdNs: number): number[] => {\n const count = pair.cancels ?? 0;\n return Array.from({ length: count }, (_, at) => ((at + 1) * holdNs) / (count + 1));\n};\n\n/** This function asks until the primary reports the standby in a state of replication. */\nconst untilStreaming = async (lab: Lab, state: string): Promise<void> => {\n const started = Date.now();\n for (;;) {\n const seen = await lab.exec(psql(\"SELECT sync_state FROM pg_stat_replication WHERE state = 'streaming'\"));\n if (seen === state) return;\n if (Date.now() - started > SETUP_MS) throw new Error(`the standby did not stream as ${state} in ${SETUP_MS} ms: it reports \"${seen}\"`);\n await sleep(100);\n }\n};\n\n/**\n * This function opens the pair of an environment. The table comes first and the standby next: the\n * base backup has it. A synchronous standby is named last, thus no setup step waits for it.\n */\nexport const openStandby = async (lab: Lab, cell: Cell): Promise<Sibling> => {\n const pair = cell.pair!;\n await lab.exec([\"sh\", \"-c\", 'echo \"host replication all all trust\" >> \"$PGDATA/pg_hba.conf\"']);\n await lab.exec(psql(\"SELECT pg_reload_conf()\"));\n await lab.exec(psql(`CREATE TABLE ${TABLE} (n integer PRIMARY KEY)`));\n const standby = await lab.sibling(await targetImageOf(cell.target), standbyCommand(lab.serverIp), STANDBY_READY);\n await untilStreaming(lab, \"async\");\n if (pair.synchronous) {\n await lab.exec(psql(\"ALTER SYSTEM SET synchronous_standby_names = '*'\"));\n await lab.exec(psql(\"SELECT pg_reload_conf()\"));\n await untilStreaming(lab, \"sync\");\n }\n return standby;\n};\n\n/** This function waits for a count of acknowledged writes. */\nconst untilSteady = async (probe: Probe): Promise<void> => {\n const started = Date.now();\n while (probe.events.filter((event) => event.ev === \"ack\").length < STEADY) {\n if (Date.now() - started > SETUP_MS) throw new Error(`the client did not write ${STEADY} times in ${SETUP_MS} ms`);\n await sleep(10);\n }\n};\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1)\n if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/**\n * This function does one run of a pair. A dry run writes and stops, with no fault: the warm-up of the\n * environment. It removes its rows, thus the numbers of the run start on an empty table.\n */\nexport const pairOnce = async (lab: Lab, standby: Sibling, cell: Cell, environment: number, index: number, dry = false): Promise<Run> => {\n const pair = cell.pair!;\n await lab.forget();\n const from = lab.kernel.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const probe = await lab.probe(pairArgs(cell, lab));\n const holdNs = cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\") * 1e9;\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n try {\n await probe.until([\"ready\"], 15_000);\n await untilSteady(probe);\n if (!dry) {\n fault = await lab.fault(\"blackhole\", \"target\", { peers: peersOf(pair, standby.ip, lab) });\n const started = Date.now();\n for (const at of cancelsOf(pair, holdNs)) {\n await sleep(Math.max(0, at / 1e6 - (Date.now() - started)));\n await lab.exec(psql(\"SELECT count(pg_cancel_backend(pid)) FROM pg_stat_activity WHERE wait_event = 'SyncRep'\"));\n }\n heal = await lab.signal(\"KILL\", fault.t0 + holdNs);\n await sleep(LAST_WRITE_MS);\n // the injector lists its processes before its wait: a backend that started in the wait is here\n if (cell.target.kill !== undefined) await lab.exec(cell.target.kill);\n }\n // a client whose writers each failed is gone already, and its done line tells it\n await probe.go().catch(() => undefined);\n await probe.until([\"done\"], STOP_MS);\n } finally {\n await probe.stop();\n }\n if (dry) await lab.exec(psql(`TRUNCATE ${TABLE}`));\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const read = `SELECT n FROM ${TABLE} ORDER BY n`;\n let holds: readonly number[] | null = null;\n let oldHolds: readonly number[] = [];\n if (!dry) {\n await standby.exec(psql(\"SELECT pg_promote(true, 60)\"));\n holds = numbersOf(await standby.exec(psql(read)));\n await lab.exec([...RESTART]);\n oldHolds = numbersOf(await lab.exec(psql(read)));\n }\n return {\n environment,\n index,\n events: [...probe.events],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost,\n ...(lab.topology === null ? {} : { topology: lab.topology, middlebox: [] }),\n group: {\n members: { primary: { ip: lab.serverIp, netns: lab.netns.target }, standby: { ip: standby.ip, netns: standby.netns } },\n sentinels: {},\n primary: \"primary\",\n at: \"primary\",\n timeline: [],\n after: dry ? \"primary\" : \"standby\",\n holds,\n oldHolds,\n },\n };\n};\n","import type { BuildRecord } from \"./image.ts\";\nimport { PINNED } from \"./image.ts\";\nimport type { Manifest } from \"./lab.ts\";\n\n/**\n * This module tells if a manifest pins each program that a run operated. A record that does not pin\n * them is not a record. A later run cannot operate the same programs, thus nobody can reproduce\n * its numbers (SYS-101). Each image is pulled by its digest, or the harness builds it. A build\n * records its bases by digest, the sha256 of each lockfile, and the versions of the packages that\n * its manifests name. The commit of the code that operated is a field of the record of a cell, and\n * `commitProblems` examines it.\n */\n\n/** This pattern matches the id of an image: `sha256:` and 64 hex digits. */\nconst IMAGE_ID = /^sha256:[0-9a-f]{64}$/;\n/** This pattern matches the tag of a build of the harness: its name, then 12 hex digits of the sha256 of its context. */\nconst BUILD_TAG = /^[a-z0-9][a-z0-9._\\-/]*:[0-9a-f]{12}$/;\n/** This pattern matches a commit of git: 40 hex digits. */\nconst COMMIT = /^[0-9a-f]{40}$/;\n\n/** This function gives each problem of the record of a build. A problem is a base that no digest pins, or a tag of another form. */\nconst buildProblems = (what: string, build: BuildRecord): string[] => [\n ...(BUILD_TAG.test(build.tag) ? [] : [`${what}: the build has the tag ${build.tag}, which is not a tag of a build`]),\n ...build.bases.filter((base) => !PINNED.test(base)).map((base) => `${what}: the base ${base} is not pinned by digest`),\n];\n\n/**\n * This function gives each problem of an image of a manifest. A pulled image needs a digest. An\n * image that the harness builds needs its build record when the manifest can hold one (`build`).\n * Otherwise, it needs the tag of a build and the id of its image.\n */\nconst pinProblems = (what: string, image: string, id: string | undefined, build: BuildRecord | undefined, needsBuild: boolean): string[] => {\n if (PINNED.test(image)) return [];\n if (build !== undefined) return buildProblems(what, build);\n if (BUILD_TAG.test(image) && !needsBuild && id !== undefined && IMAGE_ID.test(id)) return [];\n return BUILD_TAG.test(image) && needsBuild\n ? [`${what}: the image ${image} is a build with no build record`]\n : [`${what}: the image ${image} has no digest`];\n};\n\n/**\n * This function gives each problem of a manifest that stops it from pinning the programs of its\n * run. An empty list means that the manifest pins each program.\n * - the target: an image by its digest, or the build of a subject with its build record and its base\n * by digest.\n * - the harness: the version of its package, and the build record of its image.\n * - the client: an image by its digest, or a build with its build record.\n * - each hop: an image by its digest, or the tag of a build and the id of its image.\n */\nexport const manifestProblems = (manifest: Manifest): string[] => [\n ...pinProblems(\"the target\", manifest.target.image, manifest.target.id, manifest.target.build, manifest.target.subject !== undefined),\n ...(manifest.target.subject !== undefined && (manifest.target.base === undefined || !PINNED.test(manifest.target.base))\n ? [`the target: the base ${manifest.target.base ?? \"(none)\"} of its subject is not pinned by digest`]\n : []),\n ...(manifest.harness.version === undefined ? [\"the harness: the manifest has no version of the harness\"] : []),\n ...(manifest.harness.build === undefined ? [\"the harness: the image has no build record\"] : buildProblems(\"the harness\", manifest.harness.build)),\n ...pinProblems(\"the client\", manifest.client.image, undefined, manifest.client.build, true),\n ...(manifest.hops ?? []).flatMap((hop) => pinProblems(`the hop ${hop.name}`, hop.image, hop.id, undefined, false)),\n];\n\n/** This function gives the problem of the commit of a record: no commit, or a text that is not a commit of git. */\nexport const commitProblems = (commit: string | undefined): string[] =>\n commit === undefined\n ? [\"the record has no commit of the code that operated\"]\n : COMMIT.test(commit)\n ? []\n : [`the record has the commit ${commit}, which is not 40 hex digits`];\n\n/** The code of a record is the commit of the checkout that operated, and if its tracked files had changes. */\nexport interface RecordCode {\n readonly commit: string;\n readonly dirty: boolean;\n}\n\n/** These are the parts of a record that tell if it pins the programs of its runs. */\nexport interface Pinnable {\n readonly code?: RecordCode | undefined;\n readonly manifests: readonly Manifest[];\n /** A local debug run marks its record so. No page reads such a record. */\n readonly debug?: boolean | undefined;\n}\n\n/** This problem is the problem of a checkout with changes: its commit does not hold the code that operated. */\nexport const DIRTY = \"the checkout has changes to tracked files that no commit holds\";\n\n/** This problem is the problem of a record of a local debug run. */\nexport const DEBUG = \"the record is of a local debug run, and no page reads it\";\n\n/**\n * This function gives each problem that stops a record from pinning the programs of its runs. A\n * record with a problem is not a record (SYS-101). The writer of the cells refuses it, and the read\n * of a schedule refuses it. A commit with changes to tracked files is not a pin.\n */\nexport const recordProblems = (record: Pinnable): string[] => [\n ...new Set([\n ...commitProblems(record.code?.commit),\n ...(record.code?.dirty === true ? [DIRTY] : []),\n ...record.manifests.flatMap((manifest) => manifestProblems(manifest)),\n ...(record.debug === true ? [DEBUG] : []),\n ]),\n];\n","import type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type {\n Cell,\n Group,\n GroupPlace,\n GroupRole,\n KernelRecord,\n ProbeEvent,\n Run,\n RunPart,\n SentinelEvent,\n} from \"./cell.ts\";\nimport type { Manifest } from \"./lab.ts\";\nimport { harnessImage, nodeClientImage } from \"./image.ts\";\nimport { STOP, containers, harnessRecord, lines, netnsOf, output, shippedClientRecord, withPid } from \"./lab.ts\";\n\n/**\n * This module is the lab of a replicated group: a primary and its replicas, and the Sentinels\n * that decide which member is the primary. It opens one environment for a group cell, and it does\n * the runs of the cell in it. Each member and each Sentinel is a container from the stock image of\n * the group, in its own network namespace. An injector sidecar shares its network and process\n * namespaces. The client of each run is ioredis in Sentinel mode. An observer subscribes to the\n * events of each Sentinel, and the prober watches the namespace of the client.\n */\n\n/** A stamp is the time of the injector around one commit, on CLOCK_MONOTONIC in nanoseconds. */\nexport interface Stamp {\n readonly t0: number;\n readonly t1: number;\n}\n\n/** A group network fault is a black hole between a part and its peers, or a reset of each segment from them. */\nexport type GroupNetworkFault = \"blackhole\" | \"rst\";\n\n/** A group client is the client container of one run of a group cell. */\nexport interface GroupClient {\n readonly events: readonly ProbeEvent[];\n until(kinds: readonly string[], within: number): Promise<ProbeEvent>;\n stop(): Promise<void>;\n}\n\n/** A group lab is one environment of a group cell. */\nexport interface GroupLab {\n readonly group: Group;\n readonly clientIp: string;\n readonly observerIp: string;\n readonly members: Readonly<Record<string, RunPart>>;\n readonly sentinels: Readonly<Record<string, RunPart>>;\n /** These are the namespaces that the prober watches: the client, and the Sentinels for a calibration. */\n readonly netns: { readonly client: number; readonly watched: readonly number[] };\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** These are all the lines of the observer of the Sentinels, in sequence. */\n readonly timeline: readonly SentinelEvent[];\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method waits until the group is whole and calm, and gives the name of its primary. */\n converge(within?: number): Promise<string>;\n /** This method removes each key from the group, and waits until each replica has the removal. */\n flush(primary: string): Promise<void>;\n /** This method makes each Sentinel forget the state of the group (`SENTINEL RESET`): an aborted failover then holds off no later failover. */\n reset(): Promise<void>;\n /** This method gives the sequence numbers that the group holds, from its primary. */\n holds(primary: string): Promise<number[]>;\n /** This method gives the part that has a role in the group, when `primary` is the primary. */\n partOf(role: GroupRole, primary: string): string;\n /** This method starts the client of a run, with the arguments of `client-sentinel.mjs`. */\n client(args: readonly string[]): Promise<GroupClient>;\n /** This method applies a network fault between a part and some of its peers, at once or at an instant of the VM. */\n fault(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes a network fault, at once or at an instant of the VM. */\n lift(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method sends a signal to the server process of a part, at once or at an instant of the VM. */\n signal(part: string, signal: \"KILL\" | \"STOP\" | \"CONT\", at?: number): Promise<Stamp>;\n /** This method starts the server of a member again, after a fin. */\n restart(member: string): Promise<void>;\n /** This method asks the first Sentinel for a failover of the group. */\n failover(coordinated: boolean): Promise<Stamp>;\n /** This method removes the TCP metrics of the client namespace: each run starts from a kernel that keeps nothing. */\n forget(): Promise<void>;\n /** This method waits for the next clock line of the prober, which gives the count of lost records. */\n settle(): Promise<number | null>;\n manifest(sysctls: Readonly<Record<string, string>>): Promise<Manifest>;\n close(): Promise<void>;\n}\n\n/** This function gives the configuration file of a member: its port, its settings, and the primary that a replica follows. */\nexport const memberConfig = (group: Group, primary: string | null): string =>\n [\n `port ${group.port}`,\n ...Object.entries(group.memberSettings).map(([key, value]) => `${key} ${value}`),\n ...(primary === null ? [] : [`replicaof ${primary} ${group.port}`]),\n \"\",\n ].join(\"\\n\");\n\n/** This function gives the configuration file of a Sentinel: its port, the group that it monitors, and the settings of the group. */\nexport const sentinelConfig = (group: Group, primary: string): string =>\n [\n `port ${group.sentinelPort}`,\n `sentinel monitor ${group.name} ${primary} ${group.port} ${group.quorum}`,\n ...Object.entries(group.sentinelSettings).map(([key, value]) => `sentinel ${key} ${group.name} ${value}`),\n \"\",\n ].join(\"\\n\");\n\n/**\n * This function gives the peers that a fault on a part cuts it from, by their addresses. `all` is\n * each other part and the client, `group` is the other parts, and `clients` and `to-clients` are\n * the client. `one` and `one-way` are the first other member. The observer is not a peer, thus the timeline of the\n * group stays whole.\n */\nexport const peersOf = (\n parts: { readonly members: Readonly<Record<string, RunPart>>; readonly sentinels: Readonly<Record<string, RunPart>> },\n client: string,\n part: string,\n cuts: NonNullable<GroupPlace[\"cuts\"]>,\n): string[] => {\n const others = [...Object.entries(parts.members), ...Object.entries(parts.sentinels)]\n .filter(([name]) => name !== part)\n .map(([, at]) => at.ip);\n if (cuts === \"clients\" || cuts === \"to-clients\") return [client];\n if (cuts === \"group\") return others;\n if (cuts === \"one\" || cuts === \"one-way\")\n return Object.entries(parts.members)\n .filter(([name]) => name !== part)\n .slice(0, 1)\n .map(([, at]) => at.ip);\n return [...others, client];\n};\n\n/** This function gives the direction of the rules of a cut: `one-way` and `to-clients` drop only the segments from the part. */\nconst directionOf = (cuts: NonNullable<GroupPlace[\"cuts\"]>): string[] => (cuts === \"one-way\" || cuts === \"to-clients\" ? [\"--direction\", \"out\"] : []);\n\n/** This function reads the flat reply of a command line client into its fields: name, value, name, value. */\nexport const fieldsOf = (text: string): Array<Record<string, string>> => {\n const out: Array<Record<string, string>> = [];\n const words = text.split(\"\\n\").map((line) => line.replace(/\\r$/, \"\"));\n let current: Record<string, string> | null = null;\n for (let at = 0; at + 1 < words.length; at += 2) {\n const [key, value] = [words[at]!, words[at + 1]!];\n // each entry of a list starts again at its name\n if (key === \"name\" || current === null) {\n current = {};\n out.push(current);\n }\n current[key] = value;\n }\n return out;\n};\n\n/** This function reads the INFO of a server into its fields. */\nexport const infoOf = (text: string): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const line of text.split(\"\\n\")) {\n const at = line.indexOf(\":\");\n if (line.startsWith(\"#\") || at === -1) continue;\n out[line.slice(0, at)] = line.slice(at + 1).trim();\n }\n return out;\n};\n\n/**\n * A view of the group is what its parts tell at one time. `healthy` tells if each Sentinel agrees\n * on one primary with no flag but `master`, and knows each replica and each other Sentinel. Each\n * replica must follow that primary with its link up, and the primary must have each replica online,\n * with no failover in progress.\n */\nexport interface GroupView {\n readonly primary: string | null;\n readonly healthy: boolean;\n readonly why: string;\n}\n\n/** This function judges the views of the Sentinels and of the members: the primary that they agree on, if the group is healthy. */\nexport const viewOf = (\n group: Group,\n ips: Readonly<Record<string, string>>,\n sentinels: ReadonlyArray<{ readonly master: Record<string, string>; readonly replicas: ReadonlyArray<Record<string, string>> }>,\n members: Readonly<Record<string, Record<string, string>>>,\n): GroupView => {\n const others = String(group.sentinels.length - 1);\n const replicas = group.members.length - 1;\n const addresses = new Set(sentinels.map((each) => each.master[\"ip\"]));\n if (addresses.size !== 1) return { primary: null, healthy: false, why: `the Sentinels name ${addresses.size} primaries` };\n const ip = [...addresses][0]!;\n const primary = Object.entries(ips).find(([, at]) => at === ip)?.[0] ?? null;\n if (primary === null) return { primary: null, healthy: false, why: `no member has the address ${ip}` };\n for (const [at, each] of sentinels.entries()) {\n if (each.master[\"flags\"] !== \"master\") return { primary, healthy: false, why: `Sentinel ${at} flags the primary ${each.master[\"flags\"]}` };\n if (each.master[\"num-other-sentinels\"] !== others) return { primary, healthy: false, why: `Sentinel ${at} knows ${each.master[\"num-other-sentinels\"]} other Sentinels` };\n const good = each.replicas.filter(\n (replica) => replica[\"flags\"] === \"slave\" && replica[\"master-link-status\"] === \"ok\" && replica[\"master-host\"] === ip,\n );\n if (good.length !== replicas || each.replicas.length !== replicas)\n return { primary, healthy: false, why: `Sentinel ${at} has ${good.length} healthy replicas of ${each.replicas.length}` };\n }\n const info = members[primary] ?? {};\n if (info[\"role\"] !== \"master\") return { primary, healthy: false, why: `${primary} reports the role ${info[\"role\"]}` };\n if (info[\"master_failover_state\"] !== undefined && info[\"master_failover_state\"] !== \"no-failover\")\n return { primary, healthy: false, why: `${primary} is in the failover state ${info[\"master_failover_state\"]}` };\n const online = Object.entries(info).filter(([key, value]) => /^slave\\d+$/.test(key) && value.includes(\"state=online\")).length;\n if (online !== replicas) return { primary, healthy: false, why: `${primary} has ${online} replicas online` };\n for (const name of group.members) {\n if (name === primary) continue;\n const each = members[name] ?? {};\n if (each[\"role\"] !== \"slave\" || each[\"master_host\"] !== ip || each[\"master_link_status\"] !== \"up\")\n return { primary, healthy: false, why: `${name} is not a replica of ${primary} with its link up` };\n }\n return { primary, healthy: true, why: \"healthy\" };\n};\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** This time is the longest that a group takes to converge before a run, or after it. */\nexport const CONVERGE_MS = 240_000;\n\n/**\n * This function opens one environment of a group cell:\n * - one new network, with each member, each Sentinel, the client and the observer on it.\n * - each member: the stock image, its server as the child of a shell, thus a fin can stop the\n * server and the container stays up. The first member is the primary, and the others follow it.\n * - each Sentinel: the stock image, its Sentinel as the child of a shell, which monitors the first member.\n * - an injector sidecar for each part, in its network and process namespaces.\n * - a client that holds its own network namespace, with a privileged sidecar for its sysctls.\n * - the observer of the Sentinels, in a namespace of its own.\n * - the prober, which watches the namespace of the client, and of each Sentinel for a calibration.\n */\nexport const openGroupLab = async (group: Group, options: { readonly watchSentinels?: boolean } = {}): Promise<GroupLab> => {\n const image = await harnessImage();\n const node = await nodeClientImage();\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n let network: StartedNetwork | undefined;\n const close = async () => {\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n await network?.stop().catch(() => undefined);\n };\n const ipOf = async (container: StartedTestContainer): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network!.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network!.getName()}`);\n return ip;\n };\n try {\n network = await new Network().start();\n const boxes = new Map<string, StartedTestContainer>();\n const injectors = new Map<string, StartedTestContainer>();\n const parts = { members: {} as Record<string, RunPart>, sentinels: {} as Record<string, RunPart> };\n /** This function starts one part: the stock image with its configuration, its program as the child of a shell, and its injector. */\n const start = async (name: string, program: string, file: string, content: string, ready: string) => {\n const box = await new GenericContainer(group.image)\n .withNetwork(network!)\n .withNetworkAliases(name)\n .withCopyContentToContainer([{ content, target: file }])\n .withCommand([\"sh\", \"-c\", `${program} ${file} & while :; do sleep 3600; done`])\n .withWaitStrategy(Wait.forLogMessage(ready))\n .start();\n opened.push(box);\n boxes.set(name, box);\n const injector = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${box.getId()}`,\n ).start();\n opened.push(injector);\n injectors.set(name, injector);\n return { ip: await ipOf(box), netns: await netnsOf(injector) };\n };\n const [first, ...rest] = group.members;\n if (first === undefined) throw new Error(\"a group has no member\");\n parts.members[first] = await start(first, group.programs.server, \"/data/server.conf\", memberConfig(group, null), group.ready.member);\n const primaryIp = parts.members[first].ip;\n for (const name of rest)\n parts.members[name] = await start(name, group.programs.server, \"/data/server.conf\", memberConfig(group, primaryIp), group.ready.member);\n for (const name of group.sentinels)\n parts.sentinels[name] = await start(name, group.programs.sentinel, \"/data/sentinel.conf\", sentinelConfig(group, primaryIp), group.ready.sentinel);\n\n const holder = await new GenericContainer(image).withNetwork(network).start();\n opened.push(holder);\n const admin = await new GenericContainer(image)\n .withNetworkMode(`container:${holder.getId()}`)\n .withPrivilegedMode()\n .start();\n opened.push(admin);\n const clientIp = await ipOf(holder);\n\n const sentinelAddresses = group.sentinels.map((name) => `${parts.sentinels[name]!.ip}:${group.sentinelPort}`);\n const timeline = lines<SentinelEvent>();\n const observer = await new GenericContainer(node)\n .withNetwork(network)\n .withCommand([\"node\", \"/opt/harness/node/observer.mjs\", sentinelAddresses.join(\",\")])\n .withLogConsumer(timeline.consume)\n .start();\n opened.push(observer);\n const observerIp = await ipOf(observer);\n for (const address of sentinelAddresses)\n await new Promise<void>((resolve, reject) => {\n const started = Date.now();\n const look = () => {\n if (timeline.seen.some((line) => line.ev === \"subscribed\" && line[\"sentinel\"] === address)) resolve();\n else if (Date.now() - started > 30_000) reject(new Error(`the observer never subscribed to ${address}`));\n else setTimeout(look, 50);\n };\n look();\n });\n\n const clientNetns = await netnsOf(admin);\n const watched = [clientNetns, ...(options.watchSentinels === true ? group.sentinels.map((name) => parts.sentinels[name]!.netns) : [])];\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\"/opt/harness/prober\", ...watched.map(String)])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n\n const box = (name: string): StartedTestContainer => {\n const found = boxes.get(name);\n if (found === undefined) throw new Error(`the group has no part ${name}`);\n return found;\n };\n const injectorOf = (name: string): StartedTestContainer => {\n const found = injectors.get(name);\n if (found === undefined) throw new Error(`the group has no part ${name}`);\n return found;\n };\n const cli = (name: string, args: readonly string[]): Promise<string> => {\n const port = group.sentinels.includes(name) ? group.sentinelPort : group.port;\n return output(box(name), [group.programs.cli, \"-p\", String(port), ...args]);\n };\n const stamped = async (where: StartedTestContainer, argv: string[]): Promise<Stamp> => {\n const stamp = JSON.parse((await output(where, argv)).split(\"\\n\").at(-1)!) as Stamp;\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const ips: Record<string, string> = Object.fromEntries(Object.entries(parts.members).map(([name, at]) => [name, at.ip]));\n const view = async (): Promise<GroupView> => {\n const sentinels = [];\n for (const name of group.sentinels) {\n const master = fieldsOf(await cli(name, [\"SENTINEL\", \"MASTER\", group.name]))[0] ?? {};\n const replicas = fieldsOf(await cli(name, [\"SENTINEL\", \"REPLICAS\", group.name]));\n sentinels.push({ master, replicas });\n }\n const members: Record<string, Record<string, string>> = {};\n for (const name of group.members) members[name] = infoOf(await cli(name, [\"INFO\", \"replication\"]));\n return viewOf(group, ips, sentinels, members);\n };\n const after = (at: number | undefined): string[] => (at === undefined ? [] : [\"--at\", String(Math.round(at))]);\n const roles = (role: GroupRole, primary: string): string => {\n if (role === \"primary\") return primary;\n if (role === \"sentinel\") return group.sentinels[0]!;\n const replica = group.members.find((name) => name !== primary);\n if (replica === undefined) throw new Error(\"the group has no replica\");\n return replica;\n };\n\n return {\n group,\n clientIp,\n observerIp,\n members: parts.members,\n sentinels: parts.sentinels,\n netns: { client: clientNetns, watched },\n kernel: records.seen,\n timeline: timeline.seen,\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values)) read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n async converge(within = CONVERGE_MS) {\n const started = Date.now();\n let calm = 0;\n let last: GroupView = { primary: null, healthy: false, why: \"no view yet\" };\n while (Date.now() - started < within) {\n last = await view().catch((error: unknown) => ({ primary: null, healthy: false, why: (error as Error).message }));\n // two healthy views in a row: one view can come in the middle of a change\n calm = last.healthy ? calm + 1 : 0;\n if (calm >= 2 && last.primary !== null) return last.primary;\n await sleep(1_000);\n }\n throw new Error(`the group did not converge in ${within} ms: ${last.why}`);\n },\n async flush(primary) {\n await cli(primary, [\"FLUSHALL\"]);\n const acked = Number(await cli(primary, [\"WAIT\", String(group.members.length - 1), \"5000\"]));\n if (acked !== group.members.length - 1) throw new Error(`${acked} replicas acknowledged the flush`);\n },\n async reset() {\n for (const name of group.sentinels) await cli(name, [\"SENTINEL\", \"RESET\", group.name]);\n },\n async holds(primary) {\n return holdsOf(await cli(primary, [\"--scan\", \"--pattern\", \"w:*\"]), await cli(primary, [\"LRANGE\", \"w\", \"0\", \"-1\"]));\n },\n partOf: roles,\n async client(args) {\n const events = lines<ProbeEvent>();\n const container = await new GenericContainer(node)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"node\", \"/opt/harness/node/client-sentinel.mjs\", ...args])\n .withLogConsumer(events.consume)\n .start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n // a TERM first: the client writes its done line, then stops\n stop: () =>\n container\n .stop({ timeout: 2 })\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n fault(kind, part, cuts, at) {\n const peers = peersOf(parts, clientIp, part, cuts).join(\",\");\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind, peers, ...directionOf(cuts), ...after(at)]);\n },\n lift(kind, part, cuts, at) {\n const peers = peersOf(parts, clientIp, part, cuts).join(\",\");\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind === \"rst\" ? \"clear-rst\" : \"clear\", peers, ...directionOf(cuts), ...after(at)]);\n },\n signal(part, signal, at) {\n const program = group.sentinels.includes(part) ? group.programs.sentinel : group.programs.server;\n return stamped(injectorOf(part), [\"/opt/harness/inject\", \"signal\", program, signal, ...after(at)]);\n },\n async restart(member) {\n await output(box(member), [\"sh\", \"-c\", `${group.programs.server} /data/server.conf --daemonize yes`]);\n const started = Date.now();\n while ((await cli(member, [\"PING\"]).catch(() => \"\")) !== \"PONG\") {\n if (Date.now() - started > 30_000) throw new Error(`${member} did not start again`);\n await sleep(200);\n }\n },\n failover(coordinated) {\n const sentinel = group.sentinels[0]!;\n return stamped(injectorOf(sentinel), [\n \"/opt/harness/inject\",\n \"resp\",\n `127.0.0.1:${group.sentinelPort}`,\n \"SENTINEL\",\n \"FAILOVER\",\n group.name,\n ...(coordinated ? [\"COORDINATED\"] : []),\n ]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n async settle() {\n const from = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const started = Date.now();\n const look = () => {\n const line = records.seen.slice(from).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - started > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) =>\n runtime.container.inspect(runtime.container.getById(container.getId()));\n const memberSettings = async (name: string) => {\n const read: Record<string, string> = {};\n // the reply is the name, then the value: an empty value is the end of the reply\n for (const key of Object.keys(group.memberSettings)) read[key] = (await cli(name, [\"CONFIG\", \"GET\", key])).split(\"\\n\")[1] ?? \"\";\n return read;\n };\n const sentinelSettings = async (name: string) => {\n const master = fieldsOf(await cli(name, [\"SENTINEL\", \"MASTER\", group.name]))[0] ?? {};\n const read: Record<string, string> = { quorum: master[\"quorum\"] ?? \"\" };\n for (const key of Object.keys(group.sentinelSettings)) read[key] = master[key] ?? \"\";\n return read;\n };\n const members = [];\n for (const name of group.members)\n members.push({ name, ip: parts.members[name]!.ip, id: (await inspect(box(name))).Image, settings: await memberSettings(name) });\n const sentinels = [];\n for (const name of group.sentinels)\n sentinels.push({ name, ip: parts.sentinels[name]!.ip, id: (await inspect(box(name))).Image, settings: await sentinelSettings(name) });\n return {\n kernel: await output(holder, [\"uname\", \"-r\"]),\n architecture: await output(holder, [\"uname\", \"-m\"]),\n hz: /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1] ?? null,\n boot_id: await output(holder, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n target: { image: group.image, id: members[0]!.id, settings: members[0]!.settings, sysctls: {} },\n harness: {\n image,\n id: (await inspect(holder)).Image,\n packages: (await output(holder, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n ...harnessRecord(),\n },\n client: shippedClientRecord(\"ioredis\", node),\n netns: { client: clientNetns, target: parts.members[first]!.netns },\n sysctls,\n group: { members, sentinels, observer: { image: node } },\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n\n// ---------------------------------------------------------------------------------------------\n// the runs of a group cell\n// ---------------------------------------------------------------------------------------------\n\n/** This count is the number of accepted writes that a run waits for before its fault: the stream is steady then. */\nconst STEADY = 20;\n/** This time is how long a run continues after its outcome, so that the record shows what came next. */\nconst TAIL_MS = 2_000;\n\n/** This function gives the address of a member, with the port of the group. */\nconst addressOf = (lab: GroupLab, member: string): string => `${lab.members[member]!.ip}:${lab.group.port}`;\n\n/** This function gives the latest time that a group cell waits for its outcome, in ms from the fault. */\nexport const deadlineOf = (cell: Cell): number => {\n const { prediction } = cell;\n const seconds =\n prediction.detects === true\n ? valueIn(prediction.high, \"s\")\n : prediction.detects === false && prediction.recovers !== undefined\n ? valueIn(prediction.recovers.high, \"s\")\n : valueIn(prediction.window, \"s\");\n return seconds * 1_000 + 10_000;\n};\n\n/**\n * This function gives the sequence numbers that a group holds, in order, from the output of its\n * command line. They are the keys `w:<n>` of a stream of SET, and the entries of the list `w` of a\n * stream of RPUSH. A list keeps each copy, thus a number can repeat.\n */\nexport const holdsOf = (keys: string, list: string): number[] =>\n [...keys.split(\"\\n\").map((key) => Number(key.trim().slice(2))), ...list.split(\"\\n\").map((entry) => Number(entry.trim()))]\n .filter((n) => Number.isInteger(n) && n > 0)\n .sort((a, b) => a - b);\n\n/** This function gives the arguments of the client of a group cell. */\nconst clientArgs = (cell: Cell, lab: GroupLab): string[] => {\n const sentinels = cell.group!.sentinels.map((name) => `${lab.sentinels[name]!.ip}:${cell.group!.sentinelPort}`);\n const driver = cell.probe.driver?.name === \"ioredis\" ? cell.probe.driver : undefined;\n return [\n \"--sentinels\",\n sentinels.join(\",\"),\n \"--name\",\n cell.group!.name,\n \"--interval-ms\",\n String(cell.probe.interval === undefined ? 50 : valueIn(cell.probe.interval, \"ms\")),\n \"--max-s\",\n String(Math.ceil(deadlineOf(cell) / 1_000 + 120)),\n ...(cell.driverOptions === undefined ? [] : [\"--options\", JSON.stringify(cell.driverOptions)]),\n ...(driver?.op === undefined ? [] : [\"--op\", driver.op]),\n ...(driver?.window === undefined ? [] : [\"--window\", String(driver.window)]),\n ];\n};\n\n/** This function waits until a condition on the lines of the client holds, or for `within` ms. It gives the first line that matches. */\nconst waitFor = (\n client: GroupClient,\n match: (event: ProbeEvent) => boolean,\n within: number,\n): Promise<ProbeEvent | undefined> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const found = client.events.find(match);\n if (found !== undefined || Date.now() - started > within) resolve(found);\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This function gives the latest subscription of the observer to each Sentinel, in some lines of the observer. */\nexport const subscriptionsOf = (timeline: readonly SentinelEvent[]): SentinelEvent[] => {\n const latest = new Map<string, SentinelEvent>();\n for (const line of timeline) if (line.ev === \"subscribed\") latest.set(String(line.sentinel), line);\n return [...latest.values()];\n};\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1)\n if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/**\n * This function does one run of a group cell:\n * - The group converges, and its keys go. The client connects through the Sentinels, and its\n * stream of writes gets steady.\n * - The fault occurs on its part, as the primary of this run makes the roles. A fault with a\n * hold lifts at its instant in the VM. A stall lifts at its length after the first write into it.\n * - The run waits for its outcome: the first write that a new primary accepts, or the first one\n * after the lift on the same primary. Then it continues for a moment.\n * - Each fault goes, the client stops, and the group converges again. The keys that it then holds\n * tell which writes it kept.\n */\nexport const groupOnce = async (lab: GroupLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const group = cell.group!;\n const primary = await lab.converge();\n await lab.flush(primary);\n await lab.forget();\n const from = lab.kernel.length;\n const timelineFrom = lab.timeline.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const client = await lab.client(clientArgs(cell, lab));\n const lands = cell.prediction.group?.lands ?? \"new\";\n const place = (cell.faultAt ?? { role: \"primary\" }) as GroupPlace;\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n let at: string | null = null;\n const undo: Array<() => Promise<unknown>> = [];\n try {\n await client.until([\"ready\"], 60_000);\n const steady = await waitFor(client, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not write ${STEADY} times in 30 s`);\n let healing: Promise<Run[\"heal\"]> | null = null;\n switch (cell.fault) {\n case \"blackhole\":\n case \"partition\":\n case \"rst\": {\n const kind = cell.fault === \"rst\" ? \"rst\" : \"blackhole\";\n const cuts = place.cuts ?? (cell.fault === \"partition\" ? \"group\" : \"all\");\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.fault(kind, part, cuts);\n undo.push(() => lab.lift(kind, part, cuts));\n if (cell.stall !== undefined) {\n // the first write into the fault arms the retransmissions: the stall counts from it\n const t1 = fault.t1;\n const sent = await waitFor(client, (event) => event.ev === \"sent\" && event.t > t1, 5_000);\n if (sent !== undefined) healing = lab.lift(kind, part, cuts, sent.t + valueIn(cell.stall, \"s\") * 1e9);\n } else if (cell.hold !== undefined) {\n healing = lab.lift(kind, part, cuts, fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n }\n break;\n }\n case \"freeze-process\": {\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.signal(part, \"STOP\");\n undo.push(() => lab.signal(part, \"CONT\"));\n if (cell.hold !== undefined) healing = lab.signal(part, \"CONT\", fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n break;\n }\n case \"fin\": {\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.signal(part, \"KILL\");\n if (group.members.includes(part)) undo.push(() => lab.restart(part));\n break;\n }\n case \"planned-failover\":\n fault = await lab.failover(cell.coordinated === true);\n break;\n default:\n throw new Error(`a group cell has no fault ${cell.fault}`);\n }\n // the injector holds the lift in the VM: its exec returns at the instant, and the stamps come with it\n const healed =\n healing === null\n ? Promise.resolve(null)\n : healing.then((stamp) => {\n heal = stamp;\n // the lift came: nothing is left to undo\n undo.length = 0;\n return stamp;\n });\n // a run that stops early lifts the fault itself, and the late lift then has nothing to remove\n healed.catch(() => undefined);\n const t0 = fault.t0;\n const old = addressOf(lab, primary);\n const deadline = deadlineOf(cell);\n const outcome =\n lands === \"new\"\n ? await waitFor(\n client,\n (event) => event.ev === \"ack\" && event.t > t0 && typeof event[\"at\"] === \"string\" && event[\"at\"] !== old,\n deadline,\n )\n : await (async () => {\n await healed;\n const after = (heal as Run[\"heal\"])?.t0 ?? t0;\n return waitFor(client, (event) => event.ev === \"ack\" && event.t > after, deadline);\n })();\n if (outcome !== undefined) await sleep(TAIL_MS);\n await healed;\n } finally {\n // each fault that is still on goes, and a killed server starts again\n for (const step of undo.reverse()) await step().catch(() => undefined);\n await client.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge().catch(() => null);\n const holds = after === null ? null : await lab.holds(after);\n // a failover that a Sentinel aborted holds off its next attempt for 2 × failover-timeout. The\n // next run must not inherit that hold-off: each Sentinel forgets the state of the group, and the\n // next converge waits until each one knows the group again\n if (lab.timeline.slice(timelineFrom).some((line) => line.ev === \"sentinel\" && String(line.event).startsWith(\"-failover-abort\")))\n await lab.reset();\n return {\n environment,\n index,\n events: [...client.events],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[primary]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: lab.sentinels,\n primary,\n at,\n // the subscription of the observer to each Sentinel came before the run: its address names\n // the socket of each Sentinel's writes, which a calibration reads\n timeline: [...subscriptionsOf(lab.timeline.slice(0, timelineFrom)), ...lab.timeline.slice(timelineFrom)],\n after,\n holds,\n },\n };\n};\n","import type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, GroupPlace, GroupRole, KernelRecord, ProbeEvent, ReplicaSet, Run, RunPart, SentinelEvent } from \"./cell.ts\";\nimport type { GroupClient, GroupNetworkFault, GroupView, Stamp } from \"./group.ts\";\nimport { CONVERGE_MS, deadlineOf } from \"./group.ts\";\nimport type { Manifest } from \"./lab.ts\";\nimport { harnessImage, mongoClientImage } from \"./image.ts\";\nimport { STOP, containers, harnessRecord, lines, netnsOf, output, shippedClientRecord, withPid } from \"./lab.ts\";\nimport { drillSpan } from \"./recovery.ts\";\nimport { substrateHere } from \"./substrate.ts\";\n\n/**\n * This module is the lab of a replica set: a replicated group with no external authority, whose\n * members elect their own primary. It opens one environment for a replica set cell, for the runs\n * of the cell. Each member is a container from the stock image of the set, in its own network\n * namespace. An injector sidecar shares its network and process namespaces.\n *\n * The client of each run is the MongoDB driver, which finds the primary with its own monitors. The\n * timeline comes from the log of each member and from the lines of the client. The prober watches\n * the namespace of the client.\n */\n\n/**\n * A member line is one log line of a member, as mongod writes it in JSON. `real` is its time on\n * the wall clock in ms, and `t` is its time on the monotonic clock. The run gives `t` from the\n * clock lines of its client.\n */\nexport interface MemberLine extends SentinelEvent {\n readonly ev: \"mongod\";\n readonly member: string;\n readonly real: number;\n readonly id: number;\n readonly c: string;\n readonly msg: string;\n readonly attr: Readonly<Record<string, unknown>>;\n}\n\n/** These are the components of the log of mongod that a run keeps: replication, its heartbeats, the elections, the rollbacks and the commands. */\nexport const KEPT: ReadonlySet<string> = new Set([\"REPL\", \"REPL_HB\", \"ELECTION\", \"ROLLBACK\", \"COMMAND\"]);\n\n/** This function reads one log line of a member, or gives null for a line of another component or a line that is not JSON. */\nexport const memberLineOf = (member: string, text: string): MemberLine | null => {\n if (!text.startsWith(\"{\")) return null;\n let line: { t?: { $date?: string }; c?: string; id?: number; msg?: string; attr?: Record<string, unknown> };\n try {\n line = JSON.parse(text) as typeof line;\n } catch {\n return null;\n }\n const real = Date.parse(line.t?.$date ?? \"\");\n if (!Number.isFinite(real) || !KEPT.has(line.c ?? \"\")) return null;\n return { ev: \"mongod\", t: 0, member, real, id: Number(line.id ?? 0), c: line.c ?? \"\", msg: line.msg ?? \"\", attr: line.attr ?? {} };\n};\n\n/**\n * This function gives the offset of the wall clock from the monotonic clock, in ns, from the clock\n * lines of a client. Each line pairs its stamp with the wall clock in whole ms, which truncates.\n * Thus each pair is the offset or less, and the largest pair is the nearest. It is null without a clock line.\n */\nexport const clockOffsetOf = (events: readonly ProbeEvent[]): number | null => {\n const offsets = events.filter((event) => event.ev === \"clocks\").map((event) => Number(event[\"real\"]) * 1e6 - event.t);\n return offsets.length === 0 ? null : Math.max(...offsets);\n};\n\n/** This function puts the log lines of the members on the monotonic clock, with the offset of a client. */\nexport const onMonotonic = (log: readonly MemberLine[], offset: number | null): MemberLine[] =>\n log.map((line) => ({ ...line, t: offset === null ? 0 : Math.round(line.real * 1e6 - offset) }));\n\n/** A cut is the peers that a network fault on a part cuts it from, by their addresses, and the direction of the rules. */\nexport interface Cut {\n readonly peers: readonly string[];\n readonly direction?: \"out\";\n}\n\n/**\n * This function gives the peers that a fault on a member of a replica set cuts it from. `all` is\n * each other member and the client, `group` is the other members, and `clients` is the client.\n * `one` is the first other member in the sequence of the set, and `one-way` is the same member for\n * the segments from the part only.\n */\nexport const cutOf = (\n set: ReplicaSet,\n members: Readonly<Record<string, RunPart>>,\n client: string,\n part: string,\n cuts: NonNullable<GroupPlace[\"cuts\"]>,\n): Cut => {\n const others = set.members.filter((name) => name !== part).map((name) => members[name]!.ip);\n if (cuts === \"clients\") return { peers: [client] };\n if (cuts === \"group\") return { peers: others };\n if (cuts === \"one\") return { peers: others.slice(0, 1) };\n if (cuts === \"one-way\") return { peers: others.slice(0, 1), direction: \"out\" };\n if (cuts === \"to-clients\") return { peers: [client], direction: \"out\" };\n return { peers: [...others, client] };\n};\n\n/** This function gives the command of the server of each member. The server is the child of a shell, thus a fin can stop it and the container stays up. */\nexport const memberCommand = (set: ReplicaSet): string =>\n `${set.programs.server} --replSet ${set.name} --bind_ip_all --port ${set.port} ${(set.args ?? []).join(\" \")}`.trim();\n\n/** This function gives the script of the shell that starts the set: each member by its address, and the settings of the set. */\nexport const initiateScript = (set: ReplicaSet, ips: Readonly<Record<string, string>>): string => {\n const config = {\n _id: set.name,\n members: set.members.map((name, at) => ({ _id: at, host: `${ips[name]}:${set.port}` })),\n settings: set.settings,\n };\n return `print(JSON.stringify(rs.initiate(${JSON.stringify(config)})))`;\n};\n\n/** This script prints the view of a member: itself, if it accepts writes, and the state of each member as it sees them. */\nexport const STATUS_SCRIPT: string =\n \"const s = rs.status(); const h = db.hello(); print(JSON.stringify({ me: h.me, writable: h.isWritablePrimary === true, \" +\n \"members: s.members.map((m) => ({ name: m.name, state: m.stateStr, health: m.health, optime: m.optimeDate ? m.optimeDate.getTime() : null })) }))\";\n\n/** A status is the view of one member, as `STATUS_SCRIPT` prints it. */\nexport interface Status {\n readonly me: string;\n readonly writable: boolean;\n readonly members: ReadonlyArray<{ readonly name: string; readonly state: string; readonly health: number; readonly optime: number | null }>;\n}\n\n/**\n * This function judges the view of a member: the primary of the set, and if the set is healthy.\n * The set is healthy when the member is the one primary and accepts writes. Each other member must\n * be a healthy secondary at the optime of the primary.\n */\nexport const statusViewOf = (set: ReplicaSet, ips: Readonly<Record<string, string>>, status: Status): GroupView => {\n const byAddress = new Map(set.members.map((name) => [`${ips[name]}:${set.port}`, name]));\n const primaries = status.members.filter((member) => member.state === \"PRIMARY\");\n if (primaries.length !== 1) return { primary: null, healthy: false, why: `the set has ${primaries.length} primaries` };\n const primary = byAddress.get(primaries[0]!.name) ?? null;\n if (primary === null) return { primary: null, healthy: false, why: `no member has the address ${primaries[0]!.name}` };\n if (status.me !== primaries[0]!.name || !status.writable) return { primary, healthy: false, why: `${primary} does not accept writes yet` };\n if (status.members.length !== set.members.length) return { primary, healthy: false, why: `the set has ${status.members.length} members` };\n for (const member of status.members) {\n if (member.health !== 1) return { primary, healthy: false, why: `${member.name} is not healthy` };\n if (member.state !== \"PRIMARY\" && member.state !== \"SECONDARY\") return { primary, healthy: false, why: `${member.name} is ${member.state}` };\n if (member.optime !== primaries[0]!.optime) return { primary, healthy: false, why: `${member.name} is behind the primary` };\n }\n return { primary, healthy: true, why: \"healthy\" };\n};\n\n/** A replica set lab is one environment of a replica set cell. */\nexport interface ReplicaSetLab {\n readonly set: ReplicaSet;\n readonly clientIp: string;\n readonly members: Readonly<Record<string, RunPart>>;\n readonly netns: { readonly client: number };\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** These are the log lines of the members that a run keeps, in the sequence of their arrival, with `t` at 0. */\n readonly log: readonly MemberLine[];\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method waits until the set is whole and calm, and gives the name of its primary. */\n converge(within?: number): Promise<string>;\n /** This method removes each write from the set, and waits until each member has the removal. */\n flush(primary: string): Promise<void>;\n /**\n * This method lets each secondary stand for election again (`rs.freeze(0)`). A step-down holds its\n * old primary out of the elections for `STEP_DOWN.seconds`. Without it, a run inherits that hold.\n */\n unfreeze(primary: string): Promise<void>;\n /** This method gives the sequence numbers that the set holds, from its primary. */\n holds(primary: string): Promise<number[]>;\n /** This method gives the member that has a role in the set, when `primary` is the primary. */\n partOf(role: GroupRole, primary: string): string;\n /** This method starts the client of a run, with the arguments of `client-mongo.mjs`. */\n client(args: readonly string[]): Promise<GroupClient>;\n /** This method applies a network fault between a member and some of its peers, at once or at an instant of the VM. */\n fault(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes a network fault, at once or at an instant of the VM. */\n lift(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method sends a signal to the server process of a member, at once or at an instant of the VM. */\n signal(part: string, signal: \"KILL\" | \"STOP\" | \"CONT\", at?: number): Promise<Stamp>;\n /** This method starts the server of a member again, after a fin. */\n restart(member: string): Promise<void>;\n /** This method runs a command in the box of a member, and gives its output. */\n exec(member: string, argv: string[]): Promise<string>;\n /** This method runs a script of the shell on a member, against its own server only, and gives its output. Another port reads a server with no set. */\n script(member: string, script: string, port?: number): Promise<string>;\n /** This method runs a command on the backup host of a drill, and gives its output. A lab without that host refuses it. */\n vault(argv: string[]): Promise<string>;\n /** This method sends replSetStepDown to the primary. */\n stepDown(primary: string): Promise<Stamp>;\n /** This method removes the TCP metrics of the client namespace: each run starts from a kernel that keeps nothing. */\n forget(): Promise<void>;\n /** This method waits for the next clock line of the prober, which gives the count of lost records. */\n settle(): Promise<number | null>;\n manifest(sysctls: Readonly<Record<string, string>>): Promise<Manifest>;\n close(): Promise<void>;\n}\n\n/** This function waits for a time, in ms. */\nexport const sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** These are the arguments of replSetStepDown: the time that the old primary cannot stand again, and the wait for a secondary to catch up. */\nexport const STEP_DOWN = { seconds: 60, catchUp: 10 } as const;\n\n/**\n * This function opens one environment of a replica set cell:\n * - one new network, with each member, the client and the sender of a step-down on it.\n * - each member: the stock image, its server as the child of a shell. A log consumer reads its\n * JSON log. The first member starts the set with the address of each member, and the lab\n * waits for a primary.\n * - an injector sidecar for each member, in its network and process namespaces.\n * - a client that holds its own network namespace, with a privileged sidecar for its sysctls.\n * - the prober, which watches the namespace of the client.\n * - a backup host for a recovery drill: the stock image, for its tools, with no server.\n */\nexport const openReplicaSetLab = async (set: ReplicaSet, backups = false): Promise<ReplicaSetLab> => {\n const image = await harnessImage();\n const mongo = await mongoClientImage();\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n let network: StartedNetwork | undefined;\n const close = async () => {\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n await network?.stop().catch(() => undefined);\n };\n const ipOf = async (container: StartedTestContainer): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network!.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network!.getName()}`);\n return ip;\n };\n try {\n network = await new Network().start();\n const boxes = new Map<string, StartedTestContainer>();\n const injectors = new Map<string, StartedTestContainer>();\n const members: Record<string, RunPart> = {};\n const log: MemberLine[] = [];\n for (const name of set.members) {\n let partial = \"\";\n const box = await new GenericContainer(set.image)\n .withNetwork(network)\n .withNetworkAliases(name)\n .withCommand([\"sh\", \"-c\", `${memberCommand(set)} & echo $! > /tmp/server.pid; while :; do sleep 3600; done`])\n .withWaitStrategy(Wait.forLogMessage(set.ready))\n .withLogConsumer((stream) =>\n stream.on(\"data\", (chunk: Buffer | string) => {\n partial += chunk.toString();\n const split = partial.split(\"\\n\");\n partial = split.pop() ?? \"\";\n for (const text of split) {\n const line = memberLineOf(name, text.trim());\n if (line !== null) log.push(line);\n }\n }),\n )\n .start();\n opened.push(box);\n boxes.set(name, box);\n const injector = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${box.getId()}`,\n ).start();\n opened.push(injector);\n injectors.set(name, injector);\n members[name] = { ip: await ipOf(box), netns: await netnsOf(injector) };\n }\n const ips: Record<string, string> = Object.fromEntries(Object.entries(members).map(([name, at]) => [name, at.ip]));\n\n const holder = await new GenericContainer(image).withNetwork(network).start();\n opened.push(holder);\n const admin = await new GenericContainer(image).withNetworkMode(`container:${holder.getId()}`).withPrivilegedMode().start();\n opened.push(admin);\n const clientIp = await ipOf(holder);\n // the sender of a step-down is a client of its own, on the network but not in the watched namespace\n const commander = await new GenericContainer(mongo)\n .withNetwork(network)\n .withCommand([\"sh\", \"-c\", \"while :; do sleep 3600; done\"])\n .start();\n opened.push(commander);\n const backupHost = backups\n ? await new GenericContainer(set.image).withNetwork(network).withCommand([\"sh\", \"-c\", \"while :; do sleep 3600; done\"]).start()\n : null;\n if (backupHost !== null) opened.push(backupHost);\n\n const clientNetns = await netnsOf(admin);\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\"/opt/harness/prober\", String(clientNetns)])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n\n const box = (name: string): StartedTestContainer => {\n const found = boxes.get(name);\n if (found === undefined) throw new Error(`the set has no member ${name}`);\n return found;\n };\n const injectorOf = (name: string): StartedTestContainer => {\n const found = injectors.get(name);\n if (found === undefined) throw new Error(`the set has no member ${name}`);\n return found;\n };\n /** This function starts a script of the shell on a member, against its own server only. */\n const shell = (name: string, script: string, port: number = set.port): Promise<string> =>\n output(box(name), [\n set.programs.shell,\n \"--quiet\",\n \"--norc\",\n `mongodb://127.0.0.1:${port}/?directConnection=true&serverSelectionTimeoutMS=3000`,\n \"--eval\",\n script,\n ]);\n const lastLine = (text: string): string => text.split(\"\\n\").filter((line) => line.trim() !== \"\").at(-1) ?? \"\";\n const stamped = async (where: StartedTestContainer, argv: string[]): Promise<Stamp> => {\n const stamp = JSON.parse(lastLine(await output(where, argv))) as Stamp;\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const after = (at: number | undefined): string[] => (at === undefined ? [] : [\"--at\", String(Math.round(at))]);\n let known: string = set.members[0]!;\n /** This function gives the view of the set: from the member that was the primary last, then from each other member. */\n const view = async (): Promise<GroupView> => {\n let last: GroupView = { primary: null, healthy: false, why: \"no member answered\" };\n for (const name of [known, ...set.members.filter((each) => each !== known)]) {\n const read = await shell(name, STATUS_SCRIPT)\n .then((text) => statusViewOf(set, ips, JSON.parse(lastLine(text)) as Status))\n .catch((error: unknown) => ({ primary: null, healthy: false, why: `${name}: ${(error as Error).message.slice(0, 200)}` }));\n if (read.primary !== null && read.primary === name) return read;\n last = read;\n }\n return last;\n };\n const converge = async (within = CONVERGE_MS): Promise<string> => {\n const started = Date.now();\n let calm = 0;\n let last: GroupView = { primary: null, healthy: false, why: \"no view yet\" };\n while (Date.now() - started < within) {\n last = await view();\n // two healthy views in a row: one view can come in the middle of a change\n calm = last.healthy ? calm + 1 : 0;\n if (last.primary !== null) known = last.primary;\n if (calm >= 2 && last.primary !== null) return last.primary;\n await sleep(1_000);\n }\n throw new Error(`the set did not converge in ${within} ms: ${last.why}`);\n };\n\n // the first member starts the set, with the address of each member as the client reaches it\n const initiated = await shell(set.members[0]!, initiateScript(set, ips));\n if (!lastLine(initiated).includes('\"ok\":1')) throw new Error(`rs.initiate failed: ${lastLine(initiated)}`);\n await converge();\n\n return {\n set,\n clientIp,\n members,\n netns: { client: clientNetns },\n kernel: records.seen,\n log,\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values)) read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n converge,\n async flush(primary) {\n const script =\n `const r = db.getSiblingDB(\"cells\").w.deleteMany({}, { writeConcern: { w: ${set.members.length}, wtimeout: 10000 } }); ` +\n \"print(JSON.stringify({ ok: r.acknowledged === true }))\";\n const reply = lastLine(await shell(primary, script));\n if (!reply.includes('\"ok\":true')) throw new Error(`the flush failed: ${reply}`);\n },\n async unfreeze(primary) {\n for (const name of set.members) {\n if (name === primary) continue;\n const reply = lastLine(await shell(name, \"print(JSON.stringify(rs.freeze(0)))\"));\n if (!reply.includes('\"ok\":1')) throw new Error(`${name} did not unfreeze: ${reply}`);\n }\n },\n async holds(primary) {\n const script = 'print(JSON.stringify(db.getSiblingDB(\"cells\").w.find({}, { n: 1, _id: 0 }).toArray().map((d) => d.n)))';\n const held = JSON.parse(lastLine(await shell(primary, script))) as unknown[];\n return held\n .map(Number)\n .filter((n) => Number.isInteger(n) && n > 0)\n .sort((a, b) => a - b);\n },\n partOf(role, primary) {\n if (role === \"primary\") return primary;\n if (role === \"sentinel\") throw new Error(\"a replica set has no Sentinel\");\n const secondary = set.members.find((name) => name !== primary);\n if (secondary === undefined) throw new Error(\"the set has no secondary\");\n return secondary;\n },\n async client(args) {\n const events = lines<ProbeEvent>();\n const container = await new GenericContainer(mongo)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"node\", \"/opt/harness/mongo/client-mongo.mjs\", ...args])\n .withLogConsumer(events.consume)\n .start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n // a TERM first: the client writes its done line, then stops\n stop: () =>\n container\n .stop({ timeout: 2 })\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n fault(kind, part, cuts, at) {\n const cut = cutOf(set, members, clientIp, part, cuts);\n const direction = cut.direction === undefined ? [] : [\"--direction\", cut.direction];\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind, cut.peers.join(\",\"), ...direction, ...after(at)]);\n },\n lift(kind, part, cuts, at) {\n const cut = cutOf(set, members, clientIp, part, cuts);\n const direction = cut.direction === undefined ? [] : [\"--direction\", cut.direction];\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind === \"rst\" ? \"clear-rst\" : \"clear\", cut.peers.join(\",\"), ...direction, ...after(at)]);\n },\n signal(part, signal, at) {\n return stamped(injectorOf(part), [\"/opt/harness/inject\", \"signal\", set.programs.server, signal, ...after(at)]);\n },\n async restart(member) {\n // the restarted server writes to the output of the container, thus its log consumer reads it\n await output(box(member), [\"sh\", \"-c\", `${memberCommand(set)} > /proc/1/fd/1 2>&1 & echo $! > /tmp/server.pid`]);\n const started = Date.now();\n while (!(await shell(member, \"print(db.hello().ok)\").catch(() => \"\")).includes(\"1\")) {\n if (Date.now() - started > 60_000) throw new Error(`${member} did not start again`);\n await sleep(500);\n }\n },\n exec(member, argv) {\n return output(box(member), argv);\n },\n script: shell,\n vault(argv) {\n if (backupHost === null) throw new Error(\"this lab has no backup host\");\n return output(backupHost, argv);\n },\n stepDown(primary) {\n return stamped(commander, [\n \"node\",\n \"/opt/harness/mongo/stepdown-mongo.mjs\",\n `${members[primary]!.ip}:${set.port}`,\n String(STEP_DOWN.seconds),\n String(STEP_DOWN.catchUp),\n ]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n async settle() {\n const from = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const started = Date.now();\n const look = () => {\n const line = records.seen.slice(from).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - started > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) => runtime.container.inspect(runtime.container.getById(container.getId()));\n const script = \"print(JSON.stringify({ version: db.version(), settings: rs.conf().settings }))\";\n const list = [];\n for (const name of set.members) {\n const read = JSON.parse(lastLine(await shell(name, script))) as { version: string; settings: Record<string, unknown> };\n const settings: Record<string, string> = { version: read.version };\n for (const key of Object.keys(set.settings)) settings[key] = String(read.settings[key] ?? \"\");\n list.push({ name, ip: members[name]!.ip, id: (await inspect(box(name))).Image, settings });\n }\n return {\n kernel: await output(holder, [\"uname\", \"-r\"]),\n architecture: await output(holder, [\"uname\", \"-m\"]),\n hz: /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1] ?? null,\n boot_id: await output(holder, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n substrate: substrateHere(\"E1\"),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n target: { image: set.image, id: list[0]!.id, settings: list[0]!.settings, sysctls: {} },\n harness: {\n image,\n id: (await inspect(holder)).Image,\n packages: (await output(holder, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n ...harnessRecord(),\n },\n client: shippedClientRecord(\"mongodb\", mongo),\n netns: { client: clientNetns, target: members[set.members[0]!]!.netns },\n sysctls,\n group: { members: list, sentinels: [], observer: { image: mongo } },\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n\n// ---------------------------------------------------------------------------------------------\n// the runs of a replica set cell\n// ---------------------------------------------------------------------------------------------\n\n/** This count is the number of accepted writes that a run waits for before its fault: the stream is steady then. */\nexport const STEADY = 20;\n/** This time is how long a run continues after its outcome, so that the record shows what came next. */\nexport const TAIL_MS = 2_000;\n\n/** This function gives how long a run of a cell continues after its lift, in ms: the tail, and the watch of the cell. */\nexport const afterLiftOf = (cell: Cell): number => TAIL_MS + (cell.watch === undefined ? 0 : valueIn(cell.watch, \"s\") * 1000);\n\n/** This function gives the arguments of the client of a replica set cell: each member, and the stream of writes. */\nexport const replicaSetArgs = (cell: Cell, members: Readonly<Record<string, RunPart>>): string[] => {\n const set = cell.replicaSet!;\n const hosts = set.members.map((name) => `${members[name]!.ip}:${set.port}`);\n return [\n members[set.members[0]!]!.ip,\n String(set.port),\n \"--mode\",\n \"stream\",\n \"--hosts\",\n hosts.join(\",\"),\n \"--set\",\n set.name,\n \"--interval-ms\",\n String(cell.probe.interval === undefined ? 50 : valueIn(cell.probe.interval, \"ms\")),\n \"--max-s\",\n String(Math.ceil(deadlineOf(cell) / 1_000 + (cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\")) + (cell.drill === undefined ? 0 : drillSpan(cell.drill)) + 120)),\n \"--w\",\n String(cell.writeConcern ?? \"majority\"),\n ...(cell.driverOptions === undefined ? [] : [\"--options\", JSON.stringify(cell.driverOptions)]),\n ];\n};\n\n/** This function waits until a condition on the lines of the client holds, or for `within` ms. It gives the first line that matches. */\nexport const waitFor = (client: GroupClient, match: (event: ProbeEvent) => boolean, within: number): Promise<ProbeEvent | undefined> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const found = client.events.find(match);\n if (found !== undefined || Date.now() - started > within) resolve(found);\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nexport const droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1) if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/**\n * This function does one run of a replica set cell:\n * - The set converges, and its writes go. The client finds the primary with its monitors, and its\n * stream of writes gets steady.\n * - The fault occurs on its member, as the primary of this run makes the roles. A fault with a\n * hold lifts at its instant in the VM. A stall lifts at its length after the first write into\n * it. A step-down is replSetStepDown to the primary.\n * - The run waits for its outcome: the first accepted write of a write sent after the commit of\n * the fault. It is on a new primary, or on any primary. Then the run waits for the end of the\n * hold, thus the record shows what the set did in the whole hold.\n * - Each fault goes, the client stops, and the set converges again. The writes that it then holds\n * tell which writes it kept. The log lines of the members go onto the monotonic clock.\n */\nexport const replicaSetOnce = async (lab: ReplicaSetLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const set = cell.replicaSet!;\n const primary = await lab.converge();\n await lab.flush(primary);\n // each secondary can win an election: no hold of a step-down in an earlier run is left\n await lab.unfreeze(primary);\n await lab.forget();\n const from = lab.kernel.length;\n const logFrom = lab.log.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const client = await lab.client(replicaSetArgs(cell, lab.members));\n const lands = cell.prediction.group?.lands ?? \"new\";\n const place = (cell.faultAt ?? { role: \"primary\" }) as GroupPlace;\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n let at: string | null = null;\n const undo: Array<() => Promise<unknown>> = [];\n try {\n await client.until([\"ready\"], 60_000);\n const steady = await waitFor(client, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not write ${STEADY} times in 30 s`);\n let healing: Promise<Run[\"heal\"]> | null = null;\n switch (cell.fault) {\n case \"blackhole\":\n case \"partition\":\n case \"rst\": {\n const kind = cell.fault === \"rst\" ? \"rst\" : \"blackhole\";\n const cuts = place.cuts ?? (cell.fault === \"partition\" ? \"group\" : \"all\");\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.fault(kind, part, cuts);\n undo.push(() => lab.lift(kind, part, cuts));\n if (cell.stall !== undefined) {\n // the first write into the fault arms the retransmissions: the stall counts from it. A\n // write that was in flight at the commit holds the stream, and then the stall counts from\n // the commit. The measurement then voids the run\n const t1 = fault.t1;\n const sent = await waitFor(client, (event) => event.ev === \"sent\" && event.t > t1, 5_000);\n healing = lab.lift(kind, part, cuts, (sent?.t ?? t1) + valueIn(cell.stall, \"s\") * 1e9);\n } else if (cell.hold !== undefined) {\n healing = lab.lift(kind, part, cuts, fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n }\n break;\n }\n case \"freeze-process\": {\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.signal(part, \"STOP\");\n undo.push(() => lab.signal(part, \"CONT\"));\n if (cell.hold !== undefined) healing = lab.signal(part, \"CONT\", fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n break;\n }\n case \"fin\": {\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.signal(part, \"KILL\");\n undo.push(() => lab.restart(part));\n break;\n }\n case \"step-down\":\n at = primary;\n fault = await lab.stepDown(primary);\n break;\n default:\n throw new Error(`a replica set cell has no fault ${cell.fault}`);\n }\n // the injector holds the lift in the VM: its exec returns at the instant, and the stamps come with it\n const healed =\n healing === null\n ? Promise.resolve(null)\n : healing.then((stamp) => {\n heal = stamp;\n // the lift came: nothing is left to undo\n undo.length = 0;\n return stamp;\n });\n // a run that stops early lifts the fault itself, and the late lift then has nothing to remove\n healed.catch(() => undefined);\n const t1 = fault.t1;\n const old = `${lab.members[primary]!.ip}:${set.port}`;\n const sentAt = (n: number): number => client.events.find((event) => event.ev === \"sent\" && Number(event[\"n\"]) === n)?.t ?? -Infinity;\n const outcome = await waitFor(\n client,\n (event) => event.ev === \"ack\" && sentAt(Number(event[\"n\"])) > t1 && (lands === \"same\" || (typeof event[\"at\"] === \"string\" && event[\"at\"] !== old)),\n deadlineOf(cell),\n );\n if (outcome !== undefined) await sleep(TAIL_MS);\n // the whole hold: a prediction that no failover occurs reads the set in each moment of it\n if (healing !== null) {\n await healed.catch(() => undefined);\n await sleep(afterLiftOf(cell));\n }\n } finally {\n // each fault that is still on goes, and a killed server starts again\n for (const step of undo.reverse()) await step().catch(() => undefined);\n await client.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge().catch(() => null);\n const holds = after === null ? null : await lab.holds(after);\n return {\n environment,\n index,\n events: [...client.events],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[primary]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: {},\n primary,\n at,\n timeline: onMonotonic(lab.log.slice(logFrom), clockOffsetOf(client.events)),\n after,\n holds,\n },\n };\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, Drill, ProbeEvent, Run, RunBackup } from \"./cell.ts\";\nimport type { GroupClient, Stamp } from \"./group.ts\";\nimport { deadlineOf } from \"./group.ts\";\nimport type { OplogTime } from \"./recovery.ts\";\nimport { HASH_SCRIPT, hashOf, highestHeld, readOplog, seedScript, sliceQuery, standaloneCommand, stopScript } from \"./recovery.ts\";\nimport type { ReplicaSetLab } from \"./replset.ts\";\nimport { STEADY, TAIL_MS, clockOffsetOf, droppedSoFar, initiateScript, onMonotonic, replicaSetArgs, sleep, waitFor } from \"./replset.ts\";\n\n/**\n * This module does one run of a recovery drill on the lab of a replica set. A drill stops the store\n * during writes, removes its disk, and recovers from real backups, or by an election.\n *\n * A backup is a real `mongodump`, on a host of its own. The dump has the oplog of its own time, and\n * each slice has the oplog after the backup before it. The fault comes at the age of the newest\n * backup, on the clock of the VM. Thus a run measures the worst case of its interval by construction.\n *\n * A restore cannot have a client of the set: the client writes to any primary. So the restore writes\n * to a server with no set, on its own port. That server then stops, each member starts with an empty\n * set, and the old primary starts the set. Only that member has the data, thus it wins.\n *\n * The driver refuses a primary with an election id under the highest one that it saw, and a new\n * set starts its ids again. So a restore has two clients. The first one writes up to the fault, and\n * the second one starts after the restore, with the sequence numbers that follow the first.\n */\n\n/** This folder is the store of the backups, on the backup host. */\nconst VAULT = \"/backup\";\n/** This time is the longest wait for a server to answer, in ms. */\nconst STARTS_WITHIN = 60_000;\n\n/** This function waits until a check holds, or it stops the run after `within` ms. */\nconst until = async (what: string, check: () => Promise<boolean>, within: number): Promise<void> => {\n const started = Date.now();\n while (!(await check().catch(() => false))) {\n if (Date.now() - started > within) throw new Error(`${what} did not come in ${within} ms`);\n await sleep(500);\n }\n};\n\n/** This function gives the time that the client sent a write. Zero is no write. */\nconst writeOf = (events: readonly ProbeEvent[], n: number): RunBackup[\"last\"] => {\n const sent = n === 0 ? undefined : events.find((event) => event.ev === \"sent\" && Number(event[\"n\"]) === n);\n return sent === undefined ? null : { n, t: sent.t };\n};\n\n/** This function gives the size of a folder of the backup host. */\nconst sizeOf = async (lab: ReplicaSetLab, path: string): Promise<RunBackup[\"size\"]> => {\n const [bytes] = (await lab.vault([\"du\", \"-sb\", path])).split(/\\s+/);\n return { value: Number(bytes), unit: \"B\" };\n};\n\n/** This function takes the dump with its oplog, and each slice of the oplog at its interval. It gives each backup in sequence. */\nconst backupsOf = async (lab: ReplicaSetLab, drill: Drill, primary: string, writer: GroupClient): Promise<RunBackup[]> => {\n const host = `${lab.members[primary]!.ip}:${lab.set.port}`;\n const started = Date.now();\n await lab.vault([\"mongodump\", \"--host\", host, \"--oplog\", \"--out\", `${VAULT}/dump-0`]);\n const ended = Date.now();\n const oplog = readOplog(await lab.vault([\"bsondump\", \"--quiet\", `${VAULT}/dump-0/oplog.bson`]));\n const held = highestHeld(await lab.vault([\"bsondump\", \"--quiet\", `${VAULT}/dump-0/cells/w.bson`]));\n if (oplog.last === null) throw new Error(\"the oplog of the dump has no entry\");\n let highest = Math.max(oplog.highest ?? 0, held ?? 0);\n let from: OplogTime = oplog.last;\n const backups: RunBackup[] = [{ kind: \"dump\", started, ended, last: writeOf(writer.events, highest), size: await sizeOf(lab, `${VAULT}/dump-0`) }];\n const every = valueIn(drill.sliceEvery, \"s\") * 1_000;\n for (let slice = 1; slice <= drill.slices; slice += 1) {\n await sleep(Math.max(0, ended + slice * every - Date.now()));\n const out = `${VAULT}/slice-${slice}`;\n const begun = Date.now();\n await lab.vault([\"mongodump\", \"--host\", host, \"--db\", \"local\", \"--collection\", \"oplog.rs\", \"--query\", sliceQuery(from), \"--out\", out]);\n const finished = Date.now();\n const read = readOplog(await lab.vault([\"bsondump\", \"--quiet\", `${out}/local/oplog.rs.bson`]));\n highest = Math.max(highest, read.highest ?? 0);\n from = read.last ?? from;\n backups.push({ kind: \"slice\", started: begun, ended: finished, last: writeOf(writer.events, highest), size: await sizeOf(lab, out) });\n }\n return backups;\n};\n\n/**\n * This function stops the server of each member that the drill loses, and it removes each disk. A\n * restore loses each member, and an election loses the primary. The fault comes at the age of the\n * drill after the last write of the newest backup. A control has no later write, and an election\n * has no backup: their age counts from this point. The stamp is the one of the primary.\n */\nconst lose = async (lab: ReplicaSetLab, drill: Drill, primary: string, last: RunBackup[\"last\"]): Promise<Stamp> => {\n const parts = drill.recovery === \"restore\" ? [primary, ...lab.set.members.filter((name) => name !== primary)] : [primary];\n const age = valueIn(drill.age, \"s\");\n const at = last === null || drill.quiet === true ? undefined : last.t + age * 1e9;\n if (at === undefined) await sleep(age * 1_000);\n const stamps = await Promise.all(parts.map((part) => lab.signal(part, \"KILL\", at)));\n for (const part of parts) {\n await lab.exec(part, [\"sh\", \"-c\", stopScript(false)]);\n await lab.exec(part, [\"find\", \"/data/db\", \"-mindepth\", \"1\", \"-delete\"]);\n }\n return stamps[0]!;\n};\n\n/**\n * This function restores the old primary from the backups and starts the set again:\n * - The slices go after the oplog of the dump, in their sequence, thus one replay does the whole restore.\n * - The restore writes to a server of the old primary with no set, on its own port.\n * - Each member that lost its disk starts before the set, because `rs.initiate` asks each member.\n * - The old primary starts the set. It has the data, and the other members make their first sync from it.\n */\nconst restore = async (lab: ReplicaSetLab, drill: Drill, primary: string): Promise<{ started: number; ended: number }> => {\n const { set } = lab;\n const started = Date.now();\n const port = set.port + 1;\n const slices = Array.from({ length: drill.slices }, (_, at) => `${VAULT}/slice-${at + 1}/local/oplog.rs.bson`);\n if (slices.length > 0) await lab.vault([\"sh\", \"-c\", `cat ${slices.join(\" \")} >> ${VAULT}/dump-0/oplog.bson`]);\n await lab.exec(primary, [\"sh\", \"-c\", `${standaloneCommand(set, port)} > /proc/1/fd/1 2>&1 & echo $! > /tmp/server.pid`]);\n await until(\"the server of the restore\", async () => (await lab.script(primary, \"print(db.hello().ok)\", port)).includes(\"1\"), STARTS_WITHIN);\n await lab.vault([\"mongorestore\", \"--host\", `${lab.members[primary]!.ip}:${port}`, \"--oplogReplay\", `${VAULT}/dump-0`]);\n await lab.exec(primary, [\"sh\", \"-c\", stopScript(true)]);\n for (const name of set.members) if (name !== primary) await lab.restart(name);\n await lab.restart(primary);\n const ips = Object.fromEntries(Object.entries(lab.members).map(([name, at]) => [name, at.ip]));\n const initiated = await lab.script(primary, initiateScript(set, ips));\n if (!initiated.includes('\"ok\":1')) throw new Error(`rs.initiate failed after the restore: ${initiated}`);\n await until(\"the primary after the restore\", async () => (await lab.script(primary, \"print(db.hello().isWritablePrimary)\")).includes(\"true\"), STARTS_WITHIN);\n return { started, ended: Date.now() };\n};\n\n/**\n * This function does one run of a recovery drill:\n * - The set converges, and it loses its writes. The tenants get their data, and a hash reads it.\n * - The client writes until its stream is steady. A control stops it here.\n * - The backups go, each at its interval. The fault comes at the age of the newest backup.\n * - An election continues the same client. A restore stops the client, and it starts a second one.\n * - The set converges again. The writes that it then holds tell which writes it kept, and a second\n * hash tells if the tenants have the same data.\n */\nexport const drillOnce = async (lab: ReplicaSetLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const drill = cell.drill!;\n const { set } = lab;\n const primary = await lab.converge();\n await lab.flush(primary);\n await lab.unfreeze(primary);\n await lab.forget();\n await lab.vault([\"sh\", \"-c\", `rm -rf ${VAULT} && mkdir -p ${VAULT}`]);\n const seeded = await lab.script(primary, seedScript(drill, set.members.length));\n if (!seeded.includes('\"ok\":true')) throw new Error(`the seed failed: ${seeded}`);\n const before = hashOf(await lab.script(primary, HASH_SCRIPT));\n const tool = (await lab.vault([\"mongodump\", \"--version\"])).split(\"\\n\")[0]!.trim();\n const from = lab.kernel.length;\n const logFrom = lab.log.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const writer = await lab.client(replicaSetArgs(cell, lab.members));\n const restores = drill.recovery === \"restore\";\n let successor: GroupClient | null = null;\n let second: number | null = null;\n let fault: Run[\"fault\"] = null;\n let restored: { started: number; ended: number } | null = null;\n const backups: RunBackup[] = [];\n try {\n await writer.until([\"ready\"], 60_000);\n const steady = await waitFor(writer, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not write ${STEADY} times in 30 s`);\n if (drill.quiet === true) await writer.stop();\n if (restores) backups.push(...(await backupsOf(lab, drill, primary, writer)));\n const stamp = await lose(lab, drill, primary, backups.at(-1)?.last ?? null);\n fault = stamp;\n if (restores) {\n await writer.stop();\n restored = await restore(lab, drill, primary);\n second = Math.max(0, ...writer.events.filter((event) => event.ev === \"sent\").map((event) => Number(event[\"n\"]))) + 1;\n successor = await lab.client([...replicaSetArgs(cell, lab.members), \"--from\", String(second)]);\n const answered = await waitFor(successor, (event) => event.ev === \"ack\", deadlineOf(cell));\n if (answered !== undefined) await sleep(TAIL_MS);\n } else {\n const old = `${lab.members[primary]!.ip}:${set.port}`;\n const sentAt = (n: number): number => writer.events.find((event) => event.ev === \"sent\" && Number(event[\"n\"]) === n)?.t ?? -Infinity;\n const answered = await waitFor(\n writer,\n (event) => event.ev === \"ack\" && sentAt(Number(event[\"n\"])) > stamp.t1 && typeof event[\"at\"] === \"string\" && event[\"at\"] !== old,\n deadlineOf(cell),\n );\n if (answered !== undefined) await sleep(TAIL_MS);\n await lab.restart(primary);\n }\n } finally {\n await writer.stop();\n await successor?.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge().catch(() => null);\n const holds = after === null ? null : await lab.holds(after);\n const hash = after === null ? null : hashOf(await lab.script(after, HASH_SCRIPT));\n const events = [...writer.events, ...(successor?.events ?? [])].sort((a, b) => a.t - b.t);\n return {\n environment,\n index,\n events,\n fault,\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[primary]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: {},\n primary,\n at: primary,\n timeline: onMonotonic(lab.log.slice(logFrom), clockOffsetOf(events)),\n after,\n holds,\n drill: { tool, seed: \"generated\", backups, before, after: hash, restored, second },\n },\n };\n};\n","import type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, Cluster, GroupPlace, GroupRole, KernelRecord, ProbeEvent, Run, RunPart, SentinelEvent } from \"./cell.ts\";\nimport type { GroupClient, GroupNetworkFault, GroupView, Stamp } from \"./group.ts\";\nimport { CONVERGE_MS, deadlineOf } from \"./group.ts\";\nimport { amqpClientImage, harnessImage } from \"./image.ts\";\nimport type { Manifest } from \"./lab.ts\";\nimport { STOP, containers, harnessRecord, lines, netnsOf, output, shippedClientRecord, withPid } from \"./lab.ts\";\nimport type { Cut } from \"./replset.ts\";\nimport { clockOffsetOf } from \"./replset.ts\";\nimport { substrateHere } from \"./substrate.ts\";\n\n/**\n * This module is the lab of a cluster of RabbitMQ with one quorum queue. The members of the queue\n * elect its leader by Raft, one member on each node. It opens one environment for a cluster cell,\n * for the runs of the cell. Each node is a container from the stock image of the cluster, in its own\n * network namespace. An injector sidecar shares its network and process namespaces.\n *\n * The client of each run is amqplib. It publishes a stream of sequence numbers with confirms through\n * one node, and it connects to the next node when its connection ends. The timeline comes from\n * the log of each node and from the lines of the client. The prober watches the namespace of the client.\n */\n\n/**\n * A node line is one log line of a node, as RabbitMQ writes it to its console. `real` is its time on\n * the wall clock in ms, with its microseconds. `t` is its time on the monotonic clock: the run gives\n * it from the clock lines of its client.\n */\nexport interface NodeLine extends SentinelEvent {\n readonly ev: \"rabbit\";\n readonly member: string;\n readonly real: number;\n readonly level: string;\n readonly msg: string;\n}\n\n/** This form is a line of the console log of RabbitMQ 4.3: the time with its offset, the level, the process and the message. */\nconst LINE = /^(\\d{4}-\\d\\d-\\d\\d) (\\d\\d:\\d\\d:\\d\\d)\\.(\\d{3})(\\d*)([+-]\\d\\d:\\d\\d) \\[(\\w+)\\] <[^>]*> (.*)$/;\n\n/** This form is an escape of ANSI: RabbitMQ colors each line of its console by its level. */\nconst ANSI = new RegExp(String.fromCharCode(27) + \"\\\\[[0-9;]*m\", \"g\");\n\n/** This function gives a line of the console without its colors. */\nexport const plainOf = (text: string): string => text.replace(ANSI, \"\").trim();\n\n/** This text is the name of a quorum queue in the log of Ra: its friendly name. */\nexport const logNameOf = (queue: string): string => `queue '${queue}' in vhost '/'`;\n\n/**\n * This function reads one log line of a node, or gives null for a line that a run does not keep. A\n * run keeps each line of the queue, each warning and each error, and each line of the maintenance\n * mode of a drain.\n */\nexport const nodeLineOf = (member: string, text: string, queue: string): NodeLine | null => {\n const found = LINE.exec(plainOf(text));\n if (found === null) return null;\n const [, day, time, ms, us, offset, level, msg] = found as unknown as [string, string, string, string, string, string, string, string];\n const kept = msg.includes(logNameOf(queue)) || level === \"warning\" || level === \"error\" || msg.includes(\"maintenance\");\n if (!kept) return null;\n const real = Date.parse(`${day}T${time}.${ms}${offset}`) + (us === \"\" ? 0 : Number(`0.${us}`));\n if (!Number.isFinite(real)) return null;\n return { ev: \"rabbit\", t: 0, member, real, level, msg };\n};\n\n/** This function puts the log lines of the nodes on the monotonic clock, with the offset of a client. */\nexport const nodesOnMonotonic = (log: readonly NodeLine[], offset: number | null): NodeLine[] =>\n log.map((line) => ({ ...line, t: offset === null ? 0 : Math.round(line.real * 1e6 - offset) }));\n\n/**\n * This function reads the JSON output of a tool of RabbitMQ (`--formatter json`). The tools print a\n * value over one line or over more than one, thus it reads from the first bracket to the end.\n */\nexport const toolJsonOf = (text: string): unknown => {\n const at = text.search(/[[{]/);\n if (at === -1) throw new Error(`no JSON in the output: ${text.slice(0, 200)}`);\n return JSON.parse(text.slice(at));\n};\n\n/** This function gives the name of a node in the Erlang distribution: `rabbit@<name>`. */\nexport const nodeNameOf = (member: string): string => `rabbit@${member}`;\n\n/**\n * This function gives the file of rabbitmq.conf of each node. The nodes form the cluster from the list\n * of their names, and the user guest connects from each address. The lines of the cluster come last.\n */\nexport const clusterConf = (cluster: Cluster): string =>\n [\n \"cluster_formation.peer_discovery_backend = classic_config\",\n ...cluster.members.map((name, at) => `cluster_formation.classic_config.nodes.${at + 1} = ${nodeNameOf(name)}`),\n \"loopback_users.guest = false\",\n ...cluster.conf,\n \"\",\n ].join(\"\\n\");\n\n/**\n * This function gives the command of each node. It writes the cookie of the server and of the tools.\n * Then it starts the server as the child of a shell. A fin can then stop the server, and the container\n * stays up.\n */\nexport const nodeCommand = (cluster: Cluster): string =>\n [\n \"for f in /var/lib/rabbitmq/.erlang.cookie /root/.erlang.cookie; do cp /tmp/cookie $f; chmod 400 $f; done\",\n \"chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie\",\n // a command in the background ends with its &, and the shell takes no ; after it\n `${cluster.programs.start} & while :; do sleep 3600; done`,\n ].join(\"; \");\n\n/** A status row is one member of the queue in the output of `rabbitmq-queues quorum_status`. */\nexport interface StatusRow {\n readonly \"Node Name\": string;\n readonly \"Raft State\": string;\n readonly Term: number | string;\n readonly \"Commit Index\": number | string;\n}\n\n/**\n * This function judges the status of the queue: its leader, and if the queue is healthy. A healthy\n * queue has one leader and a follower on each other node. Each follower is in the term of the leader,\n * at the commit index of the leader.\n */\nexport const clusterViewOf = (cluster: Cluster, rows: readonly StatusRow[]): GroupView => {\n const byNode = new Map(cluster.members.map((name) => [nodeNameOf(name), name]));\n const leaders = rows.filter((row) => row[\"Raft State\"] === \"leader\");\n if (leaders.length !== 1) return { primary: null, healthy: false, why: `the queue has ${leaders.length} leaders` };\n const leader = leaders[0]!;\n const primary = byNode.get(leader[\"Node Name\"]) ?? null;\n if (primary === null) return { primary: null, healthy: false, why: `no node has the name ${leader[\"Node Name\"]}` };\n if (rows.length !== cluster.members.length) return { primary, healthy: false, why: `the queue has ${rows.length} members` };\n for (const row of rows) {\n if (row !== leader && row[\"Raft State\"] !== \"follower\") return { primary, healthy: false, why: `${row[\"Node Name\"]} is ${row[\"Raft State\"]}` };\n if (row.Term !== leader.Term) return { primary, healthy: false, why: `${row[\"Node Name\"]} is in term ${row.Term}` };\n if (row[\"Commit Index\"] !== leader[\"Commit Index\"]) return { primary, healthy: false, why: `${row[\"Node Name\"]} is behind the leader` };\n }\n return { primary, healthy: true, why: \"healthy\" };\n};\n\n/**\n * This function gives the peers that a fault on a node cuts it from. `all` is each other node and the\n * client, `group` is the other nodes, and `clients` is the client. `one` is the first other node in\n * the sequence of the cluster, and `one-way` is the same node for the segments from the part only.\n * `to-clients` is the client, for the segments from the part only.\n */\nexport const clusterCutOf = (\n cluster: Cluster,\n members: Readonly<Record<string, RunPart>>,\n client: string,\n part: string,\n cuts: NonNullable<GroupPlace[\"cuts\"]>,\n): Cut => {\n const others = cluster.members.filter((name) => name !== part).map((name) => members[name]!.ip);\n if (cuts === \"clients\") return { peers: [client] };\n if (cuts === \"group\") return { peers: others };\n if (cuts === \"one\") return { peers: others.slice(0, 1) };\n if (cuts === \"one-way\") return { peers: others.slice(0, 1), direction: \"out\" };\n if (cuts === \"to-clients\") return { peers: [client], direction: \"out\" };\n return { peers: [...others, client] };\n};\n\n/** A wall stamp is the wall clock in ns around a command of a node: the run puts it on the monotonic clock. */\nexport interface WallStamp {\n readonly wall0: number;\n readonly wall1: number;\n}\n\n/** A cluster lab is one environment of a cluster cell. */\nexport interface ClusterLab {\n readonly cluster: Cluster;\n readonly clientIp: string;\n readonly members: Readonly<Record<string, RunPart>>;\n readonly netns: { readonly client: number };\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** These are the log lines of the nodes that a run keeps, in the sequence of their arrival, with `t` at 0. */\n readonly log: readonly NodeLine[];\n /** These are the last raw lines of the console of each node, for the diagnosis of a lab: at most RAW_TAIL of each. */\n readonly raw: Readonly<Record<string, readonly string[]>>;\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method waits until the queue is whole and calm, and gives the name of the node of its leader. */\n converge(within?: number): Promise<string>;\n /** This method removes each message from the queue. */\n flush(leader: string): Promise<void>;\n /** This method gives the sequence numbers that the queue holds, through the node of its leader. The queue is empty after it. */\n holds(leader: string): Promise<number[]>;\n /** This method gives the node that has a role, when `leader` is the node of the leader. The role is the leader, or a follower. */\n partOf(role: GroupRole, leader: string): string;\n /** This method starts the client of a run, with the arguments of `client-cluster.mjs`. */\n client(args: readonly string[]): Promise<GroupClient>;\n /** This method applies a network fault between a node and some of its peers, at once or at an instant of the VM. */\n fault(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes a network fault, at once or at an instant of the VM. */\n lift(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method sends a signal to the server process of a node, at once or at an instant of the VM. */\n signal(part: string, signal: \"KILL\" | \"STOP\" | \"CONT\", at?: number): Promise<Stamp>;\n /** This method starts the server of a node again, after a fin. */\n restart(member: string): Promise<void>;\n /** This method moves the leadership of the queue from the node of `leader` to the node `to`: `rabbitmq-queues transfer_leadership`. */\n stepDown(leader: string, to: string): Promise<WallStamp>;\n /** This method puts a node in maintenance mode (`rabbitmq-upgrade drain`). */\n drain(member: string): Promise<WallStamp>;\n /** This method ends the maintenance mode of a node (`rabbitmq-upgrade revive`). */\n revive(member: string): Promise<void>;\n /** This method removes the TCP metrics of the client namespace: each run starts from a kernel that keeps nothing. */\n forget(): Promise<void>;\n /** This method waits for the next clock line of the prober, which gives the count of lost records. */\n settle(): Promise<number | null>;\n manifest(sysctls: Readonly<Record<string, string>>): Promise<Manifest>;\n close(): Promise<void>;\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** This count is the number of raw lines of the console of each node that a lab keeps. */\nexport const RAW_TAIL = 400;\n\n/**\n * This function opens one environment of a cluster cell:\n * - one new network, with each node, the client and the admin on it.\n * - each node: the stock image, its server as the child of a shell, with its hostname as the name of\n * the node. A log consumer reads its console. The nodes form the cluster from the list of their\n * names, and the lab waits until each node runs in it.\n * - the admin declares the quorum queue on the first node, thus its member there is the first leader.\n * - an injector sidecar for each node, in its network and process namespaces.\n * - a client that holds its own network namespace, with a privileged sidecar for its sysctls.\n * - the prober, which watches the namespace of the client.\n */\nexport const openClusterLab = async (cluster: Cluster): Promise<ClusterLab> => {\n const image = await harnessImage();\n const amqp = await amqpClientImage();\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n let network: StartedNetwork | undefined;\n const close = async () => {\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n await network?.stop().catch(() => undefined);\n };\n const ipOf = async (container: StartedTestContainer): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network!.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network!.getName()}`);\n return ip;\n };\n try {\n network = await new Network().start();\n const boxes = new Map<string, StartedTestContainer>();\n const injectors = new Map<string, StartedTestContainer>();\n const members: Record<string, RunPart> = {};\n const log: NodeLine[] = [];\n const raw: Record<string, string[]> = {};\n for (const name of cluster.members) {\n let partial = \"\";\n const box = await new GenericContainer(cluster.image)\n .withNetwork(network)\n .withNetworkAliases(name)\n .withHostname(name)\n .withCopyContentToContainer([\n { content: clusterConf(cluster), target: \"/etc/rabbitmq/conf.d/90-harness.conf\" },\n { content: cluster.cookie, target: \"/tmp/cookie\" },\n ])\n .withCommand([\"sh\", \"-c\", nodeCommand(cluster)])\n .withWaitStrategy(Wait.forLogMessage(cluster.ready))\n .withStartupTimeout(180_000)\n .withLogConsumer((stream) =>\n stream.on(\"data\", (chunk: Buffer | string) => {\n partial += chunk.toString();\n const split = partial.split(\"\\n\");\n partial = split.pop() ?? \"\";\n for (const text of split) {\n const tail = (raw[name] ??= []);\n tail.push(text);\n if (tail.length > RAW_TAIL) tail.shift();\n const line = nodeLineOf(name, text.trim(), cluster.queue);\n if (line !== null) log.push(line);\n }\n }),\n )\n .start();\n opened.push(box);\n boxes.set(name, box);\n const injector = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${box.getId()}`,\n ).start();\n opened.push(injector);\n injectors.set(name, injector);\n members[name] = { ip: await ipOf(box), netns: await netnsOf(injector) };\n }\n\n const holder = await new GenericContainer(image).withNetwork(network).start();\n opened.push(holder);\n const admin = await new GenericContainer(image).withNetworkMode(`container:${holder.getId()}`).withPrivilegedMode().start();\n opened.push(admin);\n const clientIp = await ipOf(holder);\n // the admin of the queue is a client of its own, on the network but not in the watched namespace\n const commander = await new GenericContainer(amqp)\n .withNetwork(network)\n .withCommand([\"sh\", \"-c\", \"while :; do sleep 3600; done\"])\n .start();\n opened.push(commander);\n\n const clientNetns = await netnsOf(admin);\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\"/opt/harness/prober\", String(clientNetns)])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n\n const box = (name: string): StartedTestContainer => {\n const found = boxes.get(name);\n if (found === undefined) throw new Error(`the cluster has no node ${name}`);\n return found;\n };\n const injectorOf = (name: string): StartedTestContainer => {\n const found = injectors.get(name);\n if (found === undefined) throw new Error(`the cluster has no node ${name}`);\n return found;\n };\n const lastLine = (text: string): string => text.split(\"\\n\").filter((line) => line.trim() !== \"\").at(-1) ?? \"\";\n const stamped = async (where: StartedTestContainer, argv: string[]): Promise<Stamp> => {\n const stamp = JSON.parse(lastLine(await output(where, argv))) as Stamp;\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const after = (at: number | undefined): string[] => (at === undefined ? [] : [\"--at\", String(Math.round(at))]);\n /** This function runs a command of the tools of RabbitMQ on a node, between two stamps of its wall clock. */\n const walled = async (name: string, command: string): Promise<WallStamp> => {\n const text = await output(box(name), [\"sh\", \"-c\", `date +%s%N; ${command} >&2; date +%s%N`]);\n const stamps = text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => /^\\d{18,}$/.test(line))\n .map(Number);\n if (stamps.length < 2) throw new Error(`${name}: no stamps around ${command}: ${text.slice(0, 300)}`);\n return { wall0: stamps[0]!, wall1: stamps.at(-1)! };\n };\n const status = async (name: string): Promise<GroupView> => {\n const text = await output(box(name), [\"rabbitmq-queues\", \"-q\", \"quorum_status\", cluster.queue, \"--formatter\", \"json\"]);\n return clusterViewOf(cluster, toolJsonOf(text) as StatusRow[]);\n };\n let known: string = cluster.members[0]!;\n /** This function gives the view of the queue: from the node that had the leader last, then from each other node. */\n const view = async (): Promise<GroupView> => {\n let last: GroupView = { primary: null, healthy: false, why: \"no node answered\" };\n for (const name of [known, ...cluster.members.filter((each) => each !== known)]) {\n const read = await status(name).catch((error: unknown) => ({ primary: null, healthy: false, why: `${name}: ${(error as Error).message.slice(0, 200)}` }));\n if (read.primary !== null) return read;\n last = read;\n }\n return last;\n };\n const converge = async (within = CONVERGE_MS): Promise<string> => {\n const started = Date.now();\n let calm = 0;\n let last: GroupView = { primary: null, healthy: false, why: \"no view yet\" };\n while (Date.now() - started < within) {\n last = await view();\n // two healthy views in a row: one view can come in the middle of a change\n calm = last.healthy ? calm + 1 : 0;\n if (last.primary !== null) known = last.primary;\n if (calm >= 2 && last.primary !== null) return last.primary;\n await sleep(1_000);\n }\n throw new Error(`the queue did not converge in ${within} ms: ${last.why}`);\n };\n\n // each node runs in the cluster, and then the first node declares the queue\n const started = Date.now();\n for (;;) {\n const text = await output(box(cluster.members[0]!), [\"rabbitmq-diagnostics\", \"-q\", \"cluster_status\", \"--formatter\", \"json\"]).catch(() => \"{}\");\n const running = ((text.trim() === \"\" ? {} : toolJsonOf(text)) as { running_nodes?: string[] }).running_nodes ?? [];\n if (cluster.members.every((name) => running.includes(nodeNameOf(name)))) break;\n if (Date.now() - started > 120_000) throw new Error(`the cluster did not form in 120 s: ${running.join(\", \")} run`);\n await sleep(1_000);\n }\n const declared = lastLine(await output(commander, [\"node\", \"/opt/harness/amqp/admin-cluster.mjs\", `${members[cluster.members[0]!]!.ip}:${cluster.port}`, \"declare\", cluster.queue]));\n if (!declared.includes('\"ok\":true')) throw new Error(`the declare of the queue failed: ${declared}`);\n await converge();\n\n return {\n cluster,\n clientIp,\n members,\n netns: { client: clientNetns },\n kernel: records.seen,\n log,\n raw,\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values)) read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n converge,\n async flush(leader) {\n await output(box(leader), [\"rabbitmqctl\", \"-q\", \"purge_queue\", cluster.queue]);\n },\n async holds(leader) {\n const reply = lastLine(await output(commander, [\"node\", \"/opt/harness/amqp/admin-cluster.mjs\", `${members[leader]!.ip}:${cluster.port}`, \"holds\", cluster.queue]));\n const held = (JSON.parse(reply) as { held?: unknown[] }).held;\n if (held === undefined) throw new Error(`the read of the queue failed: ${reply}`);\n return held.map(Number).filter((n) => Number.isInteger(n) && n > 0);\n },\n partOf(role, leader) {\n if (role === \"primary\") return leader;\n if (role === \"sentinel\") throw new Error(\"a cluster has no Sentinel\");\n const follower = cluster.members.find((name) => name !== leader);\n if (follower === undefined) throw new Error(\"the cluster has no follower\");\n return follower;\n },\n async client(args) {\n const events = lines<ProbeEvent>();\n const container = await new GenericContainer(amqp)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"node\", \"/opt/harness/amqp/client-cluster.mjs\", ...args])\n .withLogConsumer(events.consume)\n .start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n // a TERM first: the client writes its done line, then stops\n stop: () =>\n container\n .stop({ timeout: 2 })\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n fault(kind, part, cuts, at) {\n const cut = clusterCutOf(cluster, members, clientIp, part, cuts);\n const direction = cut.direction === undefined ? [] : [\"--direction\", cut.direction];\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind, cut.peers.join(\",\"), ...direction, ...after(at)]);\n },\n lift(kind, part, cuts, at) {\n const cut = clusterCutOf(cluster, members, clientIp, part, cuts);\n const direction = cut.direction === undefined ? [] : [\"--direction\", cut.direction];\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind === \"rst\" ? \"clear-rst\" : \"clear\", cut.peers.join(\",\"), ...direction, ...after(at)]);\n },\n signal(part, signal, at) {\n return stamped(injectorOf(part), [\"/opt/harness/inject\", \"signal\", cluster.programs.server, signal, ...after(at)]);\n },\n async restart(member) {\n // the restarted server writes to the output of the container, thus its log consumer reads it\n await output(box(member), [\"sh\", \"-c\", `${cluster.programs.start} > /proc/1/fd/1 2>&1 &`]);\n const begun = Date.now();\n while (!(await output(box(member), [\"rabbitmq-diagnostics\", \"-q\", \"check_running\"]).then(() => true).catch(() => false))) {\n if (Date.now() - begun > 120_000) throw new Error(`${member} did not start again`);\n await sleep(1_000);\n }\n },\n stepDown(leader, to) {\n return walled(leader, `rabbitmq-queues -q transfer_leadership ${cluster.queue} ${nodeNameOf(to)}`);\n },\n drain(member) {\n return walled(member, \"rabbitmq-upgrade -q drain\");\n },\n async revive(member) {\n await output(box(member), [\"rabbitmq-upgrade\", \"-q\", \"revive\"]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n async settle() {\n const from = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const begun = Date.now();\n const look = () => {\n const line = records.seen.slice(from).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - begun > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) => runtime.container.inspect(runtime.container.getById(container.getId()));\n const list = [];\n for (const name of cluster.members) {\n const version = lastLine(await output(box(name), [\"rabbitmqctl\", \"-q\", \"version\"]).catch(() => \"\"));\n list.push({ name, ip: members[name]!.ip, id: (await inspect(box(name))).Image, settings: { version, conf: cluster.conf.join(\"; \") } });\n }\n return {\n kernel: await output(holder, [\"uname\", \"-r\"]),\n architecture: await output(holder, [\"uname\", \"-m\"]),\n hz: /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1] ?? null,\n boot_id: await output(holder, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n substrate: substrateHere(\"E1\"),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n target: { image: cluster.image, id: list[0]!.id, settings: list[0]!.settings, sysctls: {} },\n harness: {\n image,\n id: (await inspect(holder)).Image,\n packages: (await output(holder, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n ...harnessRecord(),\n },\n client: shippedClientRecord(\"amqp\", amqp),\n netns: { client: clientNetns, target: members[cluster.members[0]!]!.netns },\n sysctls,\n group: { members: list, sentinels: [], observer: { image: amqp } },\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n\n// ---------------------------------------------------------------------------------------------\n// the runs of a cluster cell\n// ---------------------------------------------------------------------------------------------\n\n/** This count is the number of confirmed publishes that a run waits for before its fault: the stream is steady then. */\nconst STEADY = 20;\n/** This time is how long a run continues after its outcome, so that the record shows what came next. */\nconst TAIL_MS = 2_000;\n\n/**\n * This function gives the hosts of the client, in the sequence of its connects: its node first, then\n * each other node. The node of a follower is the last follower in the sequence of the cluster. A fault\n * on one member (`one`, `one-way`) cuts the first follower, thus not the node of the client.\n */\nexport const clusterHostsOf = (cell: Cell, members: Readonly<Record<string, RunPart>>, leader: string): string[] => {\n const cluster = cell.cluster!;\n const first = cell.clientAt === \"leader\" ? leader : cluster.members.filter((name) => name !== leader).at(-1)!;\n return [first, ...cluster.members.filter((name) => name !== first)].map((name) => `${members[name]!.ip}:${cluster.port}`);\n};\n\n/** This form is the NOTICE of a leader of the queue that starts to give its leadership away: to await_condition, for a transfer. */\nexport const GIVES_AWAY: RegExp = /: leader -> await_condition in term/;\n/** This form is the INFO of a follower whose monitor of the leader goes down (ra_server_proc.erl:871). A drain stops the leader so. */\nexport const MONITOR_DOWN: RegExp = /Leader monitor down/;\n\n/** This function gives the arguments of the client of a cluster cell: its hosts, the queue, and the stream of publishes. */\nexport const clusterArgs = (cell: Cell, members: Readonly<Record<string, RunPart>>, leader: string): string[] => [\n clusterHostsOf(cell, members, leader).join(\",\"),\n \"--queue\",\n cell.cluster!.queue,\n \"--interval-ms\",\n String(cell.probe.interval === undefined ? 50 : valueIn(cell.probe.interval, \"ms\")),\n \"--max-s\",\n String(Math.ceil(deadlineOf(cell) / 1_000 + (cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\")) + 120)),\n ...(cell.driverOptions === undefined ? [] : [\"--options\", JSON.stringify(cell.driverOptions)]),\n];\n\n/** This function waits until a condition on the lines of the client holds, or for `within` ms. It gives the first line that matches. */\nconst waitFor = (client: GroupClient, match: (event: ProbeEvent) => boolean, within: number): Promise<ProbeEvent | undefined> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const found = client.events.find(match);\n if (found !== undefined || Date.now() - started > within) resolve(found);\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1) if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/** This function puts a wall stamp on the monotonic clock, with the clock lines of the client. Without one it gives null. */\nexport const monotonicOf = (stamp: WallStamp, events: readonly ProbeEvent[]): Stamp | null => {\n const offset = clockOffsetOf(events);\n return offset === null ? null : { t0: Math.round(stamp.wall0 - offset), t1: Math.round(stamp.wall1 - offset) };\n};\n\n/**\n * This function gives the instant of a change of the leader that a command of the tools starts, as the\n * stamps of a fault. The command starts an Erlang VM first, thus its stamps hold more than the change.\n * A line of the log marks the start of the change. For a step-down it is the NOTICE of the old leader\n * (ra_server_proc.erl:1336-1345), and for a drain the INFO of a follower. Its time on the monotonic\n * clock is the stamp. Without that line, the stamps of the command are the stamps.\n */\nconst stampOf = async (\n lab: ClusterLab,\n client: GroupClient,\n logFrom: number,\n marks: (line: NodeLine) => boolean,\n wall: WallStamp,\n): Promise<{ readonly stamp: Stamp | null; readonly line: NodeLine | null }> => {\n const started = Date.now();\n while (Date.now() - started < 5_000) {\n const lines = nodesOnMonotonic(lab.log.slice(logFrom), clockOffsetOf(client.events));\n const line = lines.find(marks);\n if (line !== undefined && line.t > 0) return { stamp: { t0: line.t, t1: line.t }, line };\n await sleep(100);\n }\n return { stamp: monotonicOf(wall, client.events), line: null };\n};\n\n/**\n * This function puts the stamp of a fault from a line of the log on the monotonic clock again. It uses\n * the offset of all the clock lines of the client, as the timeline of the run does. Thus the line of the\n * stamp is at the stamp. The offset of the clock lines at the fault can be up to 1 ms smaller.\n */\nexport const restamped = (line: NodeLine, events: readonly ProbeEvent[]): Stamp | null => {\n const [on] = nodesOnMonotonic([line], clockOffsetOf(events));\n return on === undefined || on.t <= 0 ? null : { t0: on.t, t1: on.t };\n};\n\n/**\n * This function does one run of a cluster cell:\n * - The queue converges, and it is empty. The client connects through its node, and its stream of\n * publishes gets steady.\n * - The fault occurs on its node, as the leader of this run makes the roles. A fault with a hold\n * lifts at its instant in the VM. A step-down moves the leadership to a follower, and a drain puts\n * the node in maintenance mode. The stamp of each of them is a line of the log (`stampOf`).\n * - The run waits for its outcome: the first confirm of a publish sent after the commit of the fault.\n * Then it waits for the end of the hold, thus the record shows what the cluster did in the whole hold.\n * - Each fault goes, the client stops, and the queue converges again. The sequence numbers that it\n * then holds tell which publishes it kept. The log lines of the nodes go onto the monotonic clock.\n */\nexport const clusterOnce = async (lab: ClusterLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const leader = await lab.converge();\n await lab.flush(leader);\n await lab.forget();\n const from = lab.kernel.length;\n const logFrom = lab.log.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const client = await lab.client(clusterArgs(cell, lab.members, leader));\n const place = (cell.faultAt ?? { role: \"primary\" }) as GroupPlace;\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n let at: string | null = null;\n let wall: WallStamp | null = null;\n // the line of the log that gives the stamp of a step-down or of a drain\n let stampLine: NodeLine | null = null;\n const undo: Array<() => Promise<unknown>> = [];\n try {\n await client.until([\"ready\"], 60_000);\n const steady = await waitFor(client, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not publish ${STEADY} times in 30 s`);\n let healing: Promise<Run[\"heal\"]> | null = null;\n switch (cell.fault) {\n case \"blackhole\":\n case \"partition\":\n case \"rst\": {\n const kind = cell.fault === \"rst\" ? \"rst\" : \"blackhole\";\n const cuts = place.cuts ?? (cell.fault === \"partition\" ? \"group\" : \"all\");\n const part = lab.partOf(place.role, leader);\n at = part;\n fault = await lab.fault(kind, part, cuts);\n undo.push(() => lab.lift(kind, part, cuts));\n if (cell.hold !== undefined) healing = lab.lift(kind, part, cuts, fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n break;\n }\n case \"freeze-process\": {\n const part = lab.partOf(place.role, leader);\n at = part;\n fault = await lab.signal(part, \"STOP\");\n undo.push(() => lab.signal(part, \"CONT\"));\n if (cell.hold !== undefined) healing = lab.signal(part, \"CONT\", fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n break;\n }\n case \"fin\": {\n const part = lab.partOf(place.role, leader);\n at = part;\n fault = await lab.signal(part, \"KILL\");\n undo.push(() => lab.restart(part));\n break;\n }\n case \"step-down\": {\n at = leader;\n wall = await lab.stepDown(leader, lab.partOf(\"replica\", leader));\n ({ stamp: fault, line: stampLine } = await stampOf(lab, client, logFrom, (line) => line.member === leader && GIVES_AWAY.test(line.msg), wall));\n break;\n }\n case \"drain\": {\n const part = lab.partOf(place.role, leader);\n at = part;\n wall = await lab.drain(part);\n undo.push(() => lab.revive(part));\n // a drain stops the member of the leader (rabbit_quorum_queue.erl:2787-2838): a follower sees its monitor go down\n ({ stamp: fault, line: stampLine } = await stampOf(lab, client, logFrom, (line) => line.member !== part && MONITOR_DOWN.test(line.msg), wall));\n break;\n }\n default:\n throw new Error(`a cluster cell has no fault ${cell.fault}`);\n }\n if (fault === null) throw new Error(\"the client wrote no clock line: the stamps of the command have no place on the monotonic clock\");\n // the injector holds the lift in the VM: its exec returns at the instant, and the stamps come with it\n const healed =\n healing === null\n ? Promise.resolve(null)\n : healing.then((stamp) => {\n heal = stamp;\n // the lift came: nothing is left to undo\n undo.length = 0;\n return stamp;\n });\n // a run that stops early lifts the fault itself, and the late lift then has nothing to remove\n healed.catch(() => undefined);\n const t1 = fault.t1;\n const sentAt = (n: number): number => client.events.find((event) => event.ev === \"sent\" && Number(event[\"n\"]) === n)?.t ?? -Infinity;\n const outcome = await waitFor(client, (event) => event.ev === \"ack\" && sentAt(Number(event[\"n\"])) > t1, deadlineOf(cell));\n if (outcome !== undefined) await sleep(TAIL_MS);\n // the whole hold: a prediction that reads the cluster in each moment of it\n if (healing !== null) {\n await healed.catch(() => undefined);\n await sleep(TAIL_MS);\n }\n } finally {\n // each fault that is still on goes, and a killed server starts again\n for (const step of undo.reverse()) await step().catch(() => undefined);\n await client.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge().catch(() => null);\n const holds = after === null ? null : await lab.holds(after);\n return {\n environment,\n index,\n events: [...client.events],\n fault: stampLine === null ? fault : (restamped(stampLine, client.events) ?? fault),\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[at ?? leader]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: {},\n primary: leader,\n at,\n timeline: nodesOnMonotonic(lab.log.slice(logFrom), clockOffsetOf(client.events)),\n after,\n holds,\n },\n };\n};\n","import type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, GroupPlace, Kafka, KernelRecord, ProbeEvent, Run, RunPart } from \"./cell.ts\";\nimport type { GroupClient, GroupNetworkFault, GroupView, Stamp } from \"./group.ts\";\nimport { CONVERGE_MS, deadlineOf } from \"./group.ts\";\nimport { harnessImage, kafkaClientImage } from \"./image.ts\";\nimport type { Manifest } from \"./lab.ts\";\nimport { STOP, containers, lines, netnsOf, output, withPid } from \"./lab.ts\";\nimport { isFenceLine, namesGroup, pauseReady } from \"./pause.ts\";\nimport type { Cut } from \"./replset.ts\";\n\n/**\n * This module is the lab of a group of Kafka brokers in KRaft mode with one controller. It opens one\n * environment for a Kafka cell, for the runs of the cell. Each node is a container from the stock\n * image, in its own network namespace, and an injector sidecar shares its network and process\n * namespaces. The image starts by its own command, and each setting comes from the environment.\n *\n * Each run makes one new topic, thus each run starts with an empty log and its client counts from 1.\n * The client is the producer of kafka-clients. The commander holds the admin, on the network but\n * not in the namespace that the prober watches. The record of a run is the lines of the client and\n * the whole partition, read to its high watermark after the group converged.\n */\n\n/** This path is the class path of the Kafka image: the JVM expands the star itself. */\nconst CLASS_PATH = \"/opt/harness/kafka/classes:/opt/harness/kafka/lib/*\";\n\n/** This option is the heap of the client and of the admin. It has no source: the two hold a producer or a read of one partition. */\nconst CLIENT_HEAP = \"-Xmx256m\";\n\n/** This function gives the node id of a name. A broker has its place in the list from 1, and the controller has the id after them. */\nexport const nodeIdOf = (kafka: Kafka, name: string): number => {\n const at = kafka.brokers.indexOf(name);\n if (at !== -1) return at + 1;\n if (name === kafka.controller) return kafka.brokers.length + 1;\n throw new Error(`the Kafka group has no node ${name}`);\n};\n\n/**\n * This function gives the variable of a server property for the image. The wrapper of the image\n * reverses this map (KafkaDockerWrapper.scala:188-203). After the prefix `KAFKA_`, `___` is a\n * hyphen, `__` is an underscore and `_` is a dot.\n */\nexport const envOf = (property: string): string =>\n `KAFKA_${property.replace(/_/g, \"__\").replace(/-/g, \"___\").replace(/\\./g, \"_\").toUpperCase()}`;\n\n/** This function gives the variables of each node: the listener names, the voters, the log and the settings of the group. */\nconst commonEnv = (kafka: Kafka): Record<string, string> => ({\n CLUSTER_ID: kafka.clusterId,\n KAFKA_HEAP_OPTS: kafka.heap,\n KAFKA_CONTROLLER_QUORUM_VOTERS: `${nodeIdOf(kafka, kafka.controller)}@${kafka.controller}:${kafka.controllerPort}`,\n KAFKA_CONTROLLER_LISTENER_NAMES: \"CONTROLLER\",\n KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: \"CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT\",\n // the wrapper writes the server properties from these variables alone (KafkaDockerWrapper.scala:147)\n KAFKA_LOG_DIRS: \"/var/lib/kafka/data\",\n ...Object.fromEntries(Object.entries(kafka.settings).map(([property, value]) => [envOf(property), value])),\n});\n\n/** This function gives the environment of a broker. */\nexport const brokerEnv = (kafka: Kafka, name: string): Record<string, string> => ({\n ...commonEnv(kafka),\n KAFKA_PROCESS_ROLES: \"broker\",\n KAFKA_NODE_ID: String(nodeIdOf(kafka, name)),\n KAFKA_LISTENERS: `PLAINTEXT://0.0.0.0:${kafka.port}`,\n KAFKA_ADVERTISED_LISTENERS: `PLAINTEXT://${name}:${kafka.port}`,\n KAFKA_INTER_BROKER_LISTENER_NAME: \"PLAINTEXT\",\n});\n\n/** This function gives the environment of the controller. The start script of the image stops on an advertised listener here (configure:43-48). */\nexport const controllerEnv = (kafka: Kafka): Record<string, string> => ({\n ...commonEnv(kafka),\n KAFKA_PROCESS_ROLES: \"controller\",\n KAFKA_NODE_ID: String(nodeIdOf(kafka, kafka.controller)),\n KAFKA_LISTENERS: `CONTROLLER://0.0.0.0:${kafka.controllerPort}`,\n});\n\n/** A partition view is the output of the command `view` of the admin. Without a topic it has only the brokers. */\nexport interface PartitionView {\n readonly brokers: readonly number[];\n readonly leader?: number | null;\n readonly isr?: readonly number[];\n readonly replicas?: readonly number[];\n}\n\n/**\n * This function judges a view of a partition: its leader, and if the group is healthy. A healthy\n * group has each broker not fenced, one leader, and each broker in the in-sync replicas.\n */\nexport const kafkaViewOf = (kafka: Kafka, view: PartitionView): GroupView => {\n const primary = view.leader === undefined || view.leader === null ? null : (kafka.brokers[view.leader - 1] ?? null);\n const all = kafka.brokers.length;\n if (view.brokers.length !== all) return { primary, healthy: false, why: `${view.brokers.length} brokers are not fenced` };\n if (primary === null) return { primary, healthy: false, why: \"the partition has no leader\" };\n if (view.replicas?.length !== all) return { primary, healthy: false, why: `the partition has ${view.replicas?.length ?? 0} replicas` };\n if (view.isr?.length !== all) return { primary, healthy: false, why: `the partition has ${view.isr?.length ?? 0} in-sync replicas` };\n return { primary, healthy: true, why: \"healthy\" };\n};\n\n/**\n * This function gives the peers that a fault on a broker cuts it from. Only `group` has a law: the\n * other brokers and the controller, and the client keeps its route to the broker.\n */\nexport const kafkaCutOf = (\n kafka: Kafka,\n members: Readonly<Record<string, RunPart>>,\n controller: RunPart,\n part: string,\n cuts: NonNullable<GroupPlace[\"cuts\"]>,\n): Cut => {\n if (cuts !== \"group\") throw new Error(`a Kafka cell has no cut ${cuts}`);\n return { peers: [...kafka.brokers.filter((name) => name !== part).map((name) => members[name]!.ip), controller.ip] };\n};\n\n/** This function gives the addresses that the client and the admin bootstrap from. */\nexport const bootstrapOf = (kafka: Kafka): string => kafka.brokers.map((name) => `${name}:${kafka.port}`).join(\",\");\n\n/** This function gives the name of the topic of a run. A warm-up has the index -1. */\nexport const topicOf = (environment: number, index: number): string => `cells-e${environment}-r${index + 1}`;\n\n/** A Kafka member is one member of a consumer group. A signal goes from a sidecar in its process namespace. */\nexport interface KafkaMember extends GroupClient {\n /** This method sends a signal to the process of the member, at once or at an instant of the VM. The injector stamps it. */\n signal(signal: \"STOP\" | \"CONT\", at?: number): Promise<Stamp>;\n}\n\n/** A Kafka lab is one environment of a Kafka cell. */\nexport interface KafkaLab {\n readonly kafka: Kafka;\n readonly clientIp: string;\n readonly members: Readonly<Record<string, RunPart>>;\n readonly controller: RunPart;\n readonly netns: { readonly client: number };\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** These are the last raw lines of the console of each node, for the diagnosis of a lab: at most RAW_TAIL of each. */\n readonly raw: Readonly<Record<string, readonly string[]>>;\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method waits until each broker is not fenced. */\n brokersUp(within?: number): Promise<void>;\n /** These are the log lines of the brokers that tell that a member left a group (`isFenceLine`), in sequence. */\n readonly fences: readonly string[];\n /** This method makes the topic of a run, with one partition or more. */\n create(topic: string, partitions?: number): Promise<void>;\n /** This method writes `count` records in each partition of a topic, each acknowledged by each in-sync replica. */\n fill(topic: string, partitions: number, count: number): Promise<void>;\n /** This method starts one member of a consumer group, with the arguments of `ConsumerKafka` after the bootstrap. */\n consumer(args: readonly string[]): Promise<KafkaMember>;\n /** This method waits until the partition is whole and calm, and gives the name of the broker of its leader. */\n converge(topic: string, within?: number): Promise<string>;\n /** This method gives the sequence numbers that the partition holds, one entry for each copy. */\n holds(topic: string): Promise<number[]>;\n /** This method starts the client of a run, with the arguments of `ClientKafka`. */\n client(args: readonly string[]): Promise<GroupClient>;\n /** This method applies a network fault between a broker and some of its peers, at once or at an instant of the VM. */\n fault(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes a network fault, at once or at an instant of the VM. */\n lift(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes the TCP metrics of the client namespace: each run starts from a kernel that keeps nothing. */\n forget(): Promise<void>;\n /** This method waits for the next clock line of the prober, which gives the count of lost records. */\n settle(): Promise<number | null>;\n manifest(sysctls: Readonly<Record<string, string>>): Promise<Manifest>;\n close(): Promise<void>;\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** This count is the number of raw lines of the console of each node that a lab keeps. */\nexport const RAW_TAIL = 400;\n\n/**\n * This function opens one environment of a Kafka cell:\n * - one new network, with each node, the client and the commander on it.\n * - the controller first, then each broker: the stock image with its own command. The brokers\n * register with the controller, thus they need it first.\n * - an injector sidecar for each node, in its network and process namespaces.\n * - a client that holds its own network namespace, with a privileged sidecar for its sysctls.\n * - the prober, which watches the namespace of the client.\n */\nexport const openKafkaLab = async (kafka: Kafka): Promise<KafkaLab> => {\n const image = await harnessImage();\n const clientImage = await kafkaClientImage();\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n let network: StartedNetwork | undefined;\n const close = async () => {\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n await network?.stop().catch(() => undefined);\n };\n const ipOf = async (container: StartedTestContainer): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network!.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network!.getName()}`);\n return ip;\n };\n try {\n network = await new Network().start();\n const started = network;\n const boxes = new Map<string, StartedTestContainer>();\n const injectors = new Map<string, StartedTestContainer>();\n const parts: Record<string, RunPart> = {};\n const raw: Record<string, string[]> = {};\n const fences: string[] = [];\n const openNode = async (name: string, environment: Record<string, string>): Promise<void> => {\n let partial = \"\";\n const box = await new GenericContainer(kafka.image)\n .withNetwork(started)\n .withNetworkAliases(name)\n .withHostname(name)\n .withEnvironment(environment)\n .withWaitStrategy(Wait.forLogMessage(kafka.ready))\n .withStartupTimeout(180_000)\n .withLogConsumer((stream) =>\n stream.on(\"data\", (chunk: Buffer | string) => {\n partial += chunk.toString();\n const split = partial.split(\"\\n\");\n partial = split.pop() ?? \"\";\n for (const text of split) {\n const tail = (raw[name] ??= []);\n tail.push(text);\n if (tail.length > RAW_TAIL) tail.shift();\n if (isFenceLine(text)) fences.push(text);\n }\n }),\n )\n .start();\n opened.push(box);\n boxes.set(name, box);\n const injector = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${box.getId()}`,\n ).start();\n opened.push(injector);\n injectors.set(name, injector);\n parts[name] = { ip: await ipOf(box), netns: await netnsOf(injector) };\n };\n await openNode(kafka.controller, controllerEnv(kafka));\n for (const name of kafka.brokers) await openNode(name, brokerEnv(kafka, name));\n const members: Record<string, RunPart> = Object.fromEntries(kafka.brokers.map((name) => [name, parts[name]!]));\n const controller = parts[kafka.controller]!;\n\n const holder = await new GenericContainer(image).withNetwork(network).start();\n opened.push(holder);\n const admin = await new GenericContainer(image).withNetworkMode(`container:${holder.getId()}`).withPrivilegedMode().start();\n opened.push(admin);\n const clientIp = await ipOf(holder);\n const commander = await new GenericContainer(clientImage)\n .withNetwork(network)\n .withCommand([\"sh\", \"-c\", \"while :; do sleep 3600; done\"])\n .start();\n opened.push(commander);\n\n const clientNetns = await netnsOf(admin);\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\"/opt/harness/prober\", String(clientNetns)])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n\n const box = (name: string): StartedTestContainer => {\n const found = boxes.get(name);\n if (found === undefined) throw new Error(`the group has no node ${name}`);\n return found;\n };\n const injectorOf = (name: string): StartedTestContainer => {\n const found = injectors.get(name);\n if (found === undefined) throw new Error(`the group has no node ${name}`);\n return found;\n };\n const lastLine = (text: string): string => text.split(\"\\n\").filter((line) => line.trim() !== \"\").at(-1) ?? \"\";\n const stamped = async (where: StartedTestContainer, argv: string[]): Promise<Stamp> => {\n const stamp = JSON.parse(lastLine(await output(where, argv))) as Stamp;\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const after = (at: number | undefined): string[] => (at === undefined ? [] : [\"--at\", String(Math.round(at))]);\n const bootstrap = bootstrapOf(kafka);\n const tool = async (...argv: string[]): Promise<string> =>\n lastLine(await output(commander, [\"java\", CLIENT_HEAP, \"-cp\", CLASS_PATH, \"AdminKafka\", bootstrap, ...argv]));\n const view = async (topic?: string): Promise<PartitionView> =>\n JSON.parse(await tool(\"view\", ...(topic === undefined ? [] : [topic]))) as PartitionView;\n\n return {\n kafka,\n clientIp,\n members,\n controller,\n netns: { client: clientNetns },\n kernel: records.seen,\n raw,\n fences,\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values)) read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n async brokersUp(within = CONVERGE_MS) {\n const begin = Date.now();\n let last = \"no view yet\";\n while (Date.now() - begin < within) {\n const read = await view().catch((error: unknown) => (error as Error).message.slice(0, 200));\n if (typeof read !== \"string\" && read.brokers.length === kafka.brokers.length) return;\n last = typeof read === \"string\" ? read : `${read.brokers.length} brokers are not fenced`;\n await sleep(1_000);\n }\n throw new Error(`the brokers did not come up in ${within} ms: ${last}`);\n },\n async create(topic, partitions = 1) {\n const ids = kafka.brokers.map((name) => nodeIdOf(kafka, name)).join(\",\");\n const reply = await tool(\"create\", topic, String(kafka.minInsync), ids, String(partitions));\n if (!reply.includes('\"ok\":true')) throw new Error(`the create of the topic failed: ${reply}`);\n },\n async fill(topic, partitions, count) {\n const reply = await tool(\"fill\", topic, String(partitions), String(count));\n if (!reply.includes('\"ok\":true')) throw new Error(`the fill of the topic failed: ${reply}`);\n },\n async consumer(args) {\n const events = lines<ProbeEvent>();\n // sh stays as process 1, because a signal from inside a process namespace to its process 1 has no effect\n const container = await new GenericContainer(clientImage)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"sh\", \"-c\", 'java \"$@\"; :', \"consumer\", CLIENT_HEAP, \"-cp\", CLASS_PATH, \"ConsumerKafka\", bootstrap, ...args])\n .withLogConsumer(events.consume)\n .start();\n const signaller = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${holder.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${container.getId()}`,\n ).start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n signal: (signal, at) => stamped(signaller, [\"/opt/harness/inject\", \"signal\", \"java\", signal, ...after(at)]),\n // process 1 is sh and it ignores a TERM, thus this stop ends with a KILL, and it writes no done line\n stop: async () => {\n await container.stop({ timeout: 2 }).catch(() => undefined);\n await signaller.stop(STOP).catch(() => undefined);\n },\n };\n },\n async converge(topic, within = CONVERGE_MS) {\n const begin = Date.now();\n let calm = 0;\n let last: GroupView = { primary: null, healthy: false, why: \"no view yet\" };\n while (Date.now() - begin < within) {\n last = await view(topic).then(\n (read) => kafkaViewOf(kafka, read),\n (error: unknown) => ({ primary: null, healthy: false, why: (error as Error).message.slice(0, 200) }),\n );\n // two healthy views in a row: one view can come in the middle of a change, and the\n // high watermark moves with the fetch after the one that put a broker back in sync\n calm = last.healthy ? calm + 1 : 0;\n if (calm >= 2 && last.primary !== null) return last.primary;\n await sleep(1_000);\n }\n throw new Error(`the partition did not converge in ${within} ms: ${last.why}`);\n },\n async holds(topic) {\n const reply = await tool(\"holds\", topic);\n const { held } = JSON.parse(reply) as { held?: unknown[] };\n if (held === undefined) throw new Error(`the read of the partition failed: ${reply}`);\n return held.map(Number).filter((n) => Number.isInteger(n) && n > 0);\n },\n async client(args) {\n const events = lines<ProbeEvent>();\n const container = await new GenericContainer(clientImage)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"java\", CLIENT_HEAP, \"-cp\", CLASS_PATH, \"ClientKafka\", bootstrap, ...args])\n .withLogConsumer(events.consume)\n .start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n // a TERM first: the client writes its done line, then stops\n stop: () =>\n container\n .stop({ timeout: 2 })\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n fault(kind, part, cuts, at) {\n const cut = kafkaCutOf(kafka, members, controller, part, cuts);\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind, cut.peers.join(\",\"), ...after(at)]);\n },\n lift(kind, part, cuts, at) {\n const cut = kafkaCutOf(kafka, members, controller, part, cuts);\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind === \"rst\" ? \"clear-rst\" : \"clear\", cut.peers.join(\",\"), ...after(at)]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n async settle() {\n const from = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const begin = Date.now();\n const look = () => {\n const line = records.seen.slice(from).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - begin > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) => runtime.container.inspect(runtime.container.getById(container.getId()));\n const settings = {\n settings: Object.entries(kafka.settings)\n .map(([property, value]) => `${property}=${value}`)\n .join(\"; \"),\n heap: kafka.heap,\n \"min.insync.replicas\": String(kafka.minInsync),\n };\n const list = async (names: readonly string[]) => {\n const out = [];\n for (const name of names) {\n const version = lastLine(await output(box(name), [\"/opt/kafka/bin/kafka-topics.sh\", \"--version\"]).catch(() => \"\"));\n out.push({ name, ip: parts[name]!.ip, id: (await inspect(box(name))).Image, settings: { version, ...settings } });\n }\n return out;\n };\n const brokers = await list(kafka.brokers);\n return {\n kernel: await output(holder, [\"uname\", \"-r\"]),\n architecture: await output(holder, [\"uname\", \"-m\"]),\n hz: /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1] ?? null,\n boot_id: await output(holder, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n target: { image: kafka.image, id: brokers[0]!.id, settings: brokers[0]!.settings, sysctls: {} },\n harness: {\n image,\n id: (await inspect(holder)).Image,\n packages: (await output(holder, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n },\n client: { kind: \"image\", image: clientImage },\n netns: { client: clientNetns, target: members[kafka.brokers[0]!]!.netns },\n sysctls,\n group: { members: brokers, sentinels: await list([kafka.controller]), observer: { image: clientImage } },\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n\n// ---------------------------------------------------------------------------------------------\n// the runs of a Kafka cell\n// ---------------------------------------------------------------------------------------------\n\n/** This count is the number of acknowledged writes that a run waits for before its fault: the stream is steady then. */\nconst STEADY = 20;\n\n/**\n * This time is how long a run continues after its lift. The record then shows the step-down of the\n * leader and the writes after it. It has no source. It is above the largest step-down of the\n * law, which is approximately 2 s after the lift.\n */\nexport const KAFKA_TAIL_MS = 10_000;\n\n/** This function gives the arguments of the client of a Kafka cell: the topic, the writers, the stream of writes and the settings. */\nexport const kafkaArgs = (cell: Cell, topic: string): string[] => [\n \"--topic\",\n topic,\n \"--writers\",\n String(cell.kafka!.writers),\n \"--interval-ms\",\n String(cell.probe.interval === undefined ? 50 : valueIn(cell.probe.interval, \"ms\")),\n \"--max-s\",\n String(Math.ceil(deadlineOf(cell) / 1_000 + (cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\")) + 120)),\n ...Object.entries(cell.driverOptions ?? {}).flatMap(([name, value]) => [\"--set\", `${name}=${String(value)}`]),\n];\n\n/** This function waits until a condition on the lines of the client holds, or for `within` ms. It gives the first line that matches. */\nconst waitFor = (client: GroupClient, match: (event: ProbeEvent) => boolean, within: number): Promise<ProbeEvent | undefined> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const found = client.events.find(match);\n if (found !== undefined || Date.now() - started > within) resolve(found);\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1) if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/**\n * This function does one run of a Kafka cell:\n * - Each broker is up, the topic of the run exists, and its partition is whole. The client starts,\n * and its stream of writes gets steady.\n * - The fault cuts the leader from the other brokers and the controller, and it lifts at its instant\n * in the VM. The client keeps its route to the leader, thus only the group knows of the cut.\n * - The run waits for the lift and for the tail after it.\n * - Each fault goes, the client stops, and the partition converges again. The admin then reads\n * the whole partition, thus the record tells which writes the group kept.\n */\nexport const kafkaOnce = async (lab: KafkaLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n if (cell.fault !== \"partition\") throw new Error(`a Kafka cell has no fault ${cell.fault}`);\n if (cell.hold === undefined) throw new Error(\"a Kafka cell needs a hold: its law reads it\");\n const place = (cell.faultAt ?? { role: \"primary\" }) as GroupPlace;\n if (place.role !== \"primary\") throw new Error(`a Kafka cell has no fault on the ${place.role}`);\n const cuts = place.cuts ?? \"group\";\n const topic = topicOf(environment, index);\n await lab.brokersUp();\n await lab.create(topic);\n const leader = await lab.converge(topic);\n await lab.forget();\n const from = lab.kernel.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const client = await lab.client(kafkaArgs(cell, topic));\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n const undo: Array<() => Promise<unknown>> = [];\n try {\n await client.until([\"ready\"], 60_000);\n const steady = await waitFor(client, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not write ${STEADY} times in 30 s`);\n fault = await lab.fault(\"blackhole\", leader, cuts);\n undo.push(() => lab.lift(\"blackhole\", leader, cuts));\n // the injector holds the lift in the VM: its exec returns at the instant, and the stamps come with it\n heal = await lab.lift(\"blackhole\", leader, cuts, fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n // the lift came: nothing is left to undo\n undo.length = 0;\n await sleep(KAFKA_TAIL_MS);\n } finally {\n // a fault that is still on goes\n for (const step of undo.reverse()) await step().catch(() => undefined);\n await client.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge(topic).catch(() => null);\n const holds = after === null ? null : await lab.holds(topic);\n return {\n environment,\n index,\n events: [...client.events],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[leader]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: { [lab.kafka.controller]: lab.controller },\n primary: leader,\n at: leader,\n timeline: [],\n after,\n holds,\n },\n };\n};\n\n/** This count is the partitions of the topic of a run of a paused consumer: one for each member. */\nconst PAUSE_PARTITIONS = 2;\n\n/** This time bounds the wait for one partition for each member and for two commits, in ms. It has no source: it is far above two batches and one rebalance. */\nconst PAUSE_READY_MS = 90_000;\n\n/** This time bounds the wait for the next batch of the first member, in ms. It has no source: it is far above one batch. */\nconst PAUSE_BATCH_MS = 30_000;\n\n/**\n * This function does one run of a paused consumer:\n * - The topic of the run has two partitions, each with records that a run does not finish.\n * - Two members join one group, and the run waits until each member holds one partition and the\n * first member has two commits on its partition.\n * - A SIGSTOP stops the first member while it holds its next batch, and a SIGCONT ends the stop\n * after the hold of the cell. The run then waits for the tail.\n *\n * The fault is null when the members did not get one partition each. The measure then voids the run.\n * The law reads no kernel record, thus a lost record does not void this run.\n */\nexport const kafkaPauseOnce = async (lab: KafkaLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const pause = cell.kafka?.pause;\n if (pause === undefined) throw new Error(\"a run of a paused consumer needs `Kafka.pause`\");\n if (cell.fault !== \"freeze-process\") throw new Error(`a paused consumer has no fault ${cell.fault}`);\n if (cell.hold === undefined) throw new Error(\"a paused consumer needs a hold: its law reads it\");\n const hold = valueIn(cell.hold, \"s\");\n const topic = topicOf(environment, index);\n const group = `pause-e${environment}-r${index + 1}`;\n await lab.brokersUp();\n await lab.create(topic, PAUSE_PARTITIONS);\n const leader = await lab.converge(topic);\n await lab.fill(topic, PAUSE_PARTITIONS, pause.fill);\n await lab.forget();\n const from = lab.kernel.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const common = [\n \"--topic\",\n topic,\n \"--group\",\n group,\n \"--protocol\",\n pause.protocol,\n \"--max-s\",\n String(Math.ceil(hold + 180)),\n ...Object.entries(cell.driverOptions ?? {}).flatMap(([name, value]) => [\"--set\", `${name}=${String(value)}`]),\n ];\n const members: KafkaMember[] = [];\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n let otherEvents: readonly ProbeEvent[] = [];\n let firstEvents: readonly ProbeEvent[] = [];\n try {\n const first = await lab.consumer([...common, \"--process-ms\", String(valueIn(pause.process, \"ms\")), \"--after-pause\", pause.afterPause]);\n members.push(first);\n const other = await lab.consumer([...common, \"--process-ms\", \"0\", \"--after-pause\", \"commit\"]);\n members.push(other);\n firstEvents = first.events;\n otherEvents = other.events;\n const begun = Date.now();\n while (Date.now() - begun < PAUSE_READY_MS && !pauseReady(first.events, other.events)) await sleep(100);\n if (pauseReady(first.events, other.events)) {\n const seen = first.events.at(-1)?.t ?? 0;\n const batch = await waitFor(first, (event) => event.ev === \"processing\" && event.t > seen, PAUSE_BATCH_MS);\n if (batch !== undefined) {\n fault = await first.signal(\"STOP\", batch.t + valueIn(pause.stopAfter, \"s\") * 1e9);\n // the injector holds the signal in the VM: its exec returns at the instant, and the stamps come with it\n heal = await first.signal(\"CONT\", fault.t0 + hold * 1e9);\n await sleep(KAFKA_TAIL_MS);\n }\n }\n } finally {\n for (const member of members) await member.stop();\n }\n const settled = await lab.settle();\n return {\n environment,\n index,\n events: [...firstEvents],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[leader]!.netns,\n lost: settled === null ? null : settled - lostBefore,\n pause: { other: [...otherEvents], fences: lab.fences.filter((line) => namesGroup(line, group)), group },\n };\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport { schedule } from \"@mark1russell7/rigor-chaos\";\nimport type { Cell, FaultPlace, KernelRecord, LineCount, ProbeEvent, Run } from \"./cell.ts\";\nimport { isHopPlace, latestEndOf, requestFirst } from \"./cell.ts\";\nimport { drillOnce } from \"./drill.ts\";\nimport { countOf, longestOf, settled as driverSettled } from \"./driver.ts\";\nimport { laterMove } from \"./fabric.ts\";\nimport { groupOnce, openGroupLab } from \"./group.ts\";\nimport type { FaultOptions, Lab, Manifest, Probe } from \"./lab.ts\";\nimport { openLab } from \"./lab.ts\";\nimport { LOAD_PATH, SCHEDULE_PATH, loadPlanOf } from \"./load.ts\";\nimport type { Measured } from \"./observe.ts\";\nimport { jitterOf, measure, socketOf } from \"./observe.ts\";\nimport { openReplicaSetLab, replicaSetOnce } from \"./replset.ts\";\nimport { clusterOnce, openClusterLab } from \"./cluster.ts\";\nimport { kafkaOnce, kafkaPauseOnce, openKafkaLab } from \"./kafka.ts\";\nimport { openStandby, pairOnce } from \"./standby.ts\";\nimport { readCpu, stealShare } from \"./substrate.ts\";\nimport type { Verdict } from \"./verdict.ts\";\nimport { STEPS, noiseOf, verdictOf } from \"./verdict.ts\";\n\n/** A cell result is a cell with its manifests, its runs, their measurements and its verdict. */\nexport interface CellResult {\n readonly cell: Cell;\n readonly manifests: readonly Manifest[];\n readonly runs: readonly Run[];\n /** These are the warm-up runs, one for each environment before its counted runs. The verdict does not count them. */\n readonly warmups: readonly Run[];\n readonly measured: readonly Measured[];\n readonly verdict: Verdict;\n /** These times are when its first environment opened and its last environment closed, on the wall clock. */\n readonly at: { readonly started: string; readonly ended: string };\n}\n\n/**\n * This function measures and judges the raw records of a cell, with the code of the harness at\n * this time. `runCell` uses it during a cell. A holder of the raw records of a cell can use it\n * again later. Thus the records get a new analysis after a change to observe.ts or to the verdict.\n */\nexport const judge = (\n cell: Cell,\n runs: readonly Run[],\n): { measured: Measured[]; verdict: Verdict } => {\n // a warm-up run is a record, not a sample: the verdict never counts it\n const measured = runs.filter((run) => run.warmup !== true).map((run) => measure(cell, run));\n return { measured, verdict: verdictOf(cell.prediction, measured, noiseOf(cell)) };\n};\n\n/** This function gives the count of lost records in the latest clock line of the prober, since it began. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1)\n if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/** This function gives the argv of the client for a cell, with a deadline far after all that it waits for. */\nconst probeArgs = (cell: Cell, lab: Lab): string[] => {\n const { prediction, probe } = cell;\n const longest =\n (prediction.detects === true && prediction.driver !== undefined\n ? longestOf(cell)\n : prediction.detects\n ? latestEndOf(prediction)\n : valueIn(prediction.window, \"s\")) + (cell.idleBefore === undefined ? 0 : valueIn(cell.idleBefore, \"s\"));\n const args = [lab.targetIp, String(lab.targetPort), \"--mode\", probe.mode];\n if (probe.ws !== undefined) {\n // a WebSocket client gets each of its settings as a flag, and it has no default\n const { ws } = probe;\n const reconnects = prediction.detects !== false ? (prediction.reconnects?.waits ?? []) : [];\n const waits = reconnects.reduce((sum, wait) => sum + valueIn(wait.high, \"s\"), 0);\n args.push(\"--websocket\", ws.socket);\n args.push(\"--heartbeat\", ws.heartbeat === null ? \"off\" : \"on\");\n if (ws.heartbeat !== null)\n args.push(\n \"--heartbeat-interval-ms\",\n String(valueIn(ws.heartbeat.interval, \"ms\")),\n \"--heartbeat-timeout-ms\",\n String(valueIn(ws.heartbeat.timeout, \"ms\")),\n \"--heartbeat-misses\",\n String(ws.heartbeat.misses),\n );\n args.push(\"--reconnect\", ws.reconnect === null ? \"off\" : \"on\");\n if (ws.reconnect !== null)\n args.push(\n \"--reconnect-initial-ms\",\n String(valueIn(ws.reconnect.initialDelay, \"ms\")),\n \"--reconnect-multiplier\",\n String(ws.reconnect.multiplier),\n \"--reconnect-max-ms\",\n String(valueIn(ws.reconnect.maxDelay, \"ms\")),\n \"--reconnect-attempts\",\n String(ws.reconnect.attempts),\n \"--reconnect-jitter\",\n String(ws.reconnect.jitter),\n );\n args.push(\"--request-timeout-ms\", String(valueIn(ws.requestTimeout, \"ms\")));\n args.push(\"--connection-timeout-ms\", String(valueIn(ws.connectionTimeout, \"ms\")));\n if (ws.hold !== undefined) args.push(\"--hold-ms\", String(valueIn(ws.hold, \"ms\")));\n args.push(\"--max-s\", String(Math.ceil((longest + waits) * 2 + 10)));\n return args;\n }\n if (probe.http !== undefined) {\n // an HTTP client sets its socket options from its own settings, and sends its own requests\n const { http } = probe;\n const gap = http.gap === undefined ? 0 : valueIn(http.gap, \"s\");\n args.push(\"--method\", http.method);\n if (http.gap !== undefined) args.push(\"--gap-ms\", String(valueIn(http.gap, \"ms\")));\n if (http.hold !== undefined) args.push(\"--hold-ms\", String(valueIn(http.hold, \"ms\")));\n if (http.bytes !== undefined) args.push(\"--bytes\", String(http.bytes));\n for (const [name, value] of Object.entries(http.options ?? {})) args.push(`--${name}`, String(value));\n // the client waits after its second request, thus its own close comes after the window\n args.push(\"--linger-ms\", String(LINGER_MS));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + gap + 10)));\n return args;\n }\n if (probe.request !== undefined) args.push(\"--request\", probe.request);\n if (probe.count !== undefined) args.push(\"--count\", String(probe.count));\n if (probe.interval !== undefined) args.push(\"--interval-ms\", String(valueIn(probe.interval, \"ms\")));\n if (probe.driver?.name === \"mongodb\") {\n // the MongoDB driver: its replica set, its operation, its write concern and its own options\n args.push(\"--set\", probe.driver.set);\n if (probe.driver.op !== undefined) args.push(\"--op\", probe.driver.op);\n if (cell.writeConcern !== undefined) args.push(\"--w\", String(cell.writeConcern));\n if (cell.before === true) args.push(\"--before\");\n if (cell.driverOptions !== undefined) args.push(\"--options\", JSON.stringify(cell.driverOptions));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n }\n if (probe.driver?.name === \"pg\" || probe.driver?.name === \"hikari\" || probe.driver?.name === \"amqp\") {\n // node-postgres or HikariCP: its query, and the options of its pool. amqplib: the options of its connection\n if (probe.driver.name !== \"amqp\" && probe.driver.query !== undefined) args.push(\"--query\", probe.driver.query);\n if (probe.driver.name !== \"amqp\" && probe.driver.inflight !== undefined) args.push(\"--inflight-query\", probe.driver.inflight);\n if (probe.driver.name === \"hikari\" && probe.driver.burst !== undefined)\n args.push(\"--burst\", String(probe.driver.burst.count), \"--burst-gap-ms\", String(Math.round(valueIn(probe.driver.burst.gap, \"ms\"))));\n if (cell.before === true) args.push(\"--before\");\n if (cell.driverOptions !== undefined) args.push(\"--options\", JSON.stringify(cell.driverOptions));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n }\n if (probe.driver?.name === \"grpc\") {\n // grpc-js: its channel options and the deadline of a call, and the hold of the reply in flight\n if (probe.driver.hold !== undefined) args.push(\"--hold-ms\", String(valueIn(probe.driver.hold, \"ms\")));\n if (probe.driver.op !== undefined) args.push(\"--op\", probe.driver.op);\n if (cell.before === true) args.push(\"--before\");\n if (cell.driverOptions !== undefined) args.push(\"--options\", JSON.stringify(cell.driverOptions));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n }\n if (probe.driver !== undefined) {\n // a driver sets its socket options from its own options: the keepAlive of ioredis\n args.push(\"--keepalive-ms\", String(valueIn(probe.driver.keepAlive, \"ms\")));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n }\n if (probe.keepalive) args.push(\"--keepalive\");\n if (probe.userTimeout !== undefined)\n args.push(\"--user-timeout-ms\", String(valueIn(probe.userTimeout, \"ms\")));\n if (probe.plan !== undefined) args.push(\"--schedule\", SCHEDULE_PATH);\n if (probe.streams !== undefined) args.push(\"--plan\", LOAD_PATH);\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n};\n\n/**\n * This function waits for an error on the socket of the observer, or for its end of file\n * (CLOSE_WAIT, state 8). The prober records both. A cell whose observer is the server, or a proxy\n * of a topology, waits for that. A target with its own detector can also drop the connection\n * itself (`dropped`). The promise resolves after `within` ms at the latest.\n */\nconst observerError = (\n cell: Cell,\n partial: () => Run,\n within: number,\n dropped: () => boolean = () => false,\n): Promise<void> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const run = partial();\n const at = socketOf(cell, run);\n const seen =\n at !== undefined &&\n run.kernel.some(\n (record) =>\n record.netns === at.netns &&\n record.cookie === at.cookie &&\n ((record.ev === \"error\" && (record.err ?? 0) !== 0) ||\n (record.ev === \"state\" && (record as { readonly new?: number }).new === 8)),\n );\n if (seen || dropped() || Date.now() - started > within) resolve();\n else setTimeout(look, 50);\n };\n look();\n });\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * This time is the pause between the client's first reply and the fault. It is more than Linux's\n * TCP_DELACK_MAX of 200 ms. Thus the delayed ACK of the reply is out before the fault.\n */\nexport const QUIET_MS = 250;\n\n/**\n * This time is how long an HTTP client waits after its second request, before it exits. The exit\n * closes its sockets, thus that close comes after the window of the cell.\n */\nexport const LINGER_MS = 1000;\n\n/** These are the lines that end the workload of an HTTP client: the end of its second request, its deadline, or its failure. */\nconst HTTP_DONE = [\"done\", \"deadline\", \"fail\"];\n\n/**\n * This function waits for the request that an in-flight client sends on the signal: its second\n * send, after the PING that made it ready. Its stamp is when the request first met the fault.\n */\nconst requestSent = (probe: Probe, within: number): Promise<ProbeEvent> =>\n new Promise((resolve, reject) => {\n const started = Date.now();\n const look = () => {\n const sent = probe.events.filter((event) => event.ev === \"sent\")[1];\n if (sent !== undefined) resolve(sent);\n else if (Date.now() - started > within)\n reject(new Error(`the client sent no request within ${within} ms of being told to`));\n else setTimeout(look, 1);\n };\n look();\n });\n\n/** This time is how long a run of a driver cell continues after its outcome, so that the record shows what came next. */\nconst TAIL_MS = 1_000;\n/** This time lets the last lines of a route monitor reach the harness after a stall ends. */\nconst MONITOR_MS = 200;\n\n/** This function waits for the outcome of a run of a driver cell, or for `within` ms. The outcome is the end of its band and of each later band. */\nconst driverOutcome = async (cell: Cell, current: () => Run, within: number): Promise<void> => {\n const started = Date.now();\n while (Date.now() - started < within) {\n if (driverSettled(cell, current())) return;\n await sleep(250);\n }\n};\n\n/** This function gives the longest wait of a run of a driver cell for its outcome, in ms. */\nconst driverWithin = (cell: Cell): number => (longestOf(cell) * 1.2 + 10) * 1_000;\n\n/**\n * This function does one run of a cell whose fault holds before the client starts (`Cell.before`).\n * The fault is a network fault at its place. The client then starts into it, and the run waits for\n * each band of the driver. Then the fault lifts.\n */\nconst beforeOnce = async (lab: Lab, cell: Cell, environment: number, index: number): Promise<Run> => {\n if (cell.fault !== \"rst\" && cell.fault !== \"blackhole\" && cell.fault !== \"unreachable\")\n throw new Error(`${cell.name}: a fault before the client starts is a network fault, not ${cell.fault}`);\n await lab.forget();\n const from = lab.kernel.length;\n const middleboxFrom = lab.middlebox.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const faultAt: FaultPlace = cell.faultAt ?? \"target\";\n const kind = cell.fault === \"unreachable\" ? \"reject\" : cell.fault;\n const options: FaultOptions = cell.fault === \"unreachable\" ? { code: cell.icmp ?? \"host\" } : {};\n const fault = await lab.fault(kind, faultAt, options);\n let probe: Probe | undefined;\n try {\n probe = await lab.probe(probeArgs(cell, lab));\n const started = probe;\n // the topology too: a band can be on the socket that a hop opens toward the target\n const current = (): Run => ({\n environment,\n index,\n events: started.events,\n fault,\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost: 0,\n ...(lab.topology === null ? {} : { topology: lab.topology }),\n });\n await driverOutcome(cell, current, driverWithin(cell));\n await sleep(TAIL_MS);\n } finally {\n await lab.lift(kind, faultAt, options);\n await probe?.stop();\n }\n const settled = await lab.settle();\n return {\n environment,\n index,\n events: [...(probe?.events ?? [])],\n fault,\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost: settled === null ? null : settled - lostBefore,\n ...(lab.topology === null ? {} : { topology: lab.topology, middlebox: lab.middlebox.slice(middleboxFrom) }),\n };\n};\n/** This function waits for the first ping of the heartbeat of the client at the instant `after` or later: its first ping into a stall. */\nconst pingSent = (probe: Probe, after: number, within: number): Promise<ProbeEvent> =>\n new Promise((resolve, reject) => {\n const started = Date.now();\n const look = () => {\n const ping = probe.events.find((event) => event.ev === \"ping\" && event.t >= after);\n if (ping !== undefined) resolve(ping);\n else if (Date.now() - started > within) reject(new Error(`the client sent no ping into the stall within ${within} ms`));\n else setTimeout(look, 1);\n };\n look();\n });\n\n/**\n * This function waits until the client wrote `count` lines `dial`, one before each connection\n * that it tries, or until its deadline. It resolves after `within` ms at the latest.\n */\nconst dials = (probe: Probe, count: number, within: number): Promise<void> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const tried = probe.events.filter((event) => event.ev === \"dial\").length;\n const ended = probe.events.some((event) => event.ev === \"deadline\");\n if (tried >= count || ended || Date.now() - started > within) resolve();\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This time is the most that a run waits for the lines of the target after the end of its client. */\nconst LINES_MS = 5_000;\n\n/**\n * This function waits for the lines of a run's counts. The lines of the target come on their own\n * stream, thus they can come after the last line of the client. A line above a count comes in the\n * pause after the wait, thus it is in the run that wrote it.\n */\nconst linesCounted = async (lab: Lab, from: number, counts: readonly LineCount[]): Promise<void> => {\n const started = Date.now();\n const short = () => counts.some((each) => countOf(lab.server.slice(from), each.match) < each.count);\n while (short() && Date.now() - started < LINES_MS) await sleep(20);\n await sleep(QUIET_MS);\n};\n\n/** This function gives the netem specification of a cell: its latency, then the netem of its fault when it has one. */\nconst netemSpec = (cell: Cell, fault: string | undefined): string | null => {\n const parts = [\n ...(cell.latency === undefined ? [] : [`delay ${valueIn(cell.latency, \"ms\")}ms`]),\n ...(fault === undefined ? [] : [fault]),\n ];\n return parts.length === 0 ? null : parts.join(\" \");\n};\n\n/**\n * This function does one run. The client connects and gets its reply, the fault occurs, and an\n * in-flight client sends into it. The harness then waits for the observer to see the fault, or for\n * the silent window to end. The observer is the client, or the socket of the target for a cell on\n * the server side. It can also be a socket of a proxy of a topology.\n *\n * A stall stops by itself, at its length after the send of the request, and the\n * run waits for the reply. Then the harness removes the fault, thus the environment can serve the\n * next run. The run keeps the records of the prober from its start to its end. The frozen process\n * is the peer of the observer: the target, or the client for the server.\n *\n * A dry run does all of this but the fault: the warm-up of a cell whose fault ends its environment.\n */\nconst once = async (\n lab: Lab,\n cell: Cell,\n environment: number,\n index: number,\n dry = false,\n): Promise<Run> => {\n if (cell.before === true) return beforeOnce(lab, cell, environment, index);\n // a silence of the run before moved the routes: each run starts on the preferred path, with each session up\n await lab.fabric?.ready();\n const sessions = await lab.fabric?.sessions();\n const routesFrom = lab.fabric?.routes.length ?? 0;\n // each run starts from kernels that keep nothing from the runs before it\n await lab.forget();\n const from = lab.kernel.length;\n const middleboxFrom = lab.middlebox.length;\n const serverFrom = lab.server.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const plan = cell.probe.plan === undefined ? undefined : schedule(cell.probe.plan.profile, cell.probe.plan.options);\n // the client load reads one plan with the schedule and the requests of each of its streams\n const load = cell.probe.streams === undefined ? undefined : loadPlanOf(cell.probe.streams);\n const files = [\n ...(plan === undefined ? [] : [{ content: JSON.stringify(plan), target: SCHEDULE_PATH }]),\n ...(load === undefined ? [] : [{ content: load.content, target: LOAD_PATH }]),\n ];\n const probe = await lab.probe(probeArgs(cell, lab), files.length === 0 ? undefined : files);\n const server = cell.observer === \"server\";\n const peer = server\n ? { freeze: () => probe.freeze(), thaw: () => probe.thaw() }\n : { freeze: () => lab.freeze(), thaw: () => lab.thaw() };\n // a client that stopped before the signal to send tells why in its last lines\n const go = () =>\n probe.go().catch((error: unknown) => {\n const last = probe.events.slice(-3).map((event) => JSON.stringify(event));\n throw new Error(`${(error as Error).message}; the client's last lines: ${last.join(\" \")}`);\n });\n const placed = {\n ...(lab.topology === null ? {} : { topology: lab.topology }),\n ...(plan === undefined ? {} : { schedule: plan }),\n ...(load === undefined ? {} : { streams: load.streams }),\n };\n const fabricOf = () => {\n if (lab.fabric === undefined) throw new Error(`${cell.name} silences a router of a lab with no fabric`);\n return lab.fabric;\n };\n /** This function gives the run as the records show it so far: the waits read it. */\n const partial = (): Run => ({\n environment,\n index,\n events: probe.events,\n fault: null,\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost: 0,\n ...placed,\n });\n let fault: Run[\"fault\"] = null;\n let heal: { t0: number; t1: number } | null = null;\n // a target with a named process freezes by SIGSTOP, with stamps, and a hold thaws it at its instant\n const signalled = !server && cell.target.program !== undefined;\n let thawing: Promise<{ t0: number; t1: number }> | null = null;\n try {\n await probe.until([\"ready\"], 15_000);\n if (dry) {\n if (cell.probe.mode !== \"idle\") await go();\n await sleep(500);\n } else {\n // the in-flight data of a run on the server side is the reply of the server. The request goes\n // out first, and the fault occurs while the server holds it (the timeout of BLPOP). A fin with\n // a request in flight kills the server while it holds the request, so it goes first too. So\n // does the request of an event at a hop that comes while the request is in flight\n const replyInFlight =\n cell.probe.mode === \"inflight\" &&\n ((server && cell.fault !== \"mtu-blackhole\") || cell.fault === \"fin\" || requestFirst(cell));\n if (replyInFlight) {\n // the client sends one sample after the file appears. The request reaches the server well\n // in the pause, and the reply waits for the timeout of the request\n await go();\n await sleep(200);\n } else {\n // The client acknowledges its first reply with a delayed ACK, 40 to 200 ms later\n // (TCP_DELACK_MIN to TCP_DELACK_MAX). A fault that comes first meets that ACK, not the\n // request or the idle time that the cell measures. So the fault waits until the ACK is out.\n await sleep(QUIET_MS);\n }\n const faultAt: FaultPlace = cell.faultAt ?? (server ? \"client\" : \"target\");\n // the direction of a simplex drop, relative to the namespace of the rule: in the target, or at\n // a proxy toward the client, the segments to the server come in; in the client, they go out\n const towardServerComesIn =\n faultAt === \"target\" || (isHopPlace(faultAt) && faultAt.toward === \"client\");\n const direction: FaultOptions[\"direction\"] =\n cell.drops === undefined\n ? undefined\n : (cell.drops === \"to-server\") === towardServerComesIn\n ? \"in\"\n : \"out\";\n const options: FaultOptions = {\n ...(direction === undefined ? {} : { direction }),\n ...(cell.icmp === undefined ? {} : { code: cell.icmp }),\n ...(cell.mtu === undefined ? {} : { above: cell.mtu }),\n };\n // a toxic of a cell whose fault is another one goes first: a slow close, then the close\n const toxicFirst = cell.toxic !== undefined && cell.fault !== \"toxic\";\n if (toxicFirst) await lab.toxic(cell.toxic!);\n // netem at the target shares its qdisc with the latency of the cell. At a hop, it is alone\n const netemAt: FaultPlace = cell.faultAt ?? \"target\";\n const netemOn = (fault: string | undefined) =>\n netemAt === \"target\" ? lab.netem(netemSpec(cell, fault), \"target\") : lab.netem(fault ?? null, netemAt);\n // an MTU drop goes where the long reply arrives: the namespace of the client\n const apply = async (): Promise<Run[\"fault\"]> => {\n switch (cell.fault) {\n case \"freeze-process\": {\n if (signalled) {\n const stamp = await lab.signal(\"STOP\");\n if (cell.hold !== undefined) {\n thawing = lab.signal(\"CONT\", stamp.t0 + valueIn(cell.hold, \"s\") * 1e9).then((thawed) => {\n heal = thawed;\n return thawed;\n });\n thawing.catch(() => undefined);\n }\n return stamp;\n }\n await peer.freeze();\n return null;\n }\n case \"fin\":\n await (server ? probe.kill() : lab.kill());\n return null;\n case \"unreachable\":\n return lab.fault(\"reject\", faultAt, { code: cell.icmp ?? \"host\" });\n case \"simplex\":\n return lab.fault(\"blackhole\", faultAt, options);\n case \"mtu-blackhole\":\n return lab.fault(\"mtu\", cell.faultAt ?? \"client\", { above: cell.mtu ?? 1200 });\n case \"netem\":\n return netemOn(cell.netem);\n case \"rst\":\n return lab.fault(\"rst\", faultAt);\n // the router or the proxy of the topology is the fault, or a calibration has none, or the\n // server holds the reply by itself: nothing to inject\n case \"middlebox-forget\":\n case \"proxy-idle\":\n case \"app-stall\":\n case \"none\":\n return null;\n case \"toxic\":\n if (cell.toxic === undefined) throw new Error(`${cell.name} names no toxic`);\n return lab.toxic(cell.toxic);\n case \"server-close\":\n await lab.serverClose();\n return null;\n case \"silence\":\n return fabricOf().silence();\n case \"hop-event\": {\n if (cell.event === undefined) throw new Error(`${cell.name} names no event`);\n const stamp = await lab.event(cell.event);\n // a stopped proxy thaws at the end of its hold, from inside the VM, as a frozen target does\n if (\"signal\" in cell.event && cell.event.signal === \"STOP\" && cell.hold !== undefined && stamp !== null) {\n const thaw = { hop: cell.event.hop, signal: \"CONT\" } as const;\n thawing = lab.event(thaw, false, stamp.t0 + valueIn(cell.hold, \"s\") * 1e9).then((thawed) => {\n if (thawed === null) throw new Error(`the hop ${thaw.hop} gave no stamp for CONT`);\n heal = thawed;\n return thawed;\n });\n thawing.catch(() => undefined);\n }\n return stamp;\n }\n default:\n // a stall is a black hole that stops by itself\n return lab.fault(\"blackhole\", faultAt);\n }\n };\n const lift = async (): Promise<void> => {\n switch (cell.fault) {\n case \"freeze-process\":\n if (signalled) {\n if (thawing !== null) await thawing.catch(() => lab.signal(\"CONT\"));\n else await lab.signal(\"CONT\");\n return undefined;\n }\n return peer.thaw();\n case \"fin\":\n case \"middlebox-forget\":\n case \"proxy-idle\":\n case \"server-close\":\n case \"app-stall\":\n case \"none\":\n return undefined;\n case \"hop-event\":\n // a stopped proxy thaws, at once if its hold did not thaw it\n if (cell.event !== undefined && \"signal\" in cell.event && cell.event.signal === \"STOP\") {\n const thaw = { hop: cell.event.hop, signal: \"CONT\" } as const;\n if (thawing !== null) await thawing.catch(() => lab.event(thaw));\n else await lab.event(thaw);\n return undefined;\n }\n // the undo of a query on the console, for example RESUME after PAUSE\n if (cell.event !== undefined) await lab.event(cell.event, true);\n return undefined;\n case \"unreachable\":\n return lab.lift(\"reject\", faultAt, { code: cell.icmp ?? \"host\" });\n case \"simplex\":\n return lab.lift(\"blackhole\", faultAt, options);\n case \"mtu-blackhole\":\n return lab.lift(\"mtu\", cell.faultAt ?? \"client\", { above: cell.mtu ?? 1200 });\n case \"netem\":\n await netemOn(undefined);\n return undefined;\n case \"rst\":\n return lab.lift(\"rst\", faultAt);\n case \"toxic\":\n await lab.toxic(null);\n return undefined;\n case \"silence\":\n await fabricOf().clear();\n return undefined;\n default:\n return heal === null ? lab.lift(\"blackhole\", faultAt) : undefined;\n }\n };\n fault = await apply();\n try {\n // an idle time before the request: a router forgets the flow in it, or a keepalive keeps it\n if (cell.idleBefore !== undefined && cell.probe.mode !== \"idle\")\n await sleep(valueIn(cell.idleBefore, \"ms\"));\n // a client in a gap sends its second request by itself, a gap after its first reply\n if ((cell.probe.mode === \"inflight\" || cell.probe.mode === \"stream\" || cell.probe.mode === \"schedule\") && !replyInFlight) await go();\n const { prediction } = cell;\n const http = cell.probe.http !== undefined;\n if (prediction.detects !== null && prediction.driver !== undefined) {\n // a driver cell: each of its bands ends, or its silent window passes from the fault\n if (prediction.detects) {\n await driverOutcome(cell, () => ({ ...partial(), fault }), driverWithin(cell));\n } else {\n await sleep(valueIn(prediction.window, \"s\") * 1_000);\n }\n await sleep(TAIL_MS);\n } else if (cell.probe.mode === \"gap\") {\n // the run ends when the second request does: its outcome is a part of the record\n const gap = cell.probe.http?.gap === undefined ? 0 : valueIn(cell.probe.http.gap, \"s\");\n const window = valueIn(prediction.detects ? prediction.high : prediction.window, \"s\");\n await probe.until(HTTP_DONE, (gap + window) * 2_000 + 10_000).catch(() => undefined);\n if (prediction.detects === null && prediction.counts !== undefined) await linesCounted(lab, serverFrom, prediction.counts);\n } else if (cell.fault === \"stall\") {\n if (cell.stall === undefined) throw new Error(`${cell.name} says no stall's length`);\n // the injector holds the end in the VM until the length of the stall after the send. An idle\n // client sends only the pings of its heartbeat: the stall counts from its first ping into it\n const window = valueIn(prediction.detects ? prediction.high : prediction.window, \"s\");\n const sent =\n cell.probe.mode === \"idle\"\n ? await pingSent(probe, fault?.t1 ?? 0, window * 1_000)\n : await requestSent(probe, 5_000);\n heal = await lab.heal(faultAt, sent.t + valueIn(cell.stall, \"s\") * 1e9);\n await probe.until([\"data\", \"error\", \"eof\", \"drop\"], window * 1_000).catch(() => undefined);\n } else if (cell.fault === \"silence\") {\n // the routers end this stall: the later move of the two leaves is its end. The verdict of a\n // stall reads it, thus a move outside the band of the cell makes the run void\n const window = valueIn(prediction.detects ? prediction.high : prediction.window, \"s\");\n await requestSent(probe, 5_000);\n await probe.until([\"data\", \"error\", \"eof\", \"drop\"], window * 1_000).catch(() => undefined);\n await sleep(MONITOR_MS);\n const moved = laterMove(fabricOf().routes.slice(routesFrom), fault?.t0 ?? 0);\n heal = moved === null ? null : { t0: moved, t1: moved };\n } else if (prediction.detects === null) {\n // a distribution: the stream ends by itself, or the connection does\n const window = valueIn(prediction.window, \"s\") * 1_000;\n await probe.until([\"done\", \"error\", \"eof\", \"deadline\"], window).catch(() => undefined);\n } else if (prediction.detects) {\n // a band whose reference can come late ends later: the run waits for its latest end\n const within = latestEndOf(prediction) * 2_000 + 10_000;\n if (cell.observer !== undefined && cell.observer !== \"client\") {\n // a target with its own detector writes a drop line when it drops the connection itself\n await observerError(cell, partial, within, () => lab.server.slice(serverFrom).some((line) => line.ev === \"drop\"));\n } else if (http && cell.probe.mode !== \"idle\") {\n // an HTTP client can send the request again on a new connection: its outcome ends the run\n await probe.until(HTTP_DONE, within).catch(() => undefined);\n } else {\n // an HTTP client writes `closed` when its pool closes an idle connection by itself, and\n // a program with its own detector writes `drop` when it drops the connection\n await probe.until([\"error\", \"eof\", \"deadline\", \"drop\", ...(http ? [\"closed\"] : [])], within).catch(() => undefined);\n }\n } else {\n await sleep(valueIn(prediction.window, \"s\") * 1_000);\n }\n } finally {\n await lift();\n if (toxicFirst) await lab.toxic(null);\n }\n // a thawed target answers the request that it held: the client sees the late reply. An idle\n // client sent no request\n if (cell.fault === \"freeze-process\" && !server && cell.probe.mode !== \"idle\" && cell.probe.mode !== \"schedule\")\n await probe.until([\"data\"], 5_000).catch(() => undefined);\n // the client tries its new connections after the fault lifted: one `dial` line for each try.\n // A measurement-only cell can give the waits too: the end of its connection has no band\n const expected = cell.prediction.detects !== false ? cell.prediction.reconnects : undefined;\n if (expected !== undefined) {\n const waits = expected.waits.reduce((sum, wait) => sum + valueIn(wait.high, \"s\"), 0);\n await dials(probe, 1 + expected.waits.length, waits * 2_000 + 5_000);\n }\n }\n } finally {\n await probe.stop();\n }\n // the prober drains its ring each 20 ms. Its next clock line closes the records of the run\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n return {\n environment,\n index,\n events: [...probe.events],\n fault,\n ...(cell.fault === \"stall\" || cell.fault === \"silence\" || thawing !== null ? { heal } : {}),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost,\n ...placed,\n ...(lab.topology === null ? {} : { middlebox: lab.middlebox.slice(middleboxFrom) }),\n ...(cell.target.lines === true ? { server: lab.server.slice(serverFrom) } : {}),\n ...(lab.fabric === undefined || sessions === undefined\n ? {}\n : { fabric: { routes: lab.fabric.routes.slice(routesFrom), established: { before: sessions, after: await lab.fabric.sessions() } } }),\n };\n};\n\n/** This function divides a count of runs across environments, as equally as possible. */\nexport const spread = (runs: number, environments: number): number[] =>\n Array.from(\n { length: environments },\n (_, at) => Math.floor(runs / environments) + (at < runs % environments ? 1 : 0),\n ).filter((count) => count > 0);\n\n/**\n * This function tells if the fault of a cell ends its environment. A server that stopped cannot serve\n * the next run. Also, a cell can say that its fault changes the environment (`fresh`).\n */\nconst endsEnvironment = (cell: Cell): boolean =>\n cell.fresh === true || (cell.fault === \"fin\" && (cell.observer === undefined || cell.observer === \"client\"));\n\n/** This function says one line for a run. */\nconst line = (cell: Cell, run: Run, read: Measured): string =>\n `${cell.name}: env ${run.environment} ${run.warmup === true ? \"warm-up\" : `run ${run.index}`} ${read.outcome.kind}` +\n `${read.elapsed === null ? \"\" : ` ${read.elapsed.value} s`}` +\n `${read.void === null ? \"\" : ` (void: ${read.void})`}`;\n\n/** This function adds to a run the share of the CPU that the host took while the run operated. */\nconst withSteal = async (work: () => Promise<Run>): Promise<Run> => {\n const before = readCpu();\n const run = await work();\n const after = readCpu();\n const steal = before === null || after === null ? null : stealShare(before, after);\n return steal === null ? run : { ...run, steal };\n};\n\n/**\n * This function does the part of the runs of a cell in one environment, and records its manifest.\n * A warm-up goes first, and the verdict does not count it. On a loaded machine, a new environment is\n * sometimes slow at first: its first exec, its first client, its first fault. The warm-up\n * of a cell whose fault ends the environment is a dry run, without the fault.\n */\nconst inEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n if (cell.group !== undefined) return inGroupEnvironment(cell, environment, count, say);\n if (cell.replicaSet !== undefined) return inReplicaSetEnvironment(cell, environment, count, say);\n if (cell.cluster !== undefined) return inClusterEnvironment(cell, environment, count, say);\n if (cell.kafka !== undefined) return inKafkaEnvironment(cell, environment, count, say);\n if (cell.pair !== undefined) return inPairEnvironment(cell, environment, count, say);\n const lab = await openLab(cell.target, cell.client ?? cell.probe.driver?.name ?? \"tcp\", cell.topology);\n try {\n // the settings of the target first: Redis applies tcp-keepalive to a client when it accepts it\n const settings = await lab.configure(cell.targetSettings ?? {});\n const targetSysctls = await lab.targetSysctl(cell.targetSysctls ?? {});\n if (cell.targetSetup !== undefined) await lab.setup(cell.targetSetup);\n // netem and a length match act on segments only when TSO, GSO and GRO are off on the two ends,\n // and on the hop that the fault is at\n if (cell.fault === \"mtu-blackhole\" || cell.fault === \"netem\") {\n await lab.offload(false, \"target\");\n await lab.offload(false, \"client\");\n if (isHopPlace(cell.faultAt)) await lab.offload(false, cell.faultAt);\n }\n // a latency is on the path before the client connects, thus its round trip and RTO include it\n const latency = netemSpec(cell, undefined);\n if (latency !== null) await lab.netem(latency, \"target\");\n // the first connection must not wait for ARP: under a delay, that is a longer first round trip\n await lab.warm();\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls), settings, targetSysctls);\n // after the first connection: a rule that starts conntrack must not count the packets of the warm-up\n const missing = await lab\n .namespaceSetup(cell.namespaceSetup ?? [])\n .then(() => lab.hostSysctl(cell.hostSysctls ?? []))\n .then(\n () => undefined,\n (error: unknown) => (error instanceof Error ? error.message : String(error)),\n );\n // each run records the jitter of its program, which sets the window of its pairings\n const timed = (run: Run): Run => ({ ...run, jitter: jitterOf(cell, run), ...(missing === undefined ? {} : { missing }) });\n const warmed = timed(await withSteal(() => once(lab, cell, environment, -1, endsEnvironment(cell))));\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = timed(await withSteal(() => once(lab, cell, environment, index)));\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n const host = await lab.restoreHost();\n return { manifest: host.length === 0 ? manifest : { ...manifest, host }, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a group cell in one environment. The warm-up is a\n * whole run with its fault, because no fault of a group ends its environment. A server that a\n * fin stopped starts again, and the group converges before each run.\n */\nconst inGroupEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openGroupLab(cell.group!, { watchSentinels: cell.calibrates === \"sentinels\" });\n try {\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const warmed = await groupOnce(lab, cell, environment, -1);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await groupOnce(lab, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a replica set cell in one environment. The warm-up\n * is a whole run with its fault, as for a group under Sentinels. The set converges before each run.\n */\nconst inReplicaSetEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openReplicaSetLab(cell.replicaSet!, cell.drill !== undefined);\n const once = cell.drill === undefined ? replicaSetOnce : drillOnce;\n try {\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const warmed = await once(lab, cell, environment, -1);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await once(lab, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a pair cell in one environment. The warm-up is a dry\n * run. The run promotes the standby, thus a pair cell has an environment for each run.\n */\nconst inPairEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openLab(cell.target, cell.client ?? cell.probe.driver?.name ?? \"tcp\", cell.topology);\n try {\n await lab.warm();\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const standby = await openStandby(lab, cell);\n const warmed = await pairOnce(lab, standby, cell, environment, -1, true);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await pairOnce(lab, standby, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a cluster cell in one environment. The warm-up is a\n * whole run with its fault, as for a replica set. The queue converges before each run.\n */\nconst inClusterEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openClusterLab(cell.cluster!);\n try {\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const warmed = await clusterOnce(lab, cell, environment, -1);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await clusterOnce(lab, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a Kafka cell in one environment. The warm-up is a whole\n * run with its fault, as for a cluster. Each run makes its own topic.\n */\nconst inKafkaEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openKafkaLab(cell.kafka!);\n const once = cell.kafka!.pause === undefined ? kafkaOnce : kafkaPauseOnce;\n try {\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const warmed = await once(lab, cell, environment, -1);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await once(lab, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the runs of a cell. They go across new environments, and each environment records\n * its manifest. Then the verdict judges the runs. A median across the edge of the band extends\n * the cell from 11 runs to 22, and then to 44, each extension in new environments. With a\n * concurrency of more than one, that many environments operate at the same time, each with its\n * own prober. The runs then go across at least as many environments.\n *\n * Each environment does a warm-up first, and the result keeps it apart from the counted runs.\n */\nexport const runCell = async (\n cell: Cell,\n say: (line: string) => void = () => {},\n): Promise<CellResult> => {\n const started = new Date().toISOString();\n const manifests: Manifest[] = [];\n const runs: Run[] = [];\n const warmups: Run[] = [];\n const concurrency = Math.max(1, cell.concurrency ?? 1);\n let target: number = cell.runs;\n let next = 0;\n for (;;) {\n const counts = spread(target - runs.length, Math.max(cell.environments, concurrency));\n for (let at = 0; at < counts.length; at += concurrency) {\n const batch = counts.slice(at, at + concurrency).map((count) => ({ count, env: next++ }));\n const done = await Promise.all(\n batch.map(({ count, env }) => inEnvironment(cell, env, count, say)),\n );\n for (const each of done) {\n manifests.push(each.manifest);\n // each run carries the HZ of its environment, which the rule of a late timer reads\n const hz = each.manifest.hz === null ? undefined : Number(each.manifest.hz);\n const withHz = (run: Run): Run => (hz === undefined ? run : { ...run, hz });\n runs.push(...each.runs.map(withHz));\n warmups.push(withHz(each.warmup));\n }\n }\n const { measured, verdict } = judge(cell, runs);\n const larger = STEPS.find((step) => step > runs.length);\n if (verdict.decision !== \"extend\" || larger === undefined) {\n const at = { started, ended: new Date().toISOString() };\n return { cell, manifests, runs, warmups, measured, verdict, at };\n }\n target = larger;\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiBA,MAAa,gBAAgB;;AAG7B,MAAM,aAAa,OAAe,OAAuB,IAAI,SAAS;;;;;;AAOtE,MAAa,UAAU,QAA+B,SAAmC;CACvF,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,CAAC,EAAE;CAChE,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,OAAO,UAAU,QAAQ,OAAO,MAAM,KAAA,CAAS;AACjD;;AAUA,MAAM,gBAAgB,WAA6B,OAAO,WAAW,aAAa,SAAS,OAAO,SAAS;;AAG3G,MAAM,aAAa,QAA+B,OAAe,MAAgB,QAAqC;CACpH,MAAM,uBAAO,IAAI,IAAoB;CACrC,MAAM,uBAAO,IAAI,IAAoB;CACrC,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,QAAQ,MAAM;EACpB,IAAI,OAAO,UAAU,YAAa,QAAQ,KAAA,KAAa,MAAM,SAAS,KAAM;EAC5E,IAAI,MAAM,OAAO,QAAQ,KAAK,IAAI,OAAO,UAAU,OAAO,MAAM,CAAC,CAAC;EAClE,IAAI,MAAM,OAAO,WAAW;GAC1B,KAAK,IAAI,OAAO,UAAU,OAAO,MAAM,CAAC,CAAC;GACzC,IAAI,aAAa,MAAM,SAAS,GAAG,UAAU;EAC/C;CACF;CACA,MAAM,cAA4B,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS;EAAE;EAAO,MAAM;EAAI,MAAM,KAAK,IAAI,KAAK,KAAK;CAAK,EAAE;CACrH,MAAM,MAAM,OAAO,QAAQ,QAAQ,UAAU,KAAK,IAAI,QAAQ,UAAU,OAAO,MAAM,CAAC,CAAC,GAAG,CAAC;CAC3F,OAAO;EAAE,GAAG,YAAY,MAAM,aAAa,GAAG;EAAG;CAAO;AAC1D;;AAGA,MAAa,YAAY;;AAGzB,MAAa,cAAc;;;;;AAM3B,MAAa,cAAc,YAAyG;CAClI,IAAI,QAAQ,WAAW,GAAG,MAAM,IAAI,WAAW,yCAAyC;CACxF,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,MAAM,IAAI,WAAW,4BAA4B,OAAO,KAAK;EACvF,IAAI,OAAO,SAAS,WAAW,GAAG,MAAM,IAAI,WAAW,cAAc,OAAO,IAAI,gBAAgB;EAChG,KAAK,IAAI,OAAO,GAAG;CACrB;CACA,MAAM,YAAY,QAAQ,KAAK,YAAY;EAAE,KAAK,OAAO;EAAK,UAAU,SAAS,OAAO,KAAK,SAAS,OAAO,KAAK,OAAO;EAAG,UAAU,OAAO;CAAS,EAAE;CACxJ,OAAO;EACL,SAAS,UAAU,KAAK,EAAE,KAAK,UAAU,YAAY;GAAE;GAAK,UAAU;EAAK,EAAE;EAC7E,SAAS,KAAK,UAAU;GAAE,QAAQ;GAAa,SAAS;EAAU,CAAC;CACrE;AACF;;;;;;;AAQA,MAAa,iBACX,QACA,YAC2F;CAC3F,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,CAAC,EAAE;CAChE,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,MAAM,OAAO,QAAQ,KAAK,WAAW,CAAC,OAAO,KAAK,UAAU,QAAQ,OAAO,OAAO,UAAU,OAAO,GAAG,CAAC,CAAU;CACjH,MAAM,WAAW,KAAK,KAAK,GAAG,aAAa,OAAO;CAClD,MAAM,OAAO,UAAwC,SAAS,QAAQ,OAAO,YAAY,QAAQ,MAAM,OAAO,GAAG,CAAC;CAClH,MAAM,QAAQ,UAAmD,SAAS,QAAQ,KAAK;CACvF,OAAO;EACL,MAAM;GACJ,SAAS,KAAK,YAAY,QAAQ,OAAO;GACzC,QAAQ,KAAK,YAAY,QAAQ,MAAM;GACvC,YAAY,KAAK,YAAY,QAAQ,UAAU;GAC/C,QAAQ,KAAK,YAAY,QAAQ,UAAU,CAAC;GAC5C,SAAS,MAAM,YAAY,QAAQ,OAAO;GAC1C,SAAS,MAAM,YAAY,QAAQ,OAAO;GAC1C,KAAK,MAAM,YAAY,QAAQ,GAAG;GAClC,UAAU,MAAM,YAAY,QAAQ,QAAQ;EAC9C;EACA,SAAS,OAAO,YAAY,IAAI;CAClC;AACF;;AA8BA,MAAMA,cAAY,WAChB,OAAO,WAAW,IACd,OACA;CACE,KAAK,SAAS,SAAS,QAAQ,IAAK,cAAc,GAAG,IAAI;CACzD,KAAK,SAAS,SAAS,QAAQ,KAAM,cAAc,GAAG,IAAI;CAC1D,KAAK,SAAS,OAAO,QAAQ,MAAM,UAAU,KAAK,IAAI,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI;AAC9E;;AAGN,MAAM,MAAM;;;;;;;AAQZ,MAAM,eACJ,MACA,QACA,aACwD;CACxD,MAAM,OAAO,QAAQ,KAAK,MAAM,IAAI;CACpC,MAAM,OAAa;EACjB,MAAM;EACN,IAAI,CAAC;EACL,SAAS,CAAC;GAAE,MAAM;GAAY,SAAS;GAAW,MAAM;GAAM,UAAU,KAAK;GAAU,OAAO;EAAK,CAAC;EACpG,MAAM;CACR;CASA,MAAM,MAAM,YAAY,MAAM;EAP5B,MAAM;EACN,QAAQ;EACR,IAAI;EACJ,MAAM,CAAC,kBAAkB;EACzB,WAAW,CAAC;EACZ,UAAU,CAAC;GAAE,MAAM;GAAY,SAAS;GAAW;GAAQ;EAAS,CAAC;CAEpC,GAAG,EAAE,KAAK,IAAI,CAAC;CAClD,MAAM,OAAO,OAAO,SAAS,SAAS,WAAW,IAAI,OAAO,SAAS,CAAC,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,UAAU,cAAc;CAC5H,MAAM,MAAM,KAAK,QAAQ,KAAA,IAAY,OAAO,QAAQ,KAAK,KAAK,IAAI;CAClE,MAAM,QAAQ,QAAQ,QAAS,SAAS,QAAQ,QAAQ;CACxD,MAAM,QAAQ,QAAQ,OAAO,SAAS,KAAK,OAAO,OAAO,IAAI,IAAI,KAAK;CAEtE,MAAM,UAAU,IAAI,YAAY,YAAY,CAAC,QAAQ,iCAAiC,IAAI;CAC1F,OAAO;EACL,OAAO,IAAI,YAAY,YAAY;EACnC,OAAO,IAAI,KAAK,WAAW,IAAI,kBAAkB,SAAS,OAAO,iBAAiB,MAAM,KAAK,KAAK,WAAW,MAAM,IAAI,QAAQ,IAAI,IAAI;CACzI;AACF;;;;;;;;AASA,MAAM,mBAAmB,OAAe,UAAkB,WAAwE;CAUhI,MAAM,UAAU,YAAY;EATP,MAAM;EAAY,IAAI,CAAC;EAAG,SAAS,CAAC;GAAE,MAAM;GAAQ,SAAS;GAAY;EAAM,CAAC;EAAG,MAAM;CAS/E,GAAG;EAPhC,MAAM;EACN,QAAQ;EACR,IAAI;EACJ,MAAM,CAAC,kBAAkB;EACzB,WAAW,CAAC;EACZ,UAAU,CAAC;GAAE,MAAM;GAAQ,SAAS;GAAY;GAAU;EAAO,CAAC;CAE7B,GAAG,EAAE,KAAK,IAAI,CAAC;CACtD,OAAO;EACL,OAAO,QAAQ,YAAY;EAC3B,OAAO,GAAG,SAAS,MAAM,OAAO,yCAAyC,QAAQ,IAAI,MAAM,QAAQ,QAAQ,IAAI,QAAQ;CACzH;AACF;;;;;;AAcA,MAAa,eACX,YACA,SACkB;CAClB,MAAM,QAAQ,QAAQ,WAAW,KAAK,IAAI;CAC1C,MAAM,UAAU,KAAK,SAAS,QAAQ;EACpC,IAAI,IAAI,SAAS,KAAA,GAAW,OAAO,CAAC;GAAE,KAAK,IAAI;GAAM,KAAK;EAAwC,CAAC;EACnG,MAAM,QAAQ,aAAa,IAAI,MAAM,KAAK;EAC1C,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;GAAE,KAAK,IAAI;GAAM,KAAK,MAAM;EAAO,CAAC;CAChE,CAAC;CACD,MAAM,WAAW,KAAK,SAAS,QAAS,IAAI,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAE;CACjF,MAAM,UAAU,SAAS,SAAS,YAAY,QAAQ,OAAO;CAC7D,MAAM,WAAW,SAAS,SAAS,YAAY,QAAQ,QAAQ;CAC/D,MAAM,QAAQ,WAAW,MAAM,KAAK,SAAS,YAAY,MAAM,SAAS,QAAQ,CAAC;CACjF,MAAM,SAAS,UAAwC,SAAS,QAAQ,KAAK,YAAY,MAAM,MAAM,OAAO,GAAG,CAAC;CAChH,MAAM,UAAU,OAAO,YAAY,QAAQ,OAAO;CAClD,MAAM,SAAS,OAAO,YAAY,QAAQ,MAAM;CAChD,MAAM,aAAa,OAAO,YAAY,QAAQ,UAAU;CACxD,MAAM,SAAS,OAAO,YAAY,QAAQ,UAAU,CAAC;CACrD,MAAM,WAAW,WAAW,aAAa,KAAA,IAAY,KAAA,IAAY,gBAAgB,WAAW,UAAU,SAAS,aAAa,QAAQ,OAAO;CAC3I,OAAO;EACL,OAAO,KAAK,SAAS,KAAK,QAAQ,WAAW,KAAK,MAAM,OAAO,SAAS,KAAK,KAAK,MAAM,UAAU,SAAS;EAC3G;EACA,MAAM;GACJ;GACA;GACA;GACA;GACA,SAASA,WAAS,CAAC,GAAG,SAAS,GAAG,QAAQ,CAAC;GAC3C,SAASA,WAAS,SAAS,SAAS,YAAY,QAAQ,OAAO,CAAC;GAChE,KAAKA,WAAS,SAAS,SAAS,YAAY,QAAQ,IAAI,KAAK,QAAQ,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC;GACpF,OAAO,MAAM,KAAK,SAAS,KAAK,KAAK;GACrC,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,SAAS,MAAM;EAC/D;CACF;AACF;;;;ACnQA,MAAa,gBAAgB,YAM3B,GAAG,QAAQ,aAAa,QAAQ,UAAU,cAAc,GAAG,IAAI,QAAQ,YAAY,OAAO,YAAa,QAAQ,SAAS;;;;;;;;AAS1H,MAAa,QAAkB,SAAS,GAAG,IAAI;;;;;;AAO/C,MAAa,SAAmB;;AAGhC,MAAa,WAAW,SAA8D,KAAK,SAAS;;;;;;;;AAmBpG,MAAa,aAAa,MAAiD,QAAsC;CAC/G,MAAM,QAAQ,QAAQ,IAAI;CAC1B,MAAM,QAAQ,IAAI,QAAQ,SAAS;CACnC,OAAO;EAAE;EAAO,OAAO,UAAU,QAAQ,QAAQ,OAAO,GAAG,IAAI,QAAQ,OAAO,GAAG,IAAI,QAAQ;CAAM;AACrG;;;;;;AAOA,MAAa,cACX,MACA,QAAkB,UACiF;CACnG,MAAM,WAAW,KAAK,SAAS,QAAS,IAAI,YAAY,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,OAAO,CAAE;CACvF,IAAI,SAAS,WAAW,GAAG,OAAO;CAClC,MAAM,WAAW,WAA0C,OAAO,QAAQ,MAAM,SAAU,QAAQ,MAAM,GAAG,IAAI,QAAQ,MAAM,GAAG,IAAI,OAAO,IAAK;CAChJ,MAAM,SAAS,SAAS,SAAS,YAAa,QAAQ,UAAU,OAAO,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAE;CAC5F,OAAO;EACL,OAAO,OAAO,WAAW,IAAI,OAAO,QAAQ,MAAM;EAClD,OAAO,QAAQ,SAAS,KAAK,YAAY,QAAQ,KAAK,CAAC;EACvD,SAAS,SAAS,QAAQ,YAAY,QAAQ,QAAQ,OAAO,GAAG,IAAI,QAAQ,OAAO,GAAG,CAAC,CAAC,CAAC;CAC3F;AACF;;;;;;;AAQA,MAAa,cAAc,QAAgB,IAAwB,UAA6B;CAC9F,IAAI,SAAS,GAAG,OAAO;CACvB,IAAI,OAAO,KAAA,KAAa,EAAE,KAAK,IAAI,OAAO;CAC1C,OAAO,SAAS,MAAM,KAAK,IAAI,IAAI,IAAI,QAAQ,OAAO,GAAG,CAAC;AAC5D;;AAEA,MAAa,WAAW;;AAExB,MAAa,QAAQ;CAAC;CAAI;CAAI;AAAE;AAmHhC,MAAM,KAAK,UAA4B,SAAS,KAAK,MAAM,QAAQ,GAAG,IAAI,KAAK,GAAG;AAClF,MAAM,QAAQ,QAA0B,OAAO,IAAI,YAAY,OAAO,IAAI;;;;;AAM1E,MAAa,cAAc,QAA2B,MAAsB,eAAe,QAAQ,GAAG,cAAc;;AAGpH,MAAa,YAAY,UAA8C;CACrE,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,MAAM,SAAS,MAAM,KAAK,SAAS,QAAQ,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAC3E,OAAO;EACL,OAAO,OAAO;EACd,QAAQ,EAAEC,OAAO,MAAM,CAAC;EACxB,KAAK,EAAE,WAAW,QAAQ,GAAI,CAAC;EAC/B,MAAM,EAAE,WAAW,QAAQ,IAAK,CAAC;EACjC,KAAK,EAAE,OAAO,GAAG,EAAE,CAAE;CACvB;AACF;;AAGA,MAAM,mBAAmB,SAAsD;CAC7E,MAAM,OAAO,KAAK,SAAS,QAAS,IAAI,eAAe,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,UAAU,CAAE;CACzF,IAAI,KAAK,WAAW,GAAG,OAAO,KAAA;CAC9B,MAAM,OAAO,QAA8C,KAAK,QAAQ,OAAO,QAAQ,QAAQ,IAAI,MAAM,CAAC;CAC1G,MAAM,OAAO,QACX,KAAK,MAAM,QAAQ,IAAI,SAAS,IAAI,IAAI,KAAK,QAAQ,OAAO,QAAQ,SAAS,IAAI,QAAQ,IAAI,CAAC,IAAI;CACpG,MAAM,OAAO,QACX,KAAK,MAAM,QAAQ,IAAI,SAAS,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,QAAQ,CAAC,CAAC,IAAI;CAC1F,OAAO;EACL,YAAY,IAAI,YAAY;EAC5B,YAAY,IAAI,YAAY;EAC5B,KAAK,IAAI,KAAK;EACd,QAAQ,IAAI,QAAQ;EACpB,MAAM,IAAI,MAAM;EAChB,QAAQ,IAAI,QAAQ;EACpB,MAAM,IAAI,MAAM;EAChB,QAAQ,IAAI,QAAQ;EACpB,MAAM,IAAI,MAAM;CAClB;AACF;;AAGA,MAAM,mBAAmB,UACvB;CACE,GAAG,MAAM,WAAW,6BAA6B,MAAM,WAAW;CAClE,GAAI,MAAM,QAAQ,OAAO,CAAC,IAAI,CAAC,sBAAsB,MAAM,IAAI,uBAAuB;CACtF,GAAI,MAAM,WAAW,OAAO,CAAC,IAAI,CAAC,yBAAyB,MAAM,OAAO,iBAAiB;CACzF,GAAI,MAAM,WAAW,OAAO,CAAC,IAAI,CAAC,OAAO,MAAM,OAAO,QAAQ;CAC9D,QAAQ,MAAM,KAAK;CACnB,GAAI,MAAM,SAAS,OAAO,CAAC,IAAI,CAAC,OAAO,MAAM,KAAK,aAAa;CAC/D,GAAI,MAAM,WAAW,OAAO,CAAC,IAAI,CAAC,qCAAqC,MAAM,QAAQ;AACvF,CAAC,CAAC,KAAK,IAAI;;AAGb,MAAM,eAAe,WAAkC;CACrD,IAAI,WAAW,MAAM,OAAO;CAC5B,MAAM,MAAM,SAAmB,KAAK,MAAM,QAAQ,MAAM,GAAG,IAAI,GAAG,IAAI;CACtE,OAAO,UAAU,GAAG,OAAO,MAAM,EAAE,WAAW,GAAG,OAAO,GAAG,EAAE,aAAa,GAAG,OAAO,IAAI,EAAE,WAAW,GAAG,OAAO,GAAG,EAAE,SAAS,OAAO;AACtI;;;;;;;AAQA,MAAa,kBAAkB,WAAgD;CAC7E,MAAM,WAAWC,iBAAiB,QAAQ,GAAI;CAC9C,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI;AACrC;;;;;;;;;;;;;AAcA,MAAa,aAAa,YAAwB,MAA2B,QAAkB,UAAmB;CAChH,MAAM,OAAO,cAAc,YAAY,MAAM,KAAK;CAClD,MAAM,UAAU,KAAK,QAAQ,QAAQ,IAAI,SAAS,IAAI;CACtD,MAAM,QAAQ,QAAQ,MAAM,QAAQ,IAAI,YAAY,KAAA,CAAS,IAAI,aAAa,MAAM,OAAO,IAAI;CAC/F,MAAM,UAAU,YAAY,OAAO,OAAO;CAC1C,IAAI,WAAW,UAAU,KAAA,KAAa,CAAC,QAAQ,MAAM,QAAQ,IAAI,UAAU,KAAA,CAAS,GAAG,OAAO;CAC9F,OAAO;EAAE,GAAG;EAAS,OAAO,eAAe,YAAY,SAAS,KAAK;CAAE;AACzE;;;;;AAMA,MAAM,eAAe,SAAkB,YAA0C;CAC/E,MAAM,aAAa,QAAQ,SAAS,QAAS,IAAI,cAAc,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,SAAS,CAAE;CAChG,MAAM,QAAQ,QAAQ,SAAS,QAAS,IAAI,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAE;CACjF,MAAM,QAAQ,QAAQ,SAAS,QAAS,IAAI,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAE;CACjF,IAAI,WAAW,WAAW,KAAK,MAAM,WAAW,KAAK,MAAM,WAAW,GAAG,OAAO;CAChF,MAAM,MAAM,WAA2B,WAAW,OAAO,SAAS,GAAG,KAAK,MAAM,QAAQ,OAAO,QAAQ,GAAG,IAAI,GAAG,IAAI,IAAI;CACzH,MAAM,QAAQ,KAAK,IAAI,GAAG,GAAG,WAAW,KAAK,SAAS,KAAK,MAAM,MAAM,CAAC;CACxE,MAAM,YACJ,WAAW,WAAW,IAClB,KAAA,IACA;EACE,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,OACvC,SAAS,WAAW,SAAS,SAAU,KAAK,MAAM,QAAQ,KAAA,IAAY,CAAC,IAAI,CAAC,KAAK,MAAM,GAAI,CAAE,CAAC,CAChG;EACA,KAAK,SAAS,WAAW,SAAS,SAAU,KAAK,QAAQ,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,CAAE,CAAC;EACjF,aAAa,SAAS,WAAW,SAAS,SAAU,KAAK,gBAAgB,OAAO,CAAC,IAAI,CAAC,KAAK,WAAW,CAAE,CAAC;EACzG,SAAS,SAAS,WAAW,SAAS,SAAS,KAAK,QAAQ,CAAC;CAC/D;CACN,MAAM,WAAmC,CAAC;CAC1C,KAAK,MAAM,QAAQ,OAAO,SAAS,KAAK,YAAY,SAAS,KAAK,YAAY,KAAK;CACnF,MAAM,OAAO,MAAM,SAAS,SAAU,SAAS,OAAO,CAAC,IAAI,CAAC,IAAI,CAAE;CAElE,MAAM,OAAO,QAAQ,SAAS,QAAS,IAAI,WAAW,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,MAAM,CAAE;CACpF,MAAM,OACJ,MAAM,WAAW,IACb,KAAA,IACA;EAAE,QAAQ,SAAS,IAAI;EAAG,QAAQ,MAAM,SAAS,KAAK;EAAQ,GAAI,KAAK,WAAW,IAAI,CAAC,IAAI,EAAE,QAAQ,SAAS,IAAI,EAAE;CAAG;CAC7H,MAAM,QAAQ,KAAK,WAAW,IAAI,KAAK,QAAQ,KAAK,OAAO,iEAAiE,GAAG,SAAS,IAAI,CAAC,EAAE;CAC/I,MAAM,OAAO;EACX,GAAI,SAAS,KAAA,IACT,CAAC,IACD,CACE,oDAAoD,KAAK,OAAO,gBAAgB,GAAG,KAAK,MAAM,EAAE,sBAAsB,KAAK,WAAW,IAAI,KAAK,gCAAgC,KAAK,SAAS,QAAQ,EACvM;EACJ,GAAI,cAAc,KAAA,IACd,CAAC,IACD,CACE,gDAAgD,UAAU,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,yBAAyB,GAAG,UAAU,GAAG,EAAE,0BAA0B,GAAG,UAAU,WAAW,EAAE,sBACpL;EACJ,GAAI,MAAM,WAAW,IACjB,CAAC,IACD,CAAC,oBAAoB,OAAO,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,SAAS,OAAO,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE;CAC1G;CACA,OAAO;EACL,GAAG;EACH,GAAI,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU;EAC/C,GAAI,MAAM,WAAW,IAAI,CAAC,IAAI,EAAE,OAAO,SAAS;EAChD,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;EACrC,KAAK,GAAG,QAAQ,IAAI,SAAS,GAAG,IAAI,QAAQ,MAAM,GAAG,QAAQ,IAAI,GAAG,GAAG,KAAK,KAAK,GAAG;CACtF;AACF;;;;;AAMA,MAAM,gBAAgB,SAAkB,YAA0C;CAChF,MAAM,WAAmC,CAAC;CAC1C,KAAK,MAAM,OAAO,SAAS;EACzB,MAAM,QAAQ,IAAI,YAAY,QAAQ,IAAI,YAAY,KAAA,IAAY,sBAAsB,aAAa,IAAI,OAAO;EAChH,SAAS,UAAU,SAAS,UAAU,KAAK;CAC7C;CACA,MAAM,SAAS,OAAO,QAAQ,QAAQ,CAAC,CACpC,KAAK,CAAC,OAAO,OAAO,GAAG,EAAE,GAAG,OAAO,CAAC,CACpC,KAAK,IAAI;CACZ,OAAO;EACL,GAAG;EACH;EACA,KAAK,QAAQ,aAAa,aAAa,GAAG,QAAQ,IAAI,oBAAoB,OAAO,KAAK,QAAQ;CAChG;AACF;;AAGA,MAAM,eAAe,WACnB,OAAO,WAAW,IAAI,OAAOD,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC;;AAGvE,MAAa,kBAAkB,YAAwB,SAA8B,QAAkB,UAAwB;CAC7H,MAAM,QAAQ,QAAQ,OAAO,GAAG;CAChC,MAAM,SAAS,WAAW,OAAO,WAAW,KAAA,IAAY,IAAI,QAAQ,WAAW,MAAM,QAAQ,GAAG;CAChG,MAAM,UAAU,WAAW,OAAO,UAAU,CAAC,EAAA,CAAG,KAAK,SAAuB;EAC1E,MAAM,WAAW;GAAE,KAAK,EAAE,QAAQ,KAAK,KAAK,GAAG,IAAI,KAAK;GAAG,MAAM,EAAE,QAAQ,KAAK,MAAM,GAAG,IAAI,SAAS,KAAK;EAAE;EAC7G,MAAM,UAA+C,CAAC;EACtD,MAAM,SAAmB,CAAC;EAC1B,KAAK,MAAM,OAAO,SAAS;GACzB,MAAM,KAAK,IAAI,OAAO,OAAO,KAAK;GAClC,IAAI,OAAO,KAAA,GAAW;IAEpB,MAAM,MAAM,KAAK,MAAM,WAAW,GAAG,IAAI,0BAA0B;IACnE,QAAQ,KAAK;KAAE,KAAK,KAAK,GAAG;KAAG,KAAK,GAAG,IAAI,GAAG,KAAK;IAAQ,CAAC;IAC5D;GACF;GACA,MAAM,QAAQ,QAAQ,IAAI,GAAG;GAC7B,OAAO,KAAK,KAAK;GACjB,IAAI,QAAQ,QAAQ,SAAS,KAAK,GAAG,KAAK,QAAQ,QAAQ,SAAS,MAAM,GAAG,GAC1E,QAAQ,KAAK;IAAE,KAAK,KAAK,GAAG;IAAG,KAAK,GAAG,KAAK,MAAM,MAAM,MAAM,iBAAiB,SAAS,IAAI,MAAM,IAAI,SAAS,KAAK,MAAM;GAAK,CAAC;EACpI;EACA,OAAO,MAAM,GAAG,MAAM,IAAI,CAAC;EAC3B,OAAO;GACL,OAAO,KAAK;GACZ,MAAM;GACN,QAAQ,OAAO,WAAW,IAAI,OAAO,EAAEA,OAAO,MAAM,CAAC;GACrD;GACA,UAAU,QAAQ,WAAW,KAAK,OAAO,SAAS,IAAI,UAAU;EAClE;CACF,CAAC;CACD,MAAM,UAA4C,CAAC;CACnD,MAAM,OAAO,IAAI,IAAI,QAAQ,SAAS,QAAQ,OAAO,KAAK,IAAI,OAAO,UAAU,CAAC,CAAC,CAAY,CAAC;CAC9F,KAAK,MAAM,SAAS,MAAM;EACxB,MAAM,SAAS,QAAQ,SAAS,QAAQ;GACtC,MAAM,KAAK,IAAI,OAAO,OAAO;GAC7B,OAAO,OAAO,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC;EAClD,CAAC;EACD,QAAQ,SAAS,EAAEA,OAAO,OAAO,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC;CACzD;CACA,MAAM,aAAa,QAAQ,SAAS,QAAS,IAAI,OAAO,OAAO,SAAS,QAAQ,IAAI,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,MAAM,OAAO,KAAK,MAAM,CAAE;CAC9I,MAAM,YAAY,QAAQ,SAAS,QAAS,IAAI,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,MAAM,OAAO,GAAG,CAAE;CAClG,MAAM,UAAU,QAAQ,SAAS,QAAQ,IAAI,OAAO,OAAO,WAAW,CAAC,CAAC;CACxE,MAAM,yBAAS,IAAI,IAAsB;CACzC,KAAK,MAAM,OAAO,SAChB,KAAK,MAAM,SAAS,IAAI,OAAO,UAAU,CAAC,GAAG,OAAO,IAAI,MAAM,MAAM,CAAC,GAAI,OAAO,IAAI,MAAM,IAAI,KAAK,CAAC,GAAI,QAAQ,MAAM,OAAO,GAAG,CAAC,CAAC;CACpI,MAAM,OAAO,QAAQ,SAAS,QAAQ,IAAI,OAAO,QAAQ,CAAC,CAAC;CAC3D,MAAM,aAAa,QAAQ,SAAS,QAAQ;EAC1C,MAAM,SAAS,IAAI,OAAO,OAAO;EACjC,OAAO,WAAW,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,CAAC,OAAO,MAAM;CACtE,CAAC;CACD,OAAO;EACL;EACA;EACA,MAAM;GACJ,MAAM,WAAW;GACjB,OAAO,WAAW,QAAQ,KAAK,MAAM,MAAM,GAAG,CAAC;GAC/C,QAAQ,YAAY,UAAU;GAC9B,KAAK,WAAW,WAAW,IAAI,OAAO,KAAK,IAAI,GAAG,UAAU;EAC9D;EACA,KAAK;GAAE,QAAQ,YAAY,SAAS;GAAG,KAAK,UAAU,WAAW,IAAI,OAAO,KAAK,IAAI,GAAG,SAAS;EAAE;EACnG,SAAS;GAAE,OAAO,QAAQ;GAAQ,MAAM,QAAQ,QAAQ,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC;EAAO;EAC5F,QAAQ,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa;GAAE,MAAM;GAAO,MAAM,OAAO;GAAQ,OAAO,EAAEA,OAAO,OAAO,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC;EAAE,EAAE;EACnI,GAAI,KAAK,WAAW,IAAI,CAAC,IAAI,EAAE,MAAM,SAAS,IAAI,EAAE;EACpD,GAAI,WAAW,OAAO,eAAe,KAAA,IACjC,CAAC,IACD,EACE,YAAY;GACV,MAAM,WAAW;GACjB,OAAO,WAAW,QAAQ,KAAK,MAAM,MAAM,GAAG,CAAC;GAC/C,QAAQ,YAAY,UAAU;GAC9B,KAAK,WAAW,WAAW,IAAI,OAAO,KAAK,IAAI,GAAG,UAAU;EAC9D,EACF;CACN;AACF;;AAGA,MAAM,iBAAiB,YAAwB,MAA2B,QAAkB,UAAmB;CAC7G,MAAM,UAAU,KAAK,QAAQ,QAAQ,IAAI,SAAS,IAAI;CACtD,MAAM,SAAS,KAAK,SAAS,QAAQ;CACrC,MAAM,UAAU,QACb,QAAQ,QAAQ,IAAI,YAAY,IAAI,CAAC,CACrC,KAAK,SAAS;EAAE,KAAK,KAAK,GAAG;EAAG,KAAK,IAAI;CAAS,EAAE;CACvD,MAAM,QAAQ;EAAE,SAAS,QAAQ;EAAQ;EAAQ,QAAQ;EAAM,gBAAgB;CAAK;CACpF,IAAI,QAAQ,WAAW,GACrB,OAAO;EAAE,GAAG;EAAO,UAAU;EAAgB,MAAM;EAAM;EAAS,KAAK;CAAiB;CAE1F,IAAI,WAAW,YAAY,MAAM;EAE/B,MAAM,MACJ,WAAW,UAAU,KAAA,IACjB,UACA,WAAW,UAAU,KAAA,IACnB,eACA,WAAW,UAAU,KAAA,IACnB,oBACA,WAAW,cAAc,KAAA,IACvB,oBACA,KAAA;EACZ,IAAI,QAAQ,KAAA,GAAW;GACrB,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC;GACrD,OAAO;IACL,GAAG;IACH,UAAU,QAAQ,IAAI,UAAU;IAChC,MAAM;IACN;IACA,KAAK,GAAG,QAAQ,SAAS,IAAI,MAAM,QAAQ,OAAO,4BAA4B,IAAI,IAAI,WAAW;GACnG;EACF;EAEA,MAAM,UAAU,QAAQ,SAAS,QAAS,IAAI,cAAc,KAAA,IAAY,CAAC,IAAI,CAAC,IAAI,SAAS,CAAE;EAC7F,IAAI,QAAQ,SAAS,GAAG;GACtB,MAAM,MAAM,QAAQ,EAAE,CAAE;GACxB,MAAM,KAAK,SAAS,QAAQ,SAAS,SAAS,KAAK,EAAE,CAAC;GACtD,MAAM,OAAO,SAAS,QAAQ,SAAS,SAAS,KAAK,IAAI,CAAC;GAC1D,OAAO;IACL,GAAG;IACH,UAAU;IACV,MAAM;IACN,SAAS,CAAC;IACV,QAAQ,IAAI,UAAU;IACtB,OAAO;KAAE;KAAK;KAAI;IAAK;IACvB,KAAK,GAAG,QAAQ,OAAO,iBAAiB,IAAI,sBAAsB,YAAY,EAAE,EAAE,sBAAsB,YAAY,IAAI,EAAE,IAAI,WAAW;GAC3I;EACF;EAEA,IAAI,WAAW,SAAS,KAAA,GAAW;GACjC,MAAM,QAAQ,QACX,SAAS,QAAS,IAAI,YAAY,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,SAAS,GAAG,CAAC,CAAE,CAAC,CAC3E,MAAM,GAAG,MAAM,IAAI,CAAC;GACvB,MAAM,wBAAQ,IAAI,IAAoB;GACtC,KAAK,MAAM,OAAO,SAAS;IACzB,MAAM,OAAO,IAAI,QAAQ,SAAS,UAAU,IAAI,QAAQ,QAAQ,IAAI,QAAQ;IAC5E,MAAM,IAAI,OAAO,MAAM,IAAI,IAAI,KAAK,KAAK,CAAC;GAC5C;GACA,MAAM,WAAW,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,OAAO,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,KAAK,IAAI;GACxE,MAAM,QACJ,MAAM,WAAW,IACb,YACA,UAAU,EAAEA,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,UAAU,WAAW,KAAK,WAAW,EAAE,MAAM,EAAG,CAAC,CAAC,MAAM,IAAI,EAAE,MAAM,GAAG,EAAE,CAAE,CAAC,CAAC,MAAM;GAE1H,MAAM,EAAE,WAAW;GACnB,IAAI,WAAW,KAAA,GAAW;IACxB,MAAM,QAAQ,OAAO,KAAK,SAAS,GAAG,KAAK,KAAK,GAAG,KAAK,OAAO,CAAC,CAAC,KAAK,IAAI;IAC1E,OAAO;KACL,GAAG;KACH,UAAU,QAAQ,WAAW,IAAI,UAAU;KAC3C,MAAM;KACN;KACA,QAAQ,MAAM,WAAW,IAAI,OAAO,EAAEA,OAAO,KAAK,CAAC;KACnD,KAAK,GAAG,QAAQ,SAAS,QAAQ,OAAO,MAAM,QAAQ,OAAO,+BAA+B,MAAM,KAAK,SAAS,IAAI,MAAM,IAAI,WAAW;IAC3I;GACF;GAEA,MAAM,OAAO,WAAW,OAAO;GAC/B,MAAM,SAAS,WAAW,OAAO;GACjC,IAAI,SAAS,KAAA,KAAa,WAAW,KAAA,GAAW;IAC9C,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,QAAQ,CACZ,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC,gBAAgB,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,GACxE,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,CAAC,iBAAiB,OAAO,IAAI,IAAI,OAAO,KAAK,EAAE,CACjF;IACA,OAAO;KACL,GAAG;KACH,UAAU,QAAQ,IAAI,UAAU;KAChC,MAAM;KACN;KACA,QAAQ,MAAM,WAAW,IAAI,OAAO,EAAEA,OAAO,KAAK,CAAC;KACnD,KAAK,GAAG,QAAQ,SAAS,IAAI,MAAM,QAAQ,OAAO,2BAA2B,MAAM,KAAK,mBAAmB,EAAE,IAAI,SAAS,IAAI,MAAM,IAAI,WAAW;IACrJ;GACF;GAEA,MAAM,SAAS,QAAQ,QAAQ,SAAS,QAAQ,MAAM,QAAQ,KAAK,GAAG,MAAM,KAAK,OAAO,IAAI,cAAc,KAAA,CAAS,CAAC;GACpH,MAAM,OAAO,OAAO,WAAW,IAAI,KAAK,IAAI,OAAO,OAAO;GAC1D,OAAO;IACL,GAAG;IACH,UAAU;IACV,MAAM;IACN,SAAS;IACT,QAAQ,MAAM,WAAW,IAAI,OAAO,EAAEA,OAAO,KAAK,CAAC;IACnD,KAAK,GAAG,QAAQ,OAAO,kBAAkB,SAAS,IAAI,MAAM,GAAG,KAAK,GAAG,WAAW;GACpF;EACF;EAEA,IAAI,QAAQ,MAAM,QAAQ,IAAI,SAAS,KAAA,CAAS,GAAG;GACjD,MAAM,SAAS,YACb,WAAW,QAAQ;IAAE,KAAK,SAAS,OAAO,kBAAkB,IAAI;IAAG,OAAO,CAAC;GAAE,GAC7E,QAAQ,KAAK,SAAS;IAAE,MAAM,KAAK,GAAG;IAAG,MAAM,IAAI;GAAK,EAAE,CAC5D;GACA,MAAM,eAAe,OAAO,KAAK,SAAS;GAC1C,MAAM,SAAS,OAAO,KAAK,WAAW,IAAI,KAAK,KAAK,OAAO,KAAK,OAAO;GACvE,MAAM,OAAO;IAAC,GAAG,QAAQ,OAAO,uBAAuB,OAAO,KAAK,QAAQ,aAAa,OAAO,KAAK,OAAO,aAAa,OAAO,KAAK,WAAW,gBAAgB,OAAO;IAAI,GAAG,OAAO,KAAK;IAAO,GAAI,OAAO,KAAK,aAAa,KAAA,IAAY,CAAC,IAAI,CAAC,OAAO,KAAK,QAAQ;IAAI,WAAW;GAAG,CAAC,CAAC,KAAK,GAAG;GAC/R,OAAO;IACL,GAAG;IACH,UAAU,WAAW,SAAS,KAAA,IAAY,aAAa,OAAO,QAAQ,UAAU;IAChF,MAAM;IACN,SAAS,OAAO;IAChB,QAAQ,iBAAiB,KAAA,IAAY,OAAO,EAAE,QAAQ,cAAc,GAAG,CAAC;IACxE,GAAI,OAAO,KAAK,YAAY,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,OAAO,KAAK,QAAQ,KAAK,GAAG,CAAC,EAAE;IAC5F,MAAM,OAAO;IACb,KAAK;GACP;EACF;EACA,MAAM,UAAU,QACb,SAAS,SAAS,IAAI,WAAW,CAAC,EAAA,CAAG,KAAK,WAAW,QAAQ,QAAQ,GAAG,CAAC,CAAC,CAAC,CAC3E,MAAM,GAAG,MAAM,IAAI,CAAC;EACvB,MAAM,kBAAkB,QAAQ,QAAQ,KAAK,QAAQ,MAAM,IAAI,iBAAiB,CAAC;EACjF,MAAM,QAAQ,QAAQ,QAAQ,QAAQ,IAAI,QAAQ,SAAS,WAAW,IAAI,QAAQ,SAAS,KAAK;EAChG,MAAM,aAAa,gBAAgB,OAAO;EAO1C,MAAM,YAJJ,eAAe,KAAA,KACf;GAAC,WAAW;GAAY,WAAW;GAAY,WAAW;GAAK,WAAW;GAAQ,WAAW;GAAQ,WAAW;GAAM,WAAW;EAAI,CAAC,CAAC,MACpI,WAAW,SAAS,KAAK,CAC5B,IAC2B,gBAAgB,gBAAgB,UAAU,EAAE,KAAK;EAC9E,MAAM,MACJ,QAAQ,WAAW,IACf,GAAG,QAAQ,OAAO,iCAAiC,WAAW,QAC9D,GAAG,QAAQ,OAAO,SAAS,QAAQ,OAAO,mBAAmB,EAAEA,OAAO,OAAO,CAAC,CAAC,CAAC,MAAM,UAAU,EAAE,WAAW,SAAS,GAAI,CAAC,CAAC,CAAC,MAAM,cAAc,EAAE,QAAQ,GAAG,EAAE,CAAE,CAAC,CAAC,MAAM,MAAM,gBAAgB,oBAAoB,MAAM,OAAO,qBAAqB,UAAU,GAAG,WAAW;EACpR,OAAO;GACL,GAAG;GACH,UAAU;GACV,MAAM;GACN,SAAS,CAAC;GACV,QAAQ,QAAQ,WAAW,IAAI,OAAO,EAAEA,OAAO,OAAO,CAAC;GACvD,GAAI,QAAQ,WAAW,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAG,EAAE,CAAE,EAAE;GAC9D,GAAI,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW;GACjD;EACF;CACF;CAEA,IAAI,CAAC,WAAW,WAAW,WAAW,aAAa,KAAA,KAAa,WAAW,YAAY,KAAA,GAAW;EAChG,MAAM,WAAW,QAAQ,WAAW,IAAI,UAAU;EAClD,MAAM,MACJ,aAAa,UACT,0BAA0B,QAAQ,OAAO,WAAW,QAAQ,WAAW,QAAQ,GAAG,EAAE,MACpF,GAAG,QAAQ,OAAO,MAAM,QAAQ,OAAO;EAC7C,OAAO;GAAE,GAAG;GAAO;GAAU,MAAM;GAAM;GAAS;EAAI;CACxD;CAGA,MAAM,QAAQ,WAAW,UAAU,aAAc,WAAW,YAAY,WAAW;CACnF,MAAM,QAAQ,QAAQ,OAAO,GAAG;CAChC,MAAM,MAAM,QAAQ,MAAM,KAAK,GAAG;CAClC,MAAM,OAAO,QAAQ,MAAM,MAAM,GAAG;CACpC,MAAM,OAAO;EAAE,KAAK,EAAE,MAAM,KAAK;EAAG,MAAM,EAAE,OAAO,KAAK;CAAE;CAC1D,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,OAAO,SAAS;EACzB,IAAI,IAAI,YAAY,MAAM;EAC1B,MAAM,QAAQ,QAAQ,IAAI,SAAS,GAAG;EACtC,OAAO,KAAK,KAAK;EACjB,IAAI,QAAQ,MAAM,SAAS,QAAQ,OAAO,OACxC,QAAQ,KAAK;GACX,KAAK,KAAK,GAAG;GACb,KAAK,GAAG,MAAM,iBAAiB,KAAK,IAAI,MAAM,IAAI,KAAK,KAAK,MAAM;EACpE,CAAC;CACL;CACA,OAAO,MAAM,GAAG,MAAM,IAAI,CAAC;CAC3B,IAAI,OAAO,WAAW,GACpB,OAAO;EAAE,GAAG;EAAO,UAAU;EAAS;EAAM;EAAS,KAAK;CAA2B;CACvF,MAAM,CAAC,MAAM,MAAM,eAAe,MAAM;CACxC,MAAME,WAAS,EAAEF,OAAO,MAAM,CAAC;CAC/B,MAAM,WAAW;EAAE,KAAK,EAAE,IAAI;EAAG,MAAM,EAAE,EAAE;CAAE;CAC7C,MAAM,OAAO;EAAE,KAAK,MAAO;EAAe,MAAM,OAAQ;CAAc;CACtE,MAAM,SAAS,QAAQ,KAAK,OAAO,MAAM,KAAK;CAC9C,MAAM,WAAW,KAAK,KAAK,OAAO,OAAO,KAAK;CAE9C,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC;CACrD,MAAM,SAAS,GAAG,QAAQ,SAAS,IAAI,MAAM,QAAQ,OAAO,gBAAgB,KAAK,IAAI,MAAM,IAAI,KAAK,KAAK,MAAM;CAC/G,MAAM,SAAS,UAAUE,SAAO,MAAM,oBAAoB,SAAS,IAAI,MAAM,IAAI,SAAS,KAAK,MAAM;CACrG,MAAM,SAAS;EACb,SAAS,QAAQ;EACjB;EACA;EACA;EACA,QAAA;EACA,gBAAgB;CAClB;CACA,IAAI,QAAQ,SAAS,KAAK,UACxB,OAAO;EAAE,GAAG;EAAQ,UAAU;EAAS,KAAK,GAAG,OAAO,IAAI;CAAS;CACrE,IAAI,QAAQ,OAAO;EAAE,GAAG;EAAQ,UAAU;EAAS,KAAK,GAAG,OAAO,IAAI;CAAS;CAC/E,MAAM,WAAW,QAAQ,SAAS,MAAM,KAAK,WAAW;CACxD,OAAO;EAAE,GAAG;EAAQ;EAAU,KAAK,GAAG,OAAO,IAAI,OAAO;CAAqB;AAC/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClnBA,MAAa,gBAA0B,SAAS,KAAK,IAAI;;AAGzD,MAAM,cAAc,UAA4B,KAAK,IAAI,QAAQ,eAAe,GAAG,GAAG,QAAQ,OAAO,GAAG,CAAC;;AAGzG,MAAMC,aAAW,MAAc,OAAyB,SAAS,KAAK,OAAO,KAAK,QAAQ,GAAG,IAAI,KAAK,GAAG;;AAGzG,MAAMC,cAAY,WAA8C,OAAqC;AACrG,MAAMC,cAAY,WAA8C,OAAqC;;AAkBrG,MAAa,gBAAgB,MAAY,QAAoC;CAC3E,MAAM,WAAW,KAAK,YAAY;CAClC,IAAI,aAAa,UAAU,OAAO,IAAI;CACtC,IAAI,aAAa,UAAU,OAAO,IAAI,UAAU,CAAC;CACjD,OAAO,CAAC;AACV;;;;;;;AAQA,MAAM,gBAAgB,MAAkB,UAA4B;CAClE,IAAI,EAAE,WAAW,SAAS,EAAE,UAAU,OAAO,OAAO;CACpD,QAAQ,KAAK,YAAY,KAAK,aAAa;AAC7C;;AAGA,MAAM,YACJ,QACA,MACA,SACA,UAC6B;CAC7B,MAAM,QAAQ,QAAQ,OAAO,GAAG,IAAI;CACpC,OAAO,OAAO,MAAM,WAAW,OAAO,QAAQ,KAAK,KAAK,OAAO,QAAQ,KAAK,IAAI,SAAS,QAAQ,MAAM,CAAC;AAC1G;AAEA,MAAM,WACJ,QACA,MACA,SACA,QAAkB,UACD;CACjB,MAAM,SAAS,SAAS,QAAQ,MAAM,SAAS,KAAK;CACpD,OAAO;EACL;EACA,IAAI,QAAQ,QAAQ,KAAK;EACzB,QAAQ,WAAW,KAAA;EACnB,QAAQ,WAAW,KAAA,IAAY,OAAO,OAAO,OAAO,OAAO,UAAU;CACvE;AACF;;;;;;AAOA,MAAa,aAAa,QAAiC,SAAsC;CAC/F,MAAM,OAAO,OAAO,MACjB,WAAW,OAAO,OAAO,WAAWA,WAAS,MAAM,MAAM,MAAMD,WAAS,MAAM,MAAM,KAAKA,WAAS,MAAM,MAAM,MAAM,OAAO,QAAQ,KAAK,CAC3I;CACA,OAAO,SAAS,KAAA,IAAY,OAAOD,UAAQ,KAAK,GAAG,KAAK,IAAI;AAC9D;;;;;;;;AASA,MAAa,UAAU,KAAU,WAAmD;CAClF,MAAM,OAAO,IAAI,OAAO,QAAQ,SAAS,KAAK,OAAO,MAAM,CAAC,CAAC,GAAG,EAAE;CAClE,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;CAC/B,MAAM,UAAU,IAAI,IAAI,IAAI,OAAO,QAAQ,SAAS,KAAK,OAAO,MAAM,CAAC,CAAC,KAAK,SAAS,KAAK,QAAQ,CAAC;CACpG,OAAO,IAAI,OAAO,MACf,WACC,OAAO,UAAU,IAAI,SACrB,OAAO,WAAW,UAClB,OAAO,OAAO,WACdE,WAAS,MAAM,MAAM,MACpBD,WAAS,MAAM,MAAM,KAAKA,WAAS,MAAM,MAAM,MAChD,OAAO,QAAQ,KAAK,KACpB,CAAC,QAAQ,IAAI,OAAO,GAAG,CAC3B,CAAC,EAAE;AACL;;;;;;AAOA,MAAa,eACX,MACA,MACA,MACA,QAAkB,UACiD;CACnE,IAAI,SAAS,QAAQ,SAAS,KAAA,GAAW,OAAO,EAAE,KAAK;CACvD,MAAM,KAAK,KAAK,IAAI,QAAQ,MAAM,GAAG,IAAI;CACzC,OAAO,KAAK,IAAI,KAAK,IAAI,KAAK,QAAQ,OAAO,GAAG,IAAI,MAAM;EAAE,MAAM;EAAM,QAAQ;CAAK,IAAI,EAAE,KAAK;AAClG;;;;;;;AAQA,MAAa,eACX,UACA,MACA,MACA,QAAkB,OAClB,WACkB;CAClB,MAAM,QAAQ,WAAW,KAAK;CAC9B,MAAM,OAAO,SAAS,QAAQ,QAAQ,MAAM,GAAG,KAAK;CACpD,IAAI,aAAa,SAAS;EACxB,IAAI,SAAS,MACX,OAAO,gFAAgF,WAAW,KAAA,IAAY,KAAK;EACrH,OAAO,OAAO,OAAO,iCAAiC,KAAK,MAAM;CACnE;CACA,IAAI,KAAK,WAAW,SAAS,OAAO;CACpC,OAAO,OAAO,kFAAkF;AAClG;AAEA,MAAM,WAAW,WAAkC,OAAO,OAAO;;;;;;;AAQjE,MAAa,iBACX,OACA,QACA,OACA,UACW;CACX,MAAM,OAAO,MAAM,QAAQ,UAAU,KAAK,OAAO,WAAW,KAAK,OAAO,WAAW,KAAK,IAAI,SAAS,aAAa,MAAM,KAAK,CAAC;CAC9H,MAAM,SAAS,KAAK,SAAS,MAAM,OAAO;EACxC,MAAM,OAAO,KAAK,IAAI,KAAK,KAAK,EAAE,EAAE,KAAK,OAAO,KAAK;EACrD,MAAM,QAAQ,OAAO,MAAM,WAAW,QAAQ,MAAM,MAAM,OAAO,KAAK,IAAI,SAAS,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,OAAO,OAAO,IAAI;EACxI,OAAO,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,MAAM,OAAO,KAAK,CAAC;CACxD,CAAC;CACD,OAAO;EACL,MAAM,OAAO;EACb,OAAO,OAAO,WAAW,IAAI,OAAO,SAAS,KAAK,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,GAAG,IAAI,KAAK,IAAI;CAChG;AACF;;AAGA,MAAa,WACX,OACA,QACA,OACA,QAAkB,UAElB,MAAM,QAAQ,SAAS,KAAK,OAAO,UAAU,aAAa,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,QAAQ,QAAQ,MAAM,SAAS,KAAK,CAAC;;;;;AAM7H,MAAa,mBACX,OACA,QACA,QAAgB,OAAO,sBAEvB,MACG,QAAQ,SAAS,KAAK,MAAM,KAAK,CAAC,CAClC,MACE,SACC,CAAC,OAAO,MAAM,WAAW,OAAO,OAAO,SAAS,OAAO,KAAK,IAAI,SAAS,KAAK,KAAK,OAAO,OAAO,KAAK,MAAM,OAAO,QAAQ,KAAK,CACpI;;;;;;;AAQJ,MAAa,UACX,OACA,QACA,OACA,QAAkB,UACW;CAC7B,MAAM,OAAO,MAAM,MAAM,SAAS,KAAK,OAAO,UAAU,aAAa,MAAM,KAAK,CAAC;CACjF,OAAO,SAAS,KAAA,IACZ,KAAA,IACA,QAAQ,QAAQ,OAAO,WAAW,QAAQ,MAAM,KAAM,OAAO,OAAO,WAAWC,WAAS,MAAM,MAAM,GAAI,SAAS,WAAW,KAAK,GAAG,GAAG,CAAC;AAC9I;;;;;;AAmBA,MAAa,eAAe,KAAU,UAAkB,QAA4B,OAAe,aAA+B;CAChI,MAAM,QAAQ,IAAI,OAAO,QAAQ,SAAS,KAAK,IAAI,IAAI;CACvD,MAAM,SAAS,MAAM,QAAQ,SAAS,KAAK,OAAO,cAAc;CAChE,MAAM,QAAQ,MAAM,QAAQ,SAAS,KAAK,OAAO,MAAM;CACvD,MAAM,QAAQ,OAAO,SAAS,OAAO,OAAO;EAC1C,MAAM,OAAO,OAAO,KAAK,EAAE,EAAE,KAAK,OAAO;EACzC,MAAM,OAAO,MAAM,MAAM,SAAS,KAAK,KAAK,MAAM,KAAK,KAAK,IAAI,IAAI;EACpE,OAAO,SAAS,KAAA,IAAY,CAAC,IAAI,CAACF,UAAQ,MAAM,GAAG,KAAK,CAAC,CAAC;CAC5D,CAAC;CACD,MAAM,QAAQ,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,WAAW,UAAU,OAAO,OAAO,WAAW,OAAO,OAAO,QAAQ;CACrJ,MAAM,OAAO,MAAM,QAAQ,WAAWC,WAAS,MAAM,MAAM,CAAC;CAC5D,MAAM,cAAc,MAAM,MAAM,WAAWA,WAAS,MAAM,MAAM,CAAC;CACjE,MAAM,WAAW,MAAM,SAAS,SAAS;EACvC,MAAM,MAAM,KAAK,MAAM,WAAW,OAAO,QAAQ,KAAK,CAAC;EACvD,OAAO,QAAQ,KAAA,IAAY,CAAC,IAAI,CAACD,UAAQ,KAAK,GAAG,IAAI,IAAI,CAAC;CAC5D,CAAC;CACD,OAAO;EACL;EACA,KAAK,KAAK,OAAO,KAAA,IAAY,OAAOA,UAAQ,UAAU,KAAK,EAAE,CAAC,IAAI;EAClE,aAAa,gBAAgB,KAAA,IAAY,OAAOA,UAAQ,UAAU,YAAY,IAAI;EAClF;CACF;AACF;;AAGA,MAAa,oBAAoB,UAAsB,MAAwB,QAAkB,UAAyB;CACxH,MAAM,QAAQ,QAAQ,OAAO,GAAG;CAChC,MAAM,SAAS,UAAkB,KAAK,MAAM,QAAQ,GAAG,IAAI;CAC3D,MAAM,QAAQ,SAAS,MAAM,SAAS,MAAM,OAAO;EACjD,MAAM,OAAO,KAAK,MAAM;EACxB,IAAI,SAAS,KAAA,GAAW,OAAO,CAAC,0BAA0B,KAAK,EAAE,qBAAqB;EACtF,MAAM,QAAQ,QAAQ,MAAM,GAAG;EAC/B,MAAM,MAAM,MAAM,QAAQ,KAAK,KAAK,GAAG,IAAI,KAAK;EAChD,MAAM,OAAO,MAAM,QAAQ,KAAK,MAAM,GAAG,IAAI,KAAK;EAClD,OAAO,QAAQ,OAAO,QAAQ,OAAO,CAAC,uBAAuB,KAAK,EAAE,OAAO,MAAM,eAAe,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC;CACxH,CAAC;CACD,OAAO,MAAM,WAAW,IAAI,OAAO,MAAM,KAAK,IAAI;AACpD;;AAYA,MAAa,UAAU,QAA+B,SAAqB,aAA8C;CACvH,MAAM,MAAM,OAAO,MAAM,UAAU,KAAK,OAAO,gBAAgB,KAAK,OAAO,WAAW,KAAK,IAAI,QAAQ,CAAC;CACxG,IAAI,QAAQ,KAAA,GAAW,OAAO;EAAE,SAAS;EAAW,OAAO;CAAK;CAEhE,OAAO;EAAE,SADO,IAAI,OAAO,SAAS,YAAY,OAAO,IAAI,cAAc,IAAI,WAAW,UAAU;EAChF,OAAO,aAAa,KAAA,IAAY,OAAOA,UAAQ,UAAU,IAAI,CAAC;CAAE;AACpF;;;;ACxSA,MAAMG,UAA0C;CAC9C,IAAI;CACJ,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;AACP;AAEA,MAAMC,aAAW,MAAc,OAAyB,SAAS,KAAK,OAAO,KAAK,QAAQ,GAAG,IAAI,KAAK,GAAG;AACzG,MAAM,SAAS,YAA4B,KAAK,MAAM,UAAU,GAAG,IAAI;;AAGvE,MAAa,WAAW,MAAe,SACrC,KAAK,MAAM,GAAG,CAAC,CAAC,QAAiB,OAAO,QAAS,UAAU,QAAQ,OAAO,UAAU,WAAY,MAAkC,OAAO,KAAA,GAAY,IAAI;;AAG3J,MAAa,WAAW,MAAkB,UACxC,KAAK,OAAO,MAAM,MAAM,OAAO,QAAQ,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,WAAW,QAAQ,MAAM,IAAI,MAAM,KAAK;;AAGlH,MAAa,WAAW,OAA8B,UAA6B,MAAM,QAAQ,SAAS,QAAQ,MAAM,KAAK,CAAC,CAAC,CAAC;;AAGhI,MAAa,gBAAgB,QAA8B,UAAgD;CACzG,MAAM,MAAM,OAAO,SAAS,SAAS;EACnC,MAAM,OAAO,QAAQ,OAAO,KAAK,KAAK;EACtC,OAAO,SAAS,KAAK,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,KAAK,4BAA4B,KAAK,OAAO;CACnG,CAAC;CACD,OAAO,IAAI,WAAW,IAAI,OAAO,IAAI,KAAK,IAAI;AAChD;;AAGA,MAAa,WAAW,UAA6B;CACnD,MAAM,QAAQ,OAAO,QAAQ,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW,GAAG,KAAK,GAAG,OAAO,KAAK,GAAG;CACjG,OAAO,MAAM,WAAW,IAAI,KAAK,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,aAAa,MAAM,KAAK,IAAI;AAC/F;;AAGA,MAAa,aAAa,WACxB,OACG,QAAQ,UAAU,MAAM,OAAO,QAAQ,CAAC,CACxC,KAAK,UAAU;CACd,MAAM,QAAQ,OAAO,MAAM,QAAQ;CACnC,MAAM,MAAM,OAAO,MAAM,SAAS,KAAK,OAAO,gBAAgB,KAAK,aAAa,SAAS,KAAK,KAAK,MAAM,CAAC;CAC1G,OAAO;EAAE,MAAM,OAAO,MAAM,OAAO;EAAG;EAAO,QAAQ,OAAO,MAAM,SAAS;EAAG,QAAQ,MAAM;EAAG,OAAO,KAAK,KAAK;CAAK;AACvH,CAAC;;;;;;AAOL,MAAa,YAAY,QAA+B,MAAc,OAAyC;CAC7G,MAAM,UAAU,UAAU,MAAM;CAChC,IAAI,SAAS,QAAQ;EACnB,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,CAAC,GAAG;EACjE,OAAO,QAAQ,MAAM,WAAW,OAAO,UAAU,KAAK;CACxD;CACA,OAAO,QAAQ,QAAQ,WAAW,OAAO,SAAS,QAAQ,OAAO,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE;AACtF;AASA,MAAM,WAAW,KAAU,OAAe,SAAqE;CAC7G,MAAM,SAAS,IAAI,OAAO,MAAM,WAAW,OAAO,UAAU,SAAS,KAAK,MAAM,CAAC,CAAC,EAAE;CACpF,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;CACjC,OAAO;EAAE;EAAO;EAAQ,SAAS,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,SAAS,OAAO,WAAW,MAAM;CAAE;AACrH;AAEA,MAAM,UAAU,YAA4B,QAAQ,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK;;;;;;AAOzE,MAAM,aAAa,KAAU,UAA2C;CACtE,MAAM,OAAO,IAAI,aAAa,KAAA,IAAY,QAAQ,GAAG,IAAI,SAAS,WAAW,GAAG,OAAO,KAAK;CAC5F,OAAO,QAAQ,KAAK,IAAI,cAAc,WAAW,OAAO,QAAQ,IAAI;AACtE;;;;;;AAOA,MAAM,cAAc,QAAsC;CACxD,IAAI,IAAI,aAAa,KAAA,GAAW,OAAO,KAAA;CACvC,MAAM,SAAS,SAAS,GAAG;CAC3B,KAAK,MAAM,OAAO,OAAO,OAAO,IAAI,SAAS,IAAI,CAAC,CAAC,QAAQ,GAAG;EAC5D,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,WAAW,OAAO,OAAO,WAAWC,WAAS,MAAM,MAAM,KAAK,OAAO,QAAQ,UAAU,OAAO,QAAQ,IAAI,MAAM;EACvJ,IAAI,UAAU,KAAA,GAAW,OAAO;CAClC;AAEF;;;;;AAMA,MAAM,YAAY,KAAU,MAAc,OAAqF;CAC7H,IAAI,SAAS,YAAY,OAAO;EAAE,QAAQ,KAAA;EAAW,OAAO,WAAW,GAAG;CAAE;CAC5E,IAAI,SAAS,UAAU;EACrB,MAAM,OAAO,SAAS,IAAI,QAAQ,QAAQ,EAAE;EAC5C,OAAO;GAAE,QAAQ;GAAM,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,UAAU,KAAK,KAAK,KAAK;EAAE;CAC5F;CACA,MAAM,SAAS,SAAS,IAAI,QAAQ,MAAM,EAAE;CAC5C,OAAO;EAAE;EAAQ,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY,QAAQ,KAAK,IAAI,QAAQ,WAAW,OAAO,QAAQ,OAAO,KAAK;CAAE;AAC9H;AAEA,MAAMA,cAAY,WAA8C,OAAqC;AACrG,MAAMC,cAAY,WAA8C,OAAqC;;AAGrG,MAAM,YAAY,QAAqB;CACrC,MAAM,QAAQ,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CAC7D,OAAO,IAAI,OAAO,MAAM,OAAO,KAAK,IAAI,OAAO,EAAE,EAAE,KAAK;AAC1D;;;;;;;;;;;;;;;;;AAkBA,MAAa,eAAe,KAAU,MAAiB,MAAc,MAAe,MAAc,aAAiC;CACjI,MAAM,QAAQ,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CAC7D,MAAM,SAAS,IAAI,OAAO,MAAM,OAAO,KAAK;CAC5C,IAAI,SAAS,SAAS,OAAO,IAAI,OAAO;CACxC,IAAI,SAAS,gBAAgB,QAAQ,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,YAAY,KAAK,IAAI,OAAO,GAAA,EAAK;CAC9G,IAAI,SAAS,gBAAgB,OAAO,IAAI,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC,EAAE,EAAE;CAE1F,IAAI,SAAS,cACX,OAAO,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,OAAO,OAAO,OAAO,OAAO,SAAS,OAAO,KAAK,IAAI,SAAS,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE;CAC1J,MAAM,EAAE,QAAQ,UAAU,SAAS,KAAK,MAAM,MAAM;CACpD,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;CAChC,IAAI,SAAS,mBAAmB,SAAS,aAAa;EAEpD,MAAM,WAAW,QAAQ,SAAS;EAClC,MAAM,UAAU,WACd,YAAY,OAAO,OAAO,QAAQ,OAAO,OAAO,UAAU,OAAO,KAAK,IAAI,SAAS,KAAK,IAAI,OAAO,OAAO;EAC5G,OAAO,MAAM,QAAQ,QAAQ,WAAW,OAAO,QAAQ,UAAU,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE;CAC3F;CACA,IAAI,SAAS,cACX,OAAO,MAAM,QAAQ,MAAM,WAAW,OAAO,OAAO,QAAQ,OAAO,OAAO,WAAW,OAAO,KAAK,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE;CAEzH,IAAI,SAAS,YAAY,OAAO,MAAM,QAAQ,MAAM,WAAW,OAAO,OAAO,WAAWD,WAAS,MAAM,MAAM,CAAC,CAAC,EAAE;CACjH,IAAI,SAAS,wBAAwB;EACnC,MAAM,UAAU,IAAI,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK;EAC3E,OAAO,MAAM,QAAQ,MAAM,WAAW,OAAO,OAAO,aAAa,OAAO,QAAQ,SAAS,OAAO,OAAO,OAAO,CAAC,EAAE;CACnH;CAGA,IAAI,SAAS,eAAe,OAAO,KAAA;CAGnC,MAAM,UADO,WAAW,KAAA,IAAY,KAAA,IAAY,UAAU,KAAK,OAAO,KAAK,EAAA,EACtD,QAAQ,MAAM,WAAW,OAAO,OAAO,WAAWC,WAAS,MAAM,MAAM,CAAC,CAAC,EAAE;CAChG,IAAI,WAAW,KAAA,KAAa,IAAI,aAAa,KAAA,GAAW,OAAO;CAC/D,OAAO,aAAa,GAAG;AACzB;;;;;;;;AASA,MAAa,gBAAgB,QAAiC;CAC5D,IAAI,IAAI,aAAa,KAAA,GAAW,OAAO,KAAA;CACvC,MAAM,MAAM,IAAI,SAAS;CACzB,MAAM,SAAS,SAAS,GAAG;CAC3B,OAAO,IAAI,OAAO,MACf,WACC,OAAO,UAAU,IAAI,eAAe,OAAO,OAAO,WAAWA,WAAS,MAAM,MAAM,KAAK,OAAO,QAAQ,UAAU,OAAO,QAAQ,KAAA,KAAaC,OAAK,OAAO,GAAG,MAAM,GACrK,CAAC,EAAE;AACL;;AAGA,MAAMA,UAAQ,YAA4B,QAAQ,MAAM,GAAG,QAAQ,YAAY,GAAG,CAAC;;AAGnF,MAAM,aAAa,QAA+B,OAAkB,UAClE,OAAO,MAAM,UAAU,MAAM,IAAI,SAAS,QAAQ,OAAO,KAAK,CAAC;;AAGjE,MAAMC,YAAU,MAAkB,UAA6B,OAAO,QAAQ,MAAM,MAAM,QAAQ,MAAM,KAAK,KAAK,EAAE;;;;;;;AAQpH,MAAM,YAAY,OAAoB,UAAgE;CACpG,MAAM,SAAS,MAAM,QAAQ,MAC1B,WAAW,OAAO,OAAO,UAAW,OAAO,OAAO,YAAY,OAAO,OAAO,OAAO,KAAO,OAAO,OAAO,WAAWH,WAAS,MAAM,MAAM,EAC3I;CACA,IAAI,WAAW,KAAA,GAAW;EACxB,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW,OAAO,OAAO,SAAS,OAAO,OAAO,WAAWC,WAAS,MAAM,MAAM,KAAKD,WAAS,MAAM,MAAM,CAAC;EAC7I,OAAO,UAAU,KAAA,IAAY,KAAA,IAAY;GAAE,IAAI,MAAM;GAAM,SAAS,EAAE,MAAM,SAAS;EAAE;CACzF;CACA,OAAO,OAAO,OAAO,UACjB;EAAE,IAAI,OAAO;EAAM,SAAS;GAAE,MAAM;GAAS,OAAOF,QAAM,OAAO,QAAS,IAAI,OAAO;EAAM;CAAE,IAC7F;EAAE,IAAI,OAAO;EAAM,SAAS,EAAE,MAAM,MAAM;CAAE;AAClD;;;;;;AAOA,MAAa,aAAa,SAAuB;CAC/C,MAAM,EAAE,eAAe;CACvB,IAAI,WAAW,YAAY,MAAM,OAAO,QAAQ,WAAW,QAAQ,GAAG;CACtE,MAAM,OAAO,WAAW,QAAQ,QAAQ,CAAC;CACzC,MAAM,QAAQ,KAAK,KAAK,SAAS,QAAQ,KAAK,MAAM,GAAG,CAAC;CACxD,MAAM,MAAM,WAAW,UAAU,QAAQ,WAAW,MAAM,GAAG,IAAI,QAAQ,WAAW,QAAQ,GAAG;CAC/F,MAAM,UAAU,CAAC,GAAI,WAAW,WAAW,WAAW,SAAS,eAAe,CAAC,GAAG,IAAI,CAAC,GAAI,GAAG,KAAK,QAAQ,SAAS,KAAK,SAAS,YAAY,CAAC,CAAC,KAAK,SAAS,QAAQ,KAAK,MAAM,GAAG,CAAC,CAAC;CACtL,OAAO,KAAK,IAAI,KAAK,GAAG,OAAO,QAAQ,QAAQ,OAAO,SAAS,QAAQ,MAAM,CAAC,CAAC;AACjF;;;;;;AAOA,MAAa,WAAW,MAAY,QAAsB;CACxD,MAAM,EAAE,eAAe;CACvB,IAAI,WAAW,YAAY,QAAQ,WAAW,WAAW,KAAA,GAAW,OAAO;CAC3E,MAAM,SAAqB,WAAW;CACtC,MAAM,QAAQ,SAAS,GAAG;CAQ1B,QANE,OAAO,SAAS,KAAA,WACL;EACL,MAAM,EAAE,UAAU,SAAS,KAAK,OAAO,QAAQ,IAAI,OAAO,MAAM,KAAK;EACrE,OAAO,UAAU,KAAA,KAAa,SAAS,OAAO,KAAK,MAAM,KAAA;CAC3D,EAAA,CAAG,IACH,UAAU,IAAI,QAAQ,OAAO,MAAM,KAAK,MAAM,KAAA,OACnC,OAAO,QAAQ,CAAC,EAAA,CAAG,OAAO,SAAS,UAAU,IAAI,QAAQ,KAAK,MAAM,KAAK,MAAM,KAAA,CAAS;AAC3G;;;;;;;AAQA,MAAM,WAAW,OAAoB,MAAc,IAAY,IAAwB,UAAmC;CACxH,MAAM,UAAU,MAAM,QAAQ,QAAQ,WAAW,OAAO,OAAO,WAAW,OAAO,SAAS,eAAe,OAAO,QAAQ,QAAQ,OAAO,QAAQ,EAAE;CACjJ,MAAM,OAAO,QAAQ,MAAM,WAAW,WAAW,OAAO,QAAQ,SAAS,GAAG,IAAI,KAAK,CAAC;CACtF,IAAI,SAAS,KAAA,GAAW,OAAO,2BAA2B,KAAK,OAAQ,MAAM;CAE7E,OADa,QAAQ,MAAM,WAAW,OAAO,UAAU,IAC7C,MAAM,KAAA,IAAY,OAAO;AACrC;;;;;;;;;;;;;;;;;AAkBA,MAAa,iBAAiB,MAAY,QAAuB;CAC/D,MAAM,EAAE,eAAe;CACvB,IAAI,WAAW,YAAY,QAAQ,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,oBAAoB;CACrH,MAAM,SAAS,WAAW;CAC1B,MAAM,EAAE,WAAW;CACnB,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CACzD,MAAM,UAAU,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC;CAC9D,MAAM,QAAQ,SAAS,GAAG;CAC1B,MAAM,SAAS,IAAI,OAAO,MAAM,OAAO,KAAK;CAC5C,MAAM,EAAE,UAAU,SAAS,KAAK,OAAO,QAAQ,MAAM;CACrD,MAAM,UAAU,OAAO,WAAW,CAAC;CAEnC,MAAM,OADO,SAAS,KAAK,QAAQ,MAAM,CAAC,CAAC,OACxB,QAAQ,MAAM,WAAW,OAAO,KAAK,SAAS,KAAA,CAAS,CAAC,EAAE,KAAK;CAClF,MAAM,MAAM,SAAS,KAAA,IAAY,OAAO,SAAS,QAAQ,MAAM,IAAI,IAAI,KAAM,IAAI;CACjF,MAAM,OAAO;EACX,aAAa,IAAI;EACjB,OAAO,IAAI;EACX,QAAQ,QAAQ,QAAQ,WAAW,OAAO,OAAO,WAAW,OAAO,SAAS,WAAW,CAAC,CAAC;EACzF,iBAAiB,QAAQ,QAAQ,WAAW,OAAO,OAAO,SAAS,CAAC,CAAC;EACrE,MAAM,YAAY,KAAA,IAAY,IAAI,QAAQ,QAAQ,WAAW,OAAO,OAAO,QAAQ,OAAO,OAAO,QAAQ,CAAC,CAAC,CAAC;EAC5G;CACF;CACA,MAAM,UAAU;EAAE,SAAS,EAAE,MAAM,SAAS;EAAY,SAAS;EAAM,QAAQ;EAAM,SAAS;EAAM,OAAO,CAAC;EAAG,SAAS;CAAK;CAE7H,IAAI,KAAK,WAAW,QAAQ,UAAU,KAAA,GAAW,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,MAAM;CAAiC;CACtH,IAAI,IAAI,SAAS,MAAM,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,MAAM;CAAgF;CAC3I,IAAI,IAAI,OAAO,GAAG,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,MAAM,sBAAsB,IAAI,KAAK;CAAU;CAE/F,IAAI,SAAwB;CAC5B,IAAI,KAAK,MAAM,SAAS,UAAU,KAAK,WAAW,MAAM;EACtD,IAAI,YAAY,KAAA,GAAW,SAAS;OAC/B,IAAI,aAAa,IAAI,GAEpB;OAAA,IAAI,UAAU,QAAQ,IAAI,MAAM,KAAK,QAAQ,GAAG,SAAS;EAAA,OACxD,IAAI,IAAI,UAAU,QAAQ,IAAI,MAAM,KAAK,QAAQ,GAAG,SAAS;CACtE;CACA,MAAM,YAAY,QAAQ,MAAM,WAAW,OAAO,OAAO,WAAW,OAAO,SAAS,WAAW;CAC/F,IAAI,WAAW,QAAQ,IAAI,UAAU,QAAQ,cAAc,KAAA,KAAa,UAAU,OAAO,IAAI,MAAM,IACjG,SAAS;CACX,IAAI,WAAW,QAAQ,KAAK,SAAS,KAAA,KAAa,IAAI,UAAU,MAAM;EACpE,MAAM,OAAO,IAAI,QAAQ;EACzB,IAAI,SAAS,MAAM,SAAS;OACvB;GACH,MAAM,QAAQ,KAAK,KAAK,IAAI,MAAM,MAAM,MAAM,QAAQ,KAAK,MAAM,GAAG;GACpE,IAAI,OAAO,QAAQ,QAAQ,GAAG,GAAG,SAAS,iBAAiB,KAAK,MAAM,OAAO,GAAG,IAAI,GAAG;EACzF;CACF;CACA,MAAM,UAAU,WAAW;CAC3B,IAAI,WAAW,QAAQ,YAAY,KAAA,KAAa,QAAQ,QAAQ,QAAQ,KAAK,IAAI,IAAI,QAAQ,QAAQ,MAAM,IAAI,GAC7G,SAAS,iDAAiD,IAAI,MAAM,iBAAiB,QAAQ,QAAQ,MAAM,IAAI,EAAE;CAEnH,MAAM,WAAqB,CAAC;CAC5B,MAAM,QAAQ,QAAQ,QAAQ,IAAI,GAAG,GAAG;CAExC,MAAM,QAAQ,WAAW,UAAU,WAAW,QAAQ,QAAQ,WAAW,QAAQ,GAAG,IAAI;CACxF,KAAK,MAAM,SAAS,OAAO,SAAS,CAAC,GAAG;EACtC,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,IAAI,SAAS,MAAM,KAAK,SAAS,QAAQ,OAAO,KAAK,CAAC;EAChG,IAAI,SAAS,KAAA,GAAW,SAAS,KAAK,GAAG,QAAQ,KAAK,EAAE,QAAQC,UAAQ,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,sCAAsC;CACrI;CACA,MAAM,WAAW,WAAW,UAAU,KAAA,IAAY,WAAW,WAAW;CACxE,IAAI,CAAC,WAAW,YAAY,IAAI,cAAc,KAAA,KAAa,aAAa,KAAA,IAAY;EAGlF,MAAM,MAAM,SAAS,QAAQ,OAAO,QAAQ,MAAM,CAAC,EAAE;EACrD,IAAI,aAAa,KAAA,KAAa,QAAQ,KAAA,GAAW,SAAS,KAAK,wBAAwB,OAAO,OAAO,yBAAyB;EAC9H,MAAM,YAA2C,IAAI,aAAa,CAAC;EACnE,KAAK,MAAM,UAAU,UAAU,MAAM,GAAG;GACtC,MAAM,SAAS,UAAU,MACtB,SACC,KAAK,OAAO,QACZ,KAAK,YAAY,aACjB,OAAO,KAAK,WAAW,EAAE,CAAC,CAAC,WAAW,GAAG,OAAO,MAAM,EAAE,KACxD,KAAK,IAAI,OAAO,WACf,OAAO,UAAU,QAAQ,KAAK,IAAI,OAAO,UAC1C,KAAK,KAAK,KACd;GACA,IAAI,aAAa,KAAA,KAAa,OAAO,UAAU,KAAK;IAClD,IAAI,WAAW,KAAA,GAAW,SAAS,KAAK,mCAAmC,OAAO,KAAK,UAAUA,UAAQ,OAAO,OAAO,CAAC,CAAC,CAAC,MAAM,4CAA4C;IAC5K;GACF;GAEA,MAAM,OAAO,YAAY,KAAK,iBAAiB,OAAO,QAAQ,KAAK;GACnE,IAAI,WAAW,KAAA,GAAW,SAAS,KAAK,oCAAoC,OAAO,KAAK,iDAAiD;QACpI,IAAI,SAAS,KAAA,GAAW,SAAS,KAAK,OAAO,OAAO,KAAK,wCAAwC;QACjG;IACH,MAAM,KAAKA,UAAQ,MAAM,OAAO,CAAC,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,QAAQ,CAAC,MAAM,QAAQ,SAAS,KAAK,GAAG,IAAI,KAAK,GAAG,MAAM,QAAQ,SAAS,MAAM,GAAG,IAAI,KAAK,CAAC;IAC1G,IAAI,KAAK,OAAO,KAAK,MAAM,SAAS,KAAK,mCAAmC,OAAO,KAAK,UAAU,GAAG,sCAAsC,IAAI,IAAI,KAAK,IAAI;GAC9J;EACF;CACF;CACA,MAAM,aAA+B,OAAO,QAAQ,CAAC,EAAA,CAAG,KAAK,SAAS;EACpE,MAAM,OAAO,UAAU,QAAQ,KAAK,MAAM,KAAK;EAC/C,MAAM,OAAO,YAAY,KAAK,KAAK,MAAM,KAAK,UAAU,OAAO,QAAQ,MAAM,MAAM,CAAC;EACpF,IAAI,SAAS,KAAA,KAAa,SAAS,KAAA,GAAW;GAC5C,SAAS,KAAK,SAAS,KAAA,IAAY,GAAG,KAAK,KAAK,IAAI,QAAQ,KAAK,IAAI,EAAE,eAAe,GAAG,KAAK,KAAK,mBAAmB,KAAK,KAAK,aAAa;GAC7I,OAAO;IAAE,MAAM,KAAK;IAAM,MAAM,SAAS,KAAA,IAAY,OAAOI,SAAO,MAAM,KAAK,IAAI;IAAG,SAAS;GAAK;EACrG;EACA,MAAM,UAAUJ,UAAQ,MAAM,KAAK,CAAC;EACpC,MAAM,OAAOI,SAAO,MAAM,KAAK,IAAI;EACnC,IAAI,KAAK,SAAS,QAAQ,SAAS,KAAK,MAAM,SAAS,KAAK,GAAG,KAAK,KAAK,kBAAkB,KAAK,QAAQ,KAAK,MAAM;EACnH,MAAM,CAAC,KAAK,QAAQ,CAAC,MAAM,QAAQ,KAAK,KAAK,GAAG,IAAI,KAAK,GAAG,MAAM,QAAQ,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC;EAClG,IAAI,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,MAAM,SAAS,KAAK,GAAG,KAAK,KAAK,IAAI,QAAQ,MAAM,iBAAiB,IAAI,IAAI,KAAK,IAAI;EAChI,OAAO;GAAE,MAAM,KAAK;GAAM;GAAM;EAAQ;CAC1C,CAAC;CACD,MAAM,UAAU,UAAU,WAAW,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,UAAU,EAAE;CAE7E,IAAI,CAAC,WAAW,SAAS;EACvB,IAAI,OAAO,UAAU,KAAA,KAAa,WAAW,YAAY,KAAA,GACvD,OAAO;GAAE,GAAG;GAAM,GAAG;GAAS,GAAG;GAAS,MAAM;GAAQ,SAAS,SAAS,MAAM;EAAK;EACvF,MAAM,OAAO,UAAU,QAAQ,OAAO,MAAM,MAAM,KAAK;EACvD,MAAM,OAAO,YAAY,KAAK,OAAO,MAAM,MAAM,OAAO,QAAQ,MAAM,MAAM,CAAC;EAC7E,IAAI,SAAS,KAAA,KAAa,SAAS,KAAA,GACjC,OAAO;GAAE,GAAG;GAAM,GAAG;GAAS,GAAG;GAAS,MAAM;GAAQ,SAAS,SAAS,MAAM,yBAAyB,QAAQ,OAAO,MAAM,IAAI;EAAI;EACxI,OAAO;GACL,GAAG;GACH,GAAG;GACH,GAAG;GACH,SAAS,EAAE,MAAM,WAAW;GAC5B,SAASJ,UAAQ,MAAM,KAAK,CAAC;GAC7B,MAAM;GACN,SAAS,SAAS,MAAM;EAC1B;CACF;CAGA,MAAM,OAAO,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,UAAU,QAAQ,OAAO,MAAM,KAAK;CACzF,MAAM,SAAS,OAAO,SAAS,KAAA,KAAa,UAAU,KAAA,IAAY,SAAS,OAAO,KAAK,IAAI,KAAA;CAC3F,IAAI,OAAO,SAAS,KAAA,KAAa,UAAU,KAAA,GACzC,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,GAAG;EAAS,MAAM,UAAU,iCAAiC,OAAO,OAAO;EAAU,SAAS,SAAS,MAAM;CAAK;CAClJ,MAAM,QAAQ,MAAM,KAAK,QAAQ;CACjC,MAAM,UACJ,SAAS,KAAA,KAAa,OAAO,SAAS,KAAA,IAAY;EAAE,MAAM;EAAS,OAAOI,SAAO,MAAM,OAAO,IAAI;CAAE,IAAK,QAAQ,WAAW,EAAE,MAAM,SAAS;CAC/I,IAAI,UAAU,KAAA,GACZ,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,GAAG;EAAS,MAAM;EAAQ,SAAS,SAAS,MAAM,wBAAwB,WAAW,MAAM;CAAc;CACzI,MAAM,YAAY,YAAY,KAAK,WAAW,MAAM,OAAO,QAAQ,OAAO,SAAS,KAAA,GAAW,KAAK;CACnG,IAAI,cAAc,KAAA,GAChB,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,GAAG;EAAS;EAAS,MAAM;EAAQ,SAAS,yCAAyC,WAAW,KAAK,UAAU,OAAO,OAAO;CAAU;CACvK,IAAI,OAAO,SAAS,KAAA,KAAa,WAAW,SAAS,mBAAmB,UAAU,KAAA,GAAW,WAAW,QAAQ,OAAO,WAAW,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC;CAC9J,MAAM,OAAO,QAAQ,SAAS,UAAU,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,SAAS,WAAW,WAAW;CAChI,IAAI,WAAW,UAAU,QAAQ,SAAS,WAAW,OAAO,SAAS,QAAQ,iBAAiB,KAAK,QAAQ,WAAW,OAAO;CAE7H,MAAM,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY,OAAO,MAAM,UAAU,MAAM,KAAK,OAAO,OAAO,MAAM,OAAO,WAAW,MAAM,OAAO,eAAe;CACpJ,OAAO;EACL,GAAG;EACH,GAAG;EACH;EACA,SAASJ,UAAQ,WAAW,KAAK;EACjC,QAAQ,SAAS,KAAA,IAAY,OAAOA,UAAQ,WAAW,KAAK,CAAC;EAC7D,SAAS,WAAW,KAAA,KAAa,SAAS,KAAA,IAAY,OAAOA,UAAQ,OAAO,IAAI,KAAK,CAAC;EACtF,QAAQ,WAAW,SAAS,kBAAkB,QAAQ,QAAQ,WAAW,OAAO,OAAO,WAAW,OAAO,SAAS,eAAe,OAAO,OAAO,SAAS,IAAI,CAAC,EAAA,CAAG,KAC7J,WAAWA,UAAQ,WAAW,OAAO,IAAI,CAC5C;EACA,MAAM;EACN,SAAS,SAAS,MAAM;CAC1B;AACF;;;;ACvdA,MAAM,MAAM;;AAwCZ,MAAaK,aAAW,MAAc,OAAyB,SAAS,KAAK,OAAO,KAAK,QAAQ,GAAG,IAAI,KAAK,GAAG;AAEhH,MAAMC,cAAY,MAAkB,UAA0B;CAC5D,MAAM,QAAQ,KAAK;CACnB,OAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;;AAGA,MAAa,UAAU,MAAgB,SAA6B;CAClE,MAAM,UAAU,QAAQ,MAAM,GAAG;CACjC,OAAO,WAAW,QAAQ,KAAK,KAAK,GAAG,KAAK,WAAW,QAAQ,KAAK,MAAM,GAAG;AAC/E;;AAGA,MAAa,aAAa,SAA4B,IAAI,QAAQ,KAAK,KAAK,GAAG,EAAE,IAAI,QAAQ,KAAK,MAAM,GAAG,EAAE;AAE7G,MAAM,WAAW,MAAc,WAC7B,OAAO,KAAK,OAAO,OAAOD,UAAQ,OAAO,IAAI,OAAO,OAAO,KAAK,IAAK,KAAK,CAAC;;AAG7E,MAAM,aAAa,KAAU,UAAmC;CAC9D,MAAM,UAAU,IAAI,IAClB,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC,CAAC,KAAK,WAAW,OAAO,MAAM,CACjH;CACA,OAAO,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,QAAQ,IAAI,OAAO,MAAM,CAAC;AAC/F;AAEA,MAAM,kBAAkB,MAAc,KAAU,aAAkE;CAChH,MAAM,UAAU,OACd,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,MAAM,MAAM,YAAY,IAAI;CACtE,MAAM,OAAO,OAAO,MAAM;CAC1B,MAAM,YAAY,OAAO,WAAW;CACpC,MAAM,SAAS,OAAO,QAAQ;CAC9B,MAAM,QAAQ,OAAO,OAAO;CAC5B,MAAM,SAAS,SAAS,KAAA,IAAY,CAAC,IAAI,UAAU,KAAK,KAAK,QAAQ;CACrE,MAAM,OAAO,OAAO,QAAQ,WAAW,OAAO,OAAO,SAAS,CAAC,CAAC,KAAK,WAAW,OAAO,IAAI;CAC3F,MAAM,KAAK,OAAO,QAAQ,WAAW,OAAO,OAAO,UAAU,OAAO,KAAK,SAAS,KAAK,SAAS,CAAC;CACjG,MAAM,OAAO,MAAM,KAAK;CACxB,MAAM,QAAQ,UAAU,SAAS,QAAQ,UAAU,SAAS,KAAA,IAAY,KAAA,IAAY,OAAO,SAAS,KAAK,IAAI;CAC7G,MAAM,OAAO,KAAK,GAAG,EAAE;CACvB,OAAO;EACL;EACA,WAAW,cAAc,KAAA;EAEzB,MAAM,QAAQ,MAAM,cAAc,KAAA,IAAY,OAAO,KAAK,QAAQ,UAAU,QAAQ,UAAU,CAAC,CAAC;EAChG,SAAS,QACP,MACA,GAAG,KAAK,WAAW,OAAO,IAAI,CAChC;EACA,iBAAiB,KAAK;EACtB,OAAO,WAAW,KAAA,IAAY,OAAO,OAAO,OAAO,QAAQ;EAC3D,OAAO,WAAW,KAAA,KAAa,UAAU,KAAA,IAAY,OAAOA,UAAQ,MAAM,GAAG,OAAO,CAAC;EACrF,WAAW,WAAW,KAAA,KAAa,SAAS,KAAA,IAAY,OAAOA,UAAQ,MAAM,OAAO,CAAC;EACrF,SAAS,UAAU,KAAA,IAAY,OAAOC,WAAS,OAAO,SAAS;CACjE;AACF;;AAGA,MAAM,gBAAgB,MAAc,MAA2B,UAA0C;CACvG,IAAI,KAAK,WAAW,MAAM,QAAQ,OAAO,CAAC,GAAG,KAAK,IAAI,KAAK,OAAO,cAAc,MAAM,QAAQ;CAC9F,OAAO,KAAK,SAAS,MAAM,OACzB,OAAO,MAAM,MAAM,GAAI,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,GAAG,MAAM,QAAQ,MAAM,GAAG,EAAE,cAAc,UAAU,MAAM,GAAI,GAAG,CACrH;AACF;AAEA,MAAM,sBACJ,UACA,MACA,WACA,WACa;CACb,MAAM,EAAE,MAAM,SAAS;CACvB,MAAM,QAAkB,CAAC;CACzB,IAAI,KAAK,cAAc,SAAS,UAC9B,MAAM,KAAK,GAAG,KAAK,IAAI,KAAK,YAAY,cAAc,kBAAkB,yBAAyB;CACnG,IAAI,SAAS,SAAS,KAAA,GAAW,MAAM,KAAK,GAAG,aAAa,GAAG,KAAK,OAAO,KAAK,MAAM,SAAS,IAAI,CAAC;CACpG,IAAI,SAAS,YAAY,KAAA,GAAW,MAAM,KAAK,GAAG,aAAa,GAAG,KAAK,WAAW,KAAK,SAAS,SAAS,OAAO,CAAC;CACjH,IAAI,SAAS,YAAY,KAAA,KAAa,KAAK,YAAY,SAAS,SAC9D,MAAM,KAAK,GAAG,KAAK,IAAI,KAAK,WAAW,KAAK,gCAAgC,SAAS,SAAS;CAChG,IAAI,SAAS,MAAM;EACjB,IAAI,KAAK,UAAU,MAAM,MAAM,KAAK,GAAG,KAAK,eAAe,KAAK,MAAM,gCAAgC;EACtG,OAAO;CACT;CACA,IAAI,KAAK,UAAU,KAAK,OAAO,MAAM,KAAK,GAAG,KAAK,eAAe,KAAK,SAAS,UAAU,QAAQ,KAAK,OAAO;CAC7G,IAAI,KAAK,UAAU,MAAM,OAAO,CAAC,GAAG,OAAO,GAAG,KAAK,sBAAsB;CACzE,IAAI,CAAC,OAAO,KAAK,OAAO,KAAK,MAAM,GACjC,MAAM,KAAK,GAAG,KAAK,oBAAoB,QAAQ,KAAK,OAAO,GAAG,EAAE,cAAc,UAAU,KAAK,MAAM,GAAG;CACxG,IAAI,KAAK,kBAAkB,KAAA,GAAW,OAAO;CAC7C,IAAI,KAAK,cAAc,QAAQ,CAAC,OAAO,KAAK,WAAW,KAAK,aAAa,GACvE,MAAM,KAAK,GAAG,KAAK,iBAAiB,KAAK,cAAc,OAAO,2BAA2B,GAAG,QAAQ,KAAK,WAAW,GAAG,EAAE,kCAAkC,YAAY,UAAU,KAAK,aAAa,GAAG;CACxM,IAAI,cAAc,MAAM,OAAO;CAC/B,MAAM,SAAS,OAAO,GAAG,EAAE;CAC3B,MAAM,OAAO,OAAO,GAAG,EAAE;CACzB,IAAI,SAAS,KAAA,KAAa,OAAO,aAAc,WAAW,KAAA,KAAa,SAAS,WAC9E,MAAM,KAAK,GAAG,KAAK,sDAAsD;CAC3E,OAAO;AACT;;;;;;AAOA,MAAa,gBAAgB,KAAU,aAAwC;CAC7E,MAAM,EAAE,QAAQ,WAAW;CAC3B,MAAM,UAAU,OAAuC,OAAO,MAAM,UAAU,MAAM,OAAO,EAAE;CAC7F,MAAM,OAAO;EACX,aAAa,IAAI;EACjB,OAAO,IAAI;EACX,SAAS,EAAE,MAAM,WAAW;EAC5B,SAAS;EACT,QAAQ;EACR,SAAS;EACT,OAAO,CAAC;EACR,QAAQ;EACR,iBAAiB,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,OAAO,SAAS,CAAC,CAAC;EAClG,MAAM;CACR;CACA,MAAM,UAAU,SAA2B;EAAE,GAAG;EAAM,MAAM;EAAK,SAAS;CAAK;CAC/E,MAAM,SAAS,OAAO,QAAQ;CAC9B,MAAM,QAAQ,OAAO,OAAO;CAC5B,IAAI,WAAW,KAAA,GAAW,OAAO,OAAO,sCAAsC;CAC9E,IAAI,UAAU,KAAA,KAAa,OAAO,MAAM,MAAM,KAAA,GAAW,OAAO,OAAO,kCAAkC;CACzG,IAAI,IAAI,SAAS,MAAM,OAAO,OAAO,+EAA+E;CACpH,IAAI,IAAI,OAAO,GAAG,OAAO,OAAO,sBAAsB,IAAI,KAAK,SAAS;CACxE,MAAM,SAAS,IAAI,UAAU,CAAC,EAAA,CAAG,QAAQ,SAAS,KAAK,OAAO,WAAW,KAAK,KAAK,OAAO,CAAC;CAC3F,IAAI,MAAM,WAAW,GAAG,OAAO,OAAO,2CAA2C;CAEjF,MAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC,KAAK,UAAU,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC;CAC9G,MAAM,YAAY,IAAI,IAAI,SAAS,YAAY,KAAK,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;CAC/E,MAAM,cAAc,MAAM,KAAK,SAAS,eAAe,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,CAAC;CACtF,MAAM,WAAW,SAAS,aAAa,KAAA,IAAY,KAAA,IAAY,YAAY,MAAM,SAAS,KAAK,SAAS,SAAS,QAAQ;CACzH,IAAI,SAAS,aAAa,KAAA,MAAc,aAAa,KAAA,KAAa,CAAC,SAAS,aAAa,SAAS,YAAY,IAC5G,OAAO,OAAO,GAAG,SAAS,SAAS,kFAAkF;CAEvH,MAAM,UAAU,UAA0BA,WAAS,OAAO,KAAK,IAAIA,WAAS,QAAQ,KAAK;CACzF,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,MAAM,YAAY,IAAI,CAAC,EAAE,KAAK,OAAO;CACjG,MAAM,UAAU,SAAS,QAAQ;CACjC,MAAM,UAAU,YAAY,KAAA,IAAY,KAAA,IAAY,MAAM,MAAM,SAASA,WAAS,MAAM,UAAU,IAAIA,WAAS,QAAQ,UAAU,KAAK,OAAO;CAC7I,MAAM,WAAW,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU;CAE/D,MAAM,OAAO,SAAS,MAAM,SAAS;CACrC,MAAM,MAAM,aAAa,KAAA,IAAY,KAAK,MAAM,WAAW,SAAS,KAAK,KAAK,SAAS,KAAKA,WAAS,MAAM,OAAO,IAAI,IAAI;CAC1H,MAAM,QAAQ,MAAM,IAAI,KAAA,IAAY,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,SAASA,WAAS,MAAM,OAAO,KAAK,IAAI;CACnG,MAAM,UAAU,OACb,QAAQ,UAAU,MAAM,OAAO,UAAU,CAAC,CAC1C,QAAQ,KAAK,UAAU,OAAO,MAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,QAAQ,CAAC,SAAS,IAAI,CAAC;CAC9F,MAAM,QAAsB;EAC1B,KAAKA,WAAS,QAAQ,KAAK;EAC3B,MAAM,KAAK,IAAI,GAAG,MAAM,KAAK,SAASA,WAAS,MAAM,OAAO,CAAC,CAAC;EAC9D,WAAW,YAAY,QAAQ,SAAS,KAAK,SAAS,CAAC,CAAC;EACxD,WAAW,OAAO,WAAW;EAC7B,OAAO,OAAO,OAAO;EACrB,SAAS,OAAO,SAAS;EACzB,UAAU,OAAO,UAAU;EAC3B,QAAQ,OAAO,QAAQ;EACvB;EACA,QAAQ,YAAY,KAAA,IAAY,OAAOD,UAAQ,OAAO,QAAQ,CAAC;EAC/D,MAAM,UAAU,KAAA,IAAY,OAAOA,UAAQ,OAAO,MAAM,CAAC;EACzD;CACF;CAEA,MAAM,QAAkB,CAAC;CACzB,IAAI,MAAM,QAAQ,SAAS,KAAK,MAAM,KAAK,gBAAgB,MAAM,IAAI,QAAQ,SAAS,KAAK;CAC3F,IAAI,MAAM,SAAS,SAAS,MAAM,MAAM,KAAK,kBAAkB,MAAM,KAAK,QAAQ,SAAS,MAAM;CACjG,IAAI,MAAM,cAAc,SAAS,WAAW,MAAM,KAAK,GAAG,MAAM,UAAU,kBAAkB,SAAS,WAAW;CAChH,IAAI,MAAM,YAAY,SAAS,UAAU,OAAO,MAAM,YAAY,SAAS,UAAU,MACnF,MAAM,KAAK,GAAG,MAAM,UAAU,uBAAuB,SAAS,UAAU,IAAI,IAAI,SAAS,UAAU,KAAK,EAAE;CAC5G,IAAI,MAAM,WAAW,SAAS,QAAQ,MAAM,KAAK,GAAG,MAAM,OAAO,eAAe,SAAS,QAAQ;CACjG,IAAI,MAAM,YAAY,GAAG,MAAM,KAAK,GAAG,MAAM,QAAQ,mCAAmC;CACxF,IAAI,SAAS,YAAY,KAAA,KAAa,MAAM,YAAY,SAAS,SAC/D,MAAM,KAAK,GAAG,MAAM,QAAQ,iBAAiB,SAAS,SAAS;CACjE,IAAI,SAAS,WAAW,KAAA,MAAc,MAAM,WAAW,QAAQ,CAAC,OAAO,MAAM,QAAQ,SAAS,OAAO,MAAM,IACzG,MAAM,KAAK,sBAAsB,MAAM,WAAW,OAAO,YAAY,GAAG,QAAQ,MAAM,QAAQ,GAAG,EAAE,IAAI,YAAY,UAAU,SAAS,OAAO,MAAM,GAAG;CACxJ,IAAI,SAAS,SAAS,KAAA,MAAc,MAAM,SAAS,QAAQ,CAAC,OAAO,MAAM,MAAM,SAAS,KAAK,MAAM,IACjG,MAAM,KAAK,yBAAyB,SAAS,KAAK,MAAM,MAAM,MAAM,SAAS,OAAO,YAAY,GAAG,QAAQ,MAAM,MAAM,GAAG,EAAE,IAAI,YAAY,UAAU,SAAS,KAAK,MAAM,GAAG;CAC/K,KAAK,MAAM,QAAQ,SAAS,aAAa;EACvC,MAAM,OAAO,YAAY,MAAM,eAAe,WAAW,SAAS,KAAK,IAAI;EAC3E,IAAI,SAAS,KAAA,GAAW;GACtB,MAAM,KAAK,GAAG,KAAK,KAAK,6BAA6B;GACrD;EACF;EACA,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,MAAM,YAAY,KAAK,IAAI;EACtF,MAAM,SAAS,UAAU,KAAK,OAAO,QAAQ,CAAC,CAAC,QAAQ,WAAW,OAAO,OAAO,SAAS,CAAC,CAAC,KAAK,WAAW,OAAO,IAAI;EACtH,MAAM,KAAK,GAAG,mBAAmB,MAAM,MAAM,SAAS,KAAK,MAAM,MAAM,CAAC;CAC1E;CACA,OAAO;EAAE,GAAG;EAAM,MAAM;EAAM,SAAS,MAAM,WAAW,IAAI,OAAO,MAAM,KAAK,IAAI;EAAG;CAAM;AAC7F;;;;AClOA,MAAM,OAAO;AAiCb,MAAM,YAAY,MAA8B,UAAiC;CAC/E,MAAM,QAAQ,OAAO;CACrB,OAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;;AAGA,MAAM,cAAc,MAA8B,MAA8B,UAAmC;CACjH,MAAM,QAAQ,SAAS,MAAM,KAAK;CAClC,OAAO,SAAS,KAAA,KAAa,UAAU,OAAO,OAAOE,UAAQ,KAAK,GAAG,KAAK;AAC5E;AAEA,MAAM,WAAW,SACf,SAAS,KAAA,IACL,OACA;CACE,OAAO,OAAO,KAAK,QAAQ;CAC3B,MAAM,SAAS,KAAK,OAAO,SAAS,MAAM,SAAS,KAAK,KAAK,GAAG,IAAI,KAAK,GAAG;CAC5E,OAAO,SAAS,MAAM,OAAO,KAAK;CAClC,aAAa,SAAS,MAAM,cAAc,KAAK;AACjD;;AAGN,MAAMC,gBAAc,MAAwB,QAAiB,aAA4C;CACvG,MAAM,QAAkB,CAAC;CACzB,MAAM,EAAE,KAAK,UAAU,SAAS,SAAS,aAAa;CACtD,IAAI,OAAO,WAAW,UAAU,MAAM,KAAK,yBAAyB,OAAO,kCAAkC;CAC7G,IAAI,KAAK,UAAU,KAAK,MAAM,KAAK,mBAAmB,KAAK,MAAM,cAAc,KAAK;CACpF,IAAI,KAAK,UAAU,KAAK,MAAM,KAAK,kBAAkB,KAAK,MAAM,oBAAoB,KAAK;CACzF,IAAI,aAAa,KAAA,KAAa,KAAK,aAAa,UAC9C,MAAM,KAAK,oCAAoC,KAAK,YAAY,UAAU,QAAQ,UAAU;CAC9F,IAAI,YAAY,KAAA,GAAW;EACzB,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,MAAM,MAAM,KAAK,iCAAiC;OAC3D;GACH,IAAI,MAAM,UAAU,QAAQ,OAAO,MAAM,KAAK,yCAAyC,MAAM,MAAM,QAAQ,QAAQ,OAAO;GAC1H,IAAI,CAAC,OAAO,MAAM,MAAM,QAAQ,MAAM,GACpC,MAAM,KAAK,mCAAmC,QAAQ,MAAM,MAAM,GAAG,EAAE,cAAc,UAAU,QAAQ,MAAM,GAAG;GAClH,IAAI,MAAM,UAAU,QAAQ,OAAO,MAAM,KAAK,0BAA0B,MAAM,MAAM,QAAQ,QAAQ,OAAO;GAC3G,IAAI,MAAM,gBAAgB,QAAQ,aAAa,MAAM,KAAK,0BAA0B,MAAM,YAAY,QAAQ,QAAQ,aAAa;EACrI;CACF;CACA,IAAI,YAAY,KAAA,GACT;OAAA,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC,cAAc,KAAK,SAAS,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,GAC7E,IAAI,SAAS,QAAQ,CAAC,OAAO,MAAM,OAAO,GACxC,MAAM,KAAK,OAAO,KAAK,wBAAwB,SAAS,OAAO,YAAY,GAAG,QAAQ,MAAM,GAAG,EAAE,IAAI,YAAY,UAAU,OAAO,GAAG;CAAA;CAG3I,IAAI,aAAa,KAAA,GAAW;EAC1B,MAAM,QAAQ,KAAK;EACnB,IAAI,KAAK,WAAW,KAAK,MAAM,KAAK,kBAAkB,KAAK,UAAU,UAAU,+BAA+B,KAAK;EACnH,MAAM,EAAE,YAAY;EACpB,IAAI,YAAY,KAAA,GAAW;GACzB,IAAI,KAAK,WAAW,SAAS,QAAQ,MAAM,KAAK,wBAAwB,KAAK,UAAU,UAAU,QAAQ,SAAS,QAAQ;GAC1H,IAAI,KAAK,UAAU,SAAS,OAAO,MAAM,KAAK,kBAAkB,KAAK,SAAS,UAAU,0BAA0B,SAAS,OAAO;EACpI,OAAO,IAAI,KAAK,WAAW,QAAQ,KAAK,SAAS,SAAS,UAAU,KAAK,SAAS,SAChF,MAAM,KAAK,wBAAwB,KAAK,UAAU,UAAU,YAAY,SAAS,OAAO,MAAM,SAAS;OAClG,IAAI,KAAK,UAAU,KAAK,SAAS,GACtC,MAAM,KAAK,kBAAkB,KAAK,SAAS,UAAU,0BAA0B,KAAK,SAAS,GAAG;EAElG,IAAI,UAAU,MAAM,MAAM,KAAK,kCAAkC;OAC5D;GACH,IAAI,MAAM,UAAU,MAAM,MAAM,KAAK,0CAA0C,MAAM,OAAO;GAC5F,IAAI,CAAC,SAAS,OAAO,MAAM,UAAU,OAAO,MAAM,MAAM,KAAK,CAAC,GAC5D,MAAM,KAAK,oCAAoC,QAAQ,MAAM,MAAM,GAAG,EAAE,gCAAgC;EAC5G;CACF;CACA,OAAO;AACT;;;;;;AAOA,MAAa,oBAAoB,KAAU,aAA4C;CACrF,MAAM,EAAE,QAAQ,WAAW;CAC3B,MAAM,kBAAkB,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,OAAO,SAAS,CAAC,CAAC;CACzG,MAAM,OAAO;EACX,aAAa,IAAI;EACjB,OAAO,IAAI;EACX,SAAS,EAAE,MAAM,WAAW;EAC5B,SAAS;EACT,QAAQ;EACR,SAAS;EACT,OAAO,CAAC;EACR,QAAQ;EACR;EACA,MAAM;CACR;CACA,MAAM,UAAU,SAA2B;EAAE,GAAG;EAAM,MAAM;EAAK,SAAS;CAAK;CAC/E,MAAM,YAAY,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW;CACjE,IAAI,cAAc,KAAA,GAAW,OAAO,OAAO,kBAAkB,OAAO,UAAU,QAAQ,EAAE,+CAA+C;CACvI,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,MAAM,MAAM,KAAA,GAAW;EAE7D,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;EACzD,OAAO,OAAO,UAAU,KAAA,IAAY,qCAAqC,qCAAqC,OAAO,MAAM,OAAO,GAAG;CACvI;CACA,IAAI,IAAI,SAAS,MAAM,OAAO,OAAO,+EAA+E;CACpH,IAAI,IAAI,OAAO,GAAG,OAAO,OAAO,sBAAsB,IAAI,KAAK,SAAS;CAExE,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,MAAM;CACvD,IAAI,SAAS,KAAA,GAAW,OAAO,OAAO,uCAAuC;CAC7E,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CACzD,MAAM,UAAU,OAAO,MAAM,UAAU,MAAM,OAAO,SAAS;CAC7D,MAAM,UAAU,OAAO,MAAM,UAAU,MAAM,OAAO,SAAS;CAC7D,MAAM,SAAS,OAAO,MAAM,UAAU,MAAM,OAAO,QAAQ;CAE3D,MAAM,YAAY,IAAI,UAAU,CAAC,EAAA,CAAG,QAAQ,SAAS,KAAK,OAAO,WAAW,KAAK,KAAK,KAAK,MAAM,UAAU,KAAA,KAAa,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE;CACjJ,MAAM,YAA8B;EAClC,OAAO,SAAS,MAAM,OAAO,KAAK;EAClC,OAAO,SAAS,MAAM,OAAO,KAAK;EAClC,UAAU,SAAS,UAAU,OAAO;EACpC,OAAO,QAAQ,KAAK;EACpB,WAAW,WAAW,SAAS,SAAS,YAAY;EACpD,MAAM,WAAW,SAAS,SAAS,MAAM;EACzC,QAAQ,SAAS,QAAQ,OAAO;EAChC,QAAQ,SAAS,WAAW,OAAO,QAAQ;EAC3C,OAAO,SAAS,OAAO,OAAO;CAChC;CACA,MAAM,QAAQA,aAAW,WAAW,KAAK,UAAU,QAAQ;CAC3D,OAAO;EAAE,GAAG;EAAM,MAAM;EAAM,SAAS,MAAM,WAAW,IAAI,OAAO,MAAM,KAAK,IAAI;EAAG;CAAU;AACjG;;;;AC5GA,MAAM,WAAW;;AAGjB,MAAa,aAAa,MAAc,UAAqC;CAC3E,MAAM,QAAQ,SAAS,KAAK,IAAI;CAChC,IAAI,UAAU,MAAM,OAAO;CAC3B,MAAM,OAAO,KAAK,IAAI,OAAO,MAAM,EAAE,GAAG,OAAO,MAAM,EAAE,IAAI,GAAG,OAAO,MAAM,EAAE,GAAG,OAAO,MAAM,EAAE,GAAG,OAAO,MAAM,EAAE,GAAG,OAAO,MAAM,EAAE,GAAG,OAAO,MAAM,EAAE,CAAC;CACtJ,OAAO,MAAM,KAAK,OAAO,OAAO,MAAM,OAAO,KAAK;AACpD;;AAGA,MAAM,kBAAkB,MAAc,OAAyB,SAAS,KAAK,OAAO,KAAK,QAAQ,GAAG,IAAI,KAAK,GAAG;AAEhH,MAAM,YAAY,MAAgB,SAA6B;CAC7D,MAAM,UAAU,QAAQ,MAAM,GAAG;CACjC,OAAO,WAAW,QAAQ,KAAK,KAAK,GAAG,KAAK,WAAW,QAAQ,KAAK,MAAM,GAAG;AAC/E;AAEA,MAAM,YAAY,SAA4B,IAAI,QAAQ,KAAK,KAAK,GAAG,EAAE,IAAI,QAAQ,KAAK,MAAM,GAAG,EAAE;AAErG,MAAM,YAAY,UAA+B,MAAM,OAAO,cAAc,MAAM,OAAO,aAAa,MAAM,OAAO;;AAGnH,MAAM,gBAAgB,OAAmB,UAAqD,MAAM,UAA4C,CAAC;;AAGjJ,MAAM,cAAc,WAA0D,OAAO,SAAS,QAAQ;;AAGtG,MAAM,YAAY,OAAmB,cAAqC;CACxE,MAAM,QAAS,MAAM,UAAU,GAA2D,OAAO,SAAS;CAC1G,OAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;;;;;;AAOA,MAAa,cAAc,OAA8B,UAA0C;CACjG,MAAM,OAAO,WAAW,KAAK;CAC7B,MAAM,SAAS,WAAW,KAAK;CAC/B,IAAI,SAAS,KAAA,KAAa,WAAW,KAAA,GAAW,OAAO;CACvD,MAAM,OAAO,aAAa,MAAM,MAAM;CACtC,MAAM,SAAS,aAAa,QAAQ,MAAM;CAC1C,IAAI,KAAK,WAAW,KAAK,OAAO,WAAW,KAAK,KAAK,OAAO,OAAO,IAAI,OAAO;CAE9E,OADgB,MAAM,QAAQ,UAAU,MAAM,OAAO,YAAY,MAAM,IAAI,KAAK,KAAK,SAAS,OAAO,KAAK,EAAG,MAAM,IACtG,CAAC,CAAC,UAAU;AAC3B;;AAGA,MAAa,eAAe,SAC1B,0GAA0G,KAAK,IAAI;;AAGrH,MAAa,cAAc,MAAc,UAA2B,KAAK,SAAS,YAAY,MAAM,EAAE,KAAK,KAAK,SAAS,YAAY,MAAM,KAAK;;AAGhJ,MAAM,cAAc,SAAuB,YAA6B,QAA2B,iBAAoC;CACrI,MAAM,QAAkB,CAAC;CACzB,MAAM,EAAE,QAAQ,OAAO,aAAa;CACpC,IAAI,WAAW,UAAU,MAAM;EAC7B,IAAI,OAAO,SAAS,GAAG,MAAM,KAAK,+BAA+B,OAAO,IAAI;EAC5E,IAAI,cAAc,MAAM,KAAK,yCAAyC;CACxE,OAAO;EACL,IAAI,UAAU,MAAM,MAAM,KAAK,iFAAiF;OAC3G,IAAI,CAAC,SAAS,OAAO,WAAW,KAAK,GAAG,MAAM,KAAK,gBAAgB,QAAQ,OAAO,GAAG,EAAE,cAAc,SAAS,WAAW,KAAK,GAAG;EACtI,IAAI,QAAQ,eAAe,QAAQ,SAAS,MAAM,KAAK,sCAAsC,QAAQ,WAAW,2BAA2B,QAAQ,SAAS;CAC9J;CACA,IAAI,WAAW,aAAa,MAAM;EAChC,IAAI,aAAa,MAAM,MAAM,KAAK,+CAA+C;OAC5E,IAAI,CAAC,SAAS,UAAU,WAAW,QAAQ,GAAG,MAAM,KAAK,8CAA8C,QAAQ,UAAU,GAAG,EAAE,cAAc,SAAS,WAAW,QAAQ,GAAG;CAClL;CACA,IAAI,WAAW,MAAM;EACnB,MAAM,KAAK,0CAA0C;EACrD,OAAO;CACT;CACA,QAAQ,WAAW,MAAnB;EACE,KAAK;GACH,IAAI,OAAO,SAAS,yBAAyB,MAAM,KAAK,kCAAkC,OAAO,QAAQ,oBAAoB,4BAA4B;GACzJ;EACF,KAAK;GACH,IAAI,CAAC,OAAO,OAAO,MAAM,KAAK,yCAAyC,OAAO,MAAM;GACpF,IAAI,OAAO,UAAU,QAAQ,aAAa,MAAM,KAAK,0BAA0B,QAAQ,YAAY,MAAM,OAAO,OAAO;GACvH;EACF,KAAK,UAAU;GACb,MAAM,SAAS,WAAW;GAC1B,IAAI,QAAQ,WAAW,MAAM,MAAM,KAAK,oCAAoC;QACvE,IAAI,WAAW,KAAA,KAAa,QAAQ,QAAQ,QAAQ,GAAG,IAAI,QAAQ,QAAQ,GAAG,GAAG,MAAM,KAAK,yBAAyB,QAAQ,QAAQ,QAAQ,GAAG,EAAE,YAAY,QAAQ,QAAQ,GAAG,EAAE,GAAG;GAC3L,IAAI,CAAC,OAAO,OAAO,MAAM,KAAK,gCAAgC,OAAO,MAAM;GAC3E,IAAI,QAAQ,YAAY,MAAM,KAAK,uDAAuD;GAC1F,IAAI,QAAQ,cAAc,QAAQ,OAAO,MAAM,KAAK,2BAA2B,QAAQ,UAAU,+BAA+B,QAAQ,OAAO;GAC/I,IAAI,QAAQ,UAAU,QAAQ,QAAQ,cAAc,QAAQ,QAAQ,SAAS,QAAQ,WAAW,MAAM,KAAK,oBAAoB,QAAQ,MAAM,6BAA6B,QAAQ,UAAU,qBAAqB;GACjN;EACF;CACF;CACA,OAAO;AACT;;AAGA,MAAa,gBAAgB,KAAU,eAA0C;CAC/E,MAAM,kBAAkB,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,OAAO,SAAS,CAAC,CAAC;CAC7G,MAAM,OAAO;EACX,aAAa,IAAI;EACjB,OAAO,IAAI;EACX,SAAS,EAAE,MAAM,WAAW;EAC5B,SAAS;EACT,QAAQ;EACR,SAAS;EACT,OAAO,CAAC;EACR,QAAQ;EACR;EACA,MAAM;CACR;CACA,MAAM,UAAU,SAA2B;EAAE,GAAG;EAAM,MAAM;EAAK,SAAS;CAAK;CAE/E,MAAM,EAAE,OAAO,MAAM,UAAU;CAC/B,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO,OAAO,6DAA6D;CACtH,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM,OAAO,OAAO,sBAAsB;CAC7E,MAAM,OAAO,MAAM;CACnB,MAAM,OAAO,KAAK;CAClB,MAAM,SAAS,IAAI,OAAO,QAAQ,UAAU,MAAM,IAAI,IAAI;CAC1D,MAAM,QAAQ,IAAI,OAAO,QAAQ,UAAU,MAAM,KAAK,IAAI;CAC1D,MAAM,QAAQ,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CAC7D,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,gCAAgC;CAEvE,MAAM,OAAO,WAAW,MAAM;CAC9B,MAAM,SAAS,WAAW,MAAM,MAAM,QAAQ,UAAU,MAAM,IAAI,IAAI,CAAC;CACvE,MAAM,OAAO,SAAS,KAAA,IAAY,CAAC,IAAI,aAAa,MAAM,MAAM;CAChE,MAAM,SAAS,WAAW,KAAA,IAAY,CAAC,IAAI,aAAa,QAAQ,MAAM;CACtE,MAAM,YAAY,KAAK;CACvB,IAAI,cAAc,KAAA,KAAa,KAAK,WAAW,KAAK,OAAO,WAAW,KAAK,OAAO,OAAO,WACvF,OAAO,OAAO,6DAA6D;CAC7E,IAAI,MAAM,MAAM,UAAU,MAAM,OAAO,OAAO,CAAC,GAAG,UAAU,WAAW,OAAO,OAAO,mDAAmD;CACxI,IAAI,OAAO,UAAU,UAAU,MAAM,OAAO,MAAM,CAAC,GAAG,iBAAiB,WAAW,OAAO,OAAO,wDAAwD;CACxJ,MAAM,aAAa,OAAO,UAAU,UAAU,MAAM,OAAO,YAAY,SAAS,OAAO,SAAS,MAAM,IAAI;CAC1G,IAAI,eAAe,KAAA,GAAW,OAAO,OAAO,wEAAwE;CAEpH,MAAM,SAAS,OAAO,OAAO,SAAS;CAEtC,MAAM,UADa,MAAM,OAAO,QAAQ,SAAS,KAAK,SAAS,MAAM,CAC5C,CAAC,CAAC,KAAK,SAAS,UAAU,MAAM,KAAK,CAAC,CAAC,CAAC,MAAM,SAAS,SAAS,QAAQ,QAAQ,IAAI,KAAK;CAClH,MAAM,QAAQ,MAAM,MAAM,MAAM,UAAU,MAAM,OAAO,cAAc,MAAM,KAAK,QAAQ,aAAa,OAAO,YAAY,CAAC,CAAC,SAAS,SAAS,CAAC;CAC7I,IAAI,WAAW,UAAU,QAAQ,YAAY,QAAQ,UAAU,KAAA,GAAW,OAAO,OAAO,2CAA2C;CAEnI,MAAM,SAAS,MAAM,MAAM,UAAU,MAAM,OAAO,YAAY,MAAM,OAAO,aAAa;CACxF,MAAM,WAAW,MAAM,MAAM,UAAU,MAAM,OAAO,UAAU;CAC9D,MAAM,QAAQ,QAAQ,KAAK,OAAO;CAClC,MAAM,cAAc,MAAM,MAAM,UAAU,UAAU,MAAM,OAAO,YAAY,MAAM,IAAI,SAAS,SAAS,OAAO,SAAS,MAAM,IAAI;CACnI,MAAM,YAAY,MAAM,MAAM,UAAU,MAAM,OAAO,WAAW;CAChE,MAAM,WAAW,UAAkD,OAAO,QAAQ,aAAa,WAAW,MAAM,WAAW;CAE3H,MAAM,eAA6B;EACjC;EACA,OAAO,YAAY,OAAO,OAAO,eAAe,MAAM,OAAO;EAC7D,UAAU,UAAU,KAAA,IAAY,OAAO,eAAe,MAAM,MAAM,CAAC;EACnE,QACE,WAAW,KAAA,IACP,OACA;GACE,OAAO,OAAO,OAAO;GACrB,MAAM,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;GAC5D,SAAS,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;GACrE,OAAO,QAAQ,MAAM;EACvB;EACN,aAAa,QAAQ,UAAU;EAC/B,SAAS,SAAS,YAAY,SAAS;EACvC,YAAa,MAAM,MAAM,MAAM,UAAU,MAAM,OAAO,UAAU,MAAM,KAAK,QAAQ,MAAM,iBAAiB,SAAS,CAAC,GAAG,YAAmC;EAC1J,WAAW,gBAAgB,KAAA,IAAY,OAAO,SAAS,aAAa,SAAS;EAC7E,QAAQ,aAAa,KAAA,IAAY,OAAO,eAAe,MAAM,SAAS,CAAC;EACvE,YAAY,MAAM,MAAM,UAAU,MAAM,OAAO,cAAc,MAAM,KAAK,QAAQ,MAAM,KAAK,SAAS,aAAa,OAAO,YAAY,CAAC,CAAC,SAAS,SAAS,CAAC;EACzJ,WAAW,cAAc,KAAA,IAAY,OAAO,SAAS,WAAW,SAAS;EACzE,OAAO,WAAW,KAAA,IAAY,OAAO,SAAS,QAAQ,SAAS;CACjE;CACA,MAAM,WAAW,WAAW,cAAc,YAAY,MAAM,QAAQ,UAAU,KAAA,CAAS;CACvF,OAAO;EAAE,GAAG;EAAM,MAAM;EAAM,SAAS,SAAS,WAAW,IAAI,OAAO,SAAS,KAAK,IAAI;EAAG,OAAO;CAAa;AACjH;;;;AC7NA,MAAM,UAAU;AAwBhB,MAAM,WAAW,SACf,MAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,QAAQ,CAAC,QAAQ,SAAyB,OAAO,SAAS,QAAQ,IAAI,CAAC;;AAG7G,MAAM,YAAY,OAA0B,QAAyB;CACnE,MAAM,MAAM,MAAM,WAAW,UAAU,OAAO,OAAO,MAAM,CAAC;CAC5D,OAAO,MAAM,KAAK,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,UAAU,OAAO,OAAO,MAAM,CAAC;AAC3E;;;;;;AAOA,MAAa,gBAAgB,KAAU,aAAwC;CAC7E,MAAM,EAAE,QAAQ,WAAW;CAC3B,MAAM,kBAAkB,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,OAAO,SAAS,CAAC,CAAC;CACzG,MAAM,OAAO;EACX,aAAa,IAAI;EACjB,OAAO,IAAI;EACX,SAAS,EAAE,MAAM,WAAW;EAC5B,SAAS;EACT,QAAQ;EACR,SAAS;EACT,OAAO,CAAC;EACR,QAAQ;EACR;EACA,MAAM;CACR;CACA,MAAM,UAAU,SAA2B;EAAE,GAAG;EAAM,MAAM;EAAK,SAAS;CAAK;CAC/E,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,MAAM,MAAM,KAAA,GAAW,OAAO,OAAO,kCAAkC;CAC/G,IAAI,IAAI,SAAS,MAAM,OAAO,OAAO,+EAA+E;CACpH,IAAI,IAAI,OAAO,GAAG,OAAO,OAAO,sBAAsB,IAAI,KAAK,SAAS;CAExE,MAAM,SAAS,OAAO,QAAQ,UAAU,MAAM,OAAO,OAAO;CAC5D,MAAM,UAAU,OAAO,MAAM,UAAU,MAAM,OAAO,SAAS;CAC7D,MAAM,aAAa,OAAO,QAAQ,UAAU,MAAM,OAAO,OAAO;CAChE,MAAM,SAAiC,CAAC;CACxC,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,QAAQ,OAAO,QAAQ,KAAK,CAAC,CAAC,MAAM;EAC1C,OAAO,UAAU,OAAO,UAAU,KAAK;CACzC;CACA,MAAM,OAAO,CAAC,GAAG,IAAI,IAAI,OAAO,SAAS,UAAU,QAAQ,KAAK,CAAC,CAAC,KAAK,SAAS,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAC5H,MAAM,UAAU,KAAK,IAAI,GAAG,GAAG,OAAO,KAAK,UAAW,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa,CAAE,CAAC;CACnH,MAAM,QAAQ,WAAW;CACzB,MAAM,OAAO,WAAW,GAAG,EAAE;CAC7B,MAAM,QAAsB;EAC1B,QAAQ,OAAO;EACf;EACA;EACA,QAAQ,CAAC,GAAG,IAAI,IAAI,OAAO,KAAK,UAAU,OAAO,MAAM,QAAQ,CAAC,CAAC,CAAC;EAClE,SAAS,SAAS,KAAK,MAAM,UAAU,GAAG,IAAI,KAAK,GAAG;EACtD,YAAY,YAAY,KAAA,KAAa,UAAU,KAAA,IAAY,OAAOC,UAAQ,QAAQ,GAAG,MAAM,CAAC;EAC5F,WAAW,YAAY,KAAA,KAAa,SAAS,KAAA,IAAY,OAAOA,UAAQ,QAAQ,GAAG,KAAK,CAAC;EACzF,OAAO,WAAW;EAClB,OAAO,SAAS,KAAA,KAAa,OAAO,KAAK,aAAa,WAAW,IAAI,KAAK;CAC5E;CAEA,MAAM,QAAkB,CAAC;CACzB,MAAM,WAAW,SAAS,SAAS,SAAS;CAC5C,IAAI,MAAM,WAAW,UAAU,MAAM,KAAK,GAAG,MAAM,OAAO,iBAAiB,UAAU;CACrF,MAAM,QAAQ,OAAO,KAAK,MAAM,CAAC,CAAC,QAAQ,UAAU,CAAC,SAAS,OAAO,SAAS,OAAO,KAAK,CAAC,CAAC;CAC5F,IAAI,MAAM,SAAS,GAAG,MAAM,KAAK,iBAAiB,MAAM,KAAK,MAAM,EAAE,qBAAqB,SAAS,OAAO,KAAK,MAAM,GAAG;CACxH,IAAI,KAAK,KAAK,MAAM,SAAS,KAAK,KAAK,GAAG,MAAM,KAAK,wBAAwB,KAAK,KAAK,GAAG,EAAE,kBAAkB,SAAS,KAAK,KAAK,GAAG,GAAG;CACvI,IAAI,MAAM,OAAO,KAAK,MAAM,SAAS,MAAM,KAAK,2BAA2B,MAAM,OAAO,KAAK,OAAO,EAAE,QAAQ,SAAS;CACvH,IAAI,QAAQ,MAAM,SAAS,GAAG,IAAI,QAAQ,SAAS,eAAe,GAAG,GACnE,MAAM,KAAK,0BAA0B,QAAQ,MAAM,SAAS,GAAG,EAAE,YAAY,QAAQ,SAAS,eAAe,GAAG,EAAE,GAAG;CACvH,IAAI,SAAS,UAAU,KAAA,GAAW;EAChC,MAAM,EAAE,OAAO,KAAK,SAAS,SAAS;EACtC,MAAM,SAAS,OAAO,OAAO,KAAK,MAAM,KAAK,KAAK,IAAI,GAAG,MAAM,MAAM;EACrE,IAAI,QAAQ,OAAO,QAAQ,MAAM,MAAM,KAAK,gBAAgB,MAAM,eAAe,MAAM,aAAa,IAAI,IAAI,KAAK,EAAE;CACrH;CACA,IAAI,SAAS,aAAa,QAAQ,CAAC,OAAO,OAAO,UAAU,SAAS,QAAQ,KAAK,GAAG,SAAS,GAAG,CAAC,GAC/F,MAAM,KAAK,wFAAwF;CACrG,IAAI,SAAS,oBAAoB,KAAA,KAAa,oBAAoB,SAAS,iBACzE,MAAM,KAAK,GAAG,gBAAgB,wBAAwB,SAAS,iBAAiB;CAClF,IAAI,SAAS,UAAU,KAAA,GAAW;EAChC,MAAM,OAAO,KAAK,IAAI,GAAG,SAAS,MAAM;EACxC,IAAI,MAAM,UAAU,MAAM,MAAM,KAAK,GAAG,MAAM,MAAM,wBAAwB,MAAM;EAClF,KAAK,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,UAAU,GAAG,CAAC,QAAQ,MAAM,SAAS,CAAC,GAChF,IAAI,SAAS,QAAQ,CAAC,OAAO,MAAM,SAAS,KAAK,GAC/C,MAAM,KAAK,OAAO,KAAK,qBAAqB,SAAS,OAAO,YAAY,GAAG,QAAQ,MAAM,GAAG,EAAE,IAAI,YAAY,UAAU,SAAS,KAAK,GAAG;EAE7I,IAAI,MAAM,UAAU,GAAG,MAAM,KAAK,mDAAmD;CACvF;CACA,OAAO;EAAE,GAAG;EAAM,MAAM;EAAM,SAAS,MAAM,WAAW,IAAI,OAAO,MAAM,KAAK,IAAI;EAAG;CAAM;AAC7F;;;;;;;;;;;;;;ACpGA,MAAa,gBAAgB;;AAE7B,MAAa,cAAc;;AAE3B,MAAM,cAAc;;AAGpB,MAAa,aAAa,UAAyB,MAAM,SAAS,QAAQ,MAAM,YAAY,GAAG,IAAI,QAAQ,MAAM,KAAK,GAAG;;;;;AAMzH,MAAa,cAAc,OAAc,WAA2B;CAClE,MAAM,YAAY,KAAK,KAAK,QAAQ,MAAM,WAAW,GAAG,IAAI,aAAa;CACzE,MAAM,OAAO,4CAA4C,cAAc;CACvE,OACE,2EACuC,OAAO,8BACtB,MAAM,QAAQ,oDACd,UAAU,kEAAkE,KAAK,uDACtD,OAAO;AAG9D;;AAGA,MAAa,cACX;;AAGF,MAAa,UAAU,SAAyB;CAC9C,MAAM,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,SAAS,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK;CAC7E,MAAM,EAAE,SAAS,KAAK,MAAM,IAAI;CAChC,IAAI,OAAO,SAAS,YAAY,SAAS,IAAI,MAAM,IAAI,MAAM,8BAA8B,MAAM;CACjG,OAAO;AACT;;AAGA,MAAa,qBAAqB,KAAiB,SACjD,GAAG,IAAI,SAAS,OAAO,wBAAwB,KAAK,IAAI,IAAI,QAAQ,CAAC,EAAA,CAAG,KAAK,GAAG,IAAI,KAAK;;;;;;AAO3F,MAAa,cAAc,cACzB,kCACC,YAAY,0BAAwB,MACrC,oBAAoB,YAAY;;AAIlC,MAAM,YAAY,UAAkC;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,UAAU;CAChB,MAAM,OAAO,QAAQ,cAAc,QAAQ,eAAe,QAAQ;CAClE,OAAO,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO,SAAS,OAAO,IAAI,CAAC,IAAI,OAAO,IAAI,IAAI;AACnG;;AAGA,MAAM,eAAe,SACnB,KAAK,MAAM,IAAI,CAAC,CAAC,SAAS,SAAS;CACjC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,WAAW,GAAG,GAAG,OAAO,CAAC;CAC1C,IAAI;EACF,OAAO,CAAC,KAAK,MAAM,IAAI,CAA4B;CACrD,QAAQ;EACN,OAAO,CAAC;CACV;AACF,CAAC;;AASH,MAAM,UAAU,UAAqD;CACnE,MAAM,QAAS,MAAM,KAAK,EAA2F;CACrH,MAAM,IAAI,SAAS,OAAO,CAAC;CAC3B,MAAM,IAAI,SAAS,OAAO,CAAC;CAC3B,OAAO,MAAM,QAAQ,MAAM,OAAO,OAAO;EAAE;EAAG;CAAE;AAClD;;AASA,MAAa,aAAa,SAA4B;CACpD,IAAI,OAAyB;CAC7B,IAAI,UAAyB;CAC7B,KAAK,MAAM,SAAS,YAAY,IAAI,GAAG;EACrC,MAAM,OAAO,OAAO,KAAK;EACzB,IAAI,SAAS,SAAS,SAAS,QAAQ,KAAK,IAAI,KAAK,KAAM,KAAK,MAAM,KAAK,KAAK,KAAK,IAAI,KAAK,IAAK,OAAO;EAC1G,IAAI,MAAM,UAAU,OAAO,MAAM,UAAU,WAAW;EACtD,MAAM,IAAI,SAAU,MAAM,IAAI,EAA2C,CAAC;EAC1E,IAAI,MAAM,SAAS,YAAY,QAAQ,IAAI,UAAU,UAAU;CACjE;CACA,OAAO;EAAE;EAAM;CAAQ;AACzB;;AAGA,MAAa,eAAe,SAAgC;CAC1D,MAAM,OAAO,YAAY,IAAI,CAAC,CAAC,SAAS,aAAa;EACnD,MAAM,IAAI,SAAS,SAAS,IAAI;EAChC,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B,CAAC;CACD,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,GAAG,IAAI;AACpD;;AAGA,MAAa,cAAc,UAA6B,KAAK,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY;CAAE,GAAG,MAAM;CAAG,GAAG,MAAM;AAAE,EAAE,EAAE,EAAE,CAAC;AAgBlI,MAAM,WAAW,UAA0B,KAAK,MAAM,QAAQ,GAAG,IAAI;;AAGrE,MAAM,aAAa,QAA+B,WAA+C;CAC/F,MAAM,uBAAO,IAAI,IAAoB;CACrC,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,IAAI,OAAO,MAAM,IAAI;EAC3B,IAAI,MAAM,OAAO,UAAU,WAAW,QAAQ,IAAI,SAAS,KAAK,IAAI,GAAG,MAAM,CAAC;CAChF;CACA,OAAO;AACT;;AAGA,MAAa,cAAc,OAAc,KAAU,OAAiC;CAClF,MAAM,SAAS,IAAI,OAAO;CAC1B,MAAM,WAAW,WAAW,KAAA,KAAa,OAAO,UAAU,OAAO,OAAO,OAAO,UAAU,OAAO;CAChG,IAAI,MAAM,aAAa,cAAc,WAAW,KAAA,GAAW,OAAO;EAAE,KAAK;EAAM,QAAQ;EAAM,OAAO,CAAC;EAAG,aAAa;EAAM;CAAS;CACpI,MAAM,OAAO,UAAU,IAAI,QAAQ,OAAO,MAAM;CAChD,MAAM,WAAW,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CACtD,MAAM,SAAS,OAAO,QAAQ,GAAG,EAAE,CAAC,EAAE,MAAM,KAAK;CACjD,MAAM,cAAc,SAAS,QAAQ,MAAM,IAAI,MAAM,CAAC,CAAC;CACvD,MAAM,QAAQ,IAAI,OAAO,SAAS;CAClC,IAAI,UAAU,MAAM,OAAO;EAAE,KAAK;EAAM,QAAQ;EAAM,OAAO,CAAC;EAAG;EAAa;CAAS;CACvF,MAAM,OAAO,IAAI,IAAI,KAAK;CAC1B,MAAM,UAAU,MAAM,QAAQ,MAAM,OAAO,WAAW,QAAQ,IAAI,OAAO,MAAM;CAC/E,MAAM,UAAU,QAAQ,WAAW,IAAI,IAAI,KAAK,IAAI,GAAG,OAAO;CAC9D,MAAM,QAAQ,SAAS,QAAQ,MAAM,IAAI,WAAW,CAAC,KAAK,IAAI,CAAC,CAAC;CAChE,MAAM,WAAW,SAAS,QAAQ,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;CAC1D,MAAM,MAAM,aAAa,KAAA,IAAY,OAAO,SAAS,KAAK,KAAK,IAAI,QAAQ,KAAM,GAAG;CACpF,OAAO;EACL,KAAK,QAAQ,OAAO,OAAO;GAAE,OAAO;GAAK,MAAM;EAAI;EACnD,QAAQ,QAAQ,QAAQ,MAAM,UAAU,OAAO,OAAO;GAAE,OAAO,QAAQ,MAAM,QAAQ,MAAM,KAAK,GAAG,CAAC;GAAG,MAAM;EAAI;EACjH;EACA;EACA;CACF;AACF;;AAGA,MAAa,oBAAoB,UAA4B,WAA6B;CACxF,MAAM,WAAqB,CAAC;CAC5B,IAAI,SAAS,aAAa,MAAM,SAAS,KAAK,yEAAyE;MAClH,IAAI,CAAC,SAAS,UAAU,SAAS,KAAK,iDAAiD;CAC5F,IAAI,SAAS,MAAM,SAAS,GAC1B,SAAS,KAAK,oBAAoB,SAAS,MAAM,OAAO,4DAA4D,SAAS,MAAM,IAAI;CACzI,MAAM,OAAO,OAAO,MAAM,UAAU;CACpC,IAAI,SAAS,gBAAgB,QAAQ,SAAS,QAAQ,KAAK,IAAI,OAAO,SAAS,WAAW,IAAA,GACxF,SAAS,KAAK,oBAAoB,KAAK,wBAAwB,SAAS,YAAY,4BAA4B;CAClH,OAAO;AACT;;;;;;;;;;ACvLA,MAAa,SAAmC;CAC9C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAyDA,MAAMC,aAAU,MAAc,OAAyB,SAAS,KAAK,OAAO,KAAK,QAAQ,GAAG,IAAI,KAAK,GAAG;;AAGxG,MAAM,YAAY,KAAU,OAA+B;CACzD,IAAI,OAAO,OAAO,UAAU,OAAO;CACnC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC;CACzB,OAAO,OAAO,QAAQ,IAAI,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,UAAU,KAAK,OAAO,EAAE,CAAC,GAAG,MAAM;AAC7F;;AAGA,MAAa,YAAY,UAAoC,SAAmD;CAC9G,MAAM,MAAwC,CAAC;CAC/C,KAAK,MAAM,QAAQ,UAAU;EAC3B,IAAI,KAAK,OAAO,cAAc,KAAK,IAAI,MAAM;EAC7C,MAAM,QAAQ,OAAO,MAAM,SAAS,SAAS,KAAK,KAAK;EACvD,IAAI,UAAU,KAAA,KAAa,IAAI,WAAW,KAAA,GAAW;EAErD,KAAK,UAAU,YAAY,UAAU,aAAa,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,WAAW,SAAS,GAAG;EACpG,IAAI,SAASA,UAAQ,MAAM,KAAK,CAAC;CACnC;CACA,OAAO;AACT;;AAGA,MAAa,qBAAiD;CAC5D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAcA,MAAa,eAAqH;CAChI,eAAe;EAAE,KAAK,CAAC,KAAK;EAAG,SAAS;EAAqB,IAAI;CAAQ;CACzE,kBAAkB;EAAE,KAAK,CAAC,SAAS,KAAK;EAAG,SAAS;EAA+D,IAAI;CAAQ;CAC/H,SAAS;EAAE,KAAK,CAAC,KAAK;EAAG,SAAS;EAAuB,IAAI;CAAQ;CACrE,aAAa;EAAE,KAAK,CAAC,KAAK;EAAG,SAAS;EAAiC,IAAI;CAAQ;CACnF,UAAU;EAAE,KAAK,CAAC,KAAK;EAAG,SAAS;EAAmC,IAAI;CAAQ;CAClF,0BAA0B;EAAE,KAAK;GAAC;GAAO;GAAO;EAAM;EAAG,SAAS;EAAoD,IAAI;CAAM;AAClI;;AAGA,MAAM,SAAS,MAAqB,OAAkC,KAAa,eAAgC;CACjH,MAAM,OAAO,aAAa;CAC1B,MAAM,SAAS,OAAO,KAAK,aAAa,EAAE;CAC1C,IAAK,KAAK,OAAO,WAAY,WAAW,MAAM,OAAO;CACrD,MAAM,OAAQ,KAAK,WAAW,CAAC;CAE/B,IAAI,UAAU,iBAAiB,CAAC,KAAK,UAAU,IAAI,CAAC,CAAC,SAAS,UAAU,GAAG,OAAO;CAElF,IAAI,UAAU,4BAA4B,OAAO,KAAK,KAAK,MAAM,SAAS,KAAK,gBAAgB,WAAW,OAAO;CACjH,OAAO,KAAK,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC,KAAK,KAAK,QAAQ,KAAK,OAAO,KAAK,UAAU,EAAE,CAAC;AAC7F;;;;;;;;;;AAWA,MAAa,sBACX,KACA,MACA,WACA,UACqC;CACrC,MAAM,MAAwC,CAAC;CAC/C,MAAM,MAAM,IAAI,OAAO,WAAW;CAElC,MAAM,aAAa,GADL,IAAI,OAAO,QAAQ,IAAI,EAAE,MAAM,GACjB;CAC5B,KAAK,MAAM,QAAQ,IAAI,OAAO,YAAY,CAAC,GAAG;EAC5C,IAAI,KAAK,OAAO,YAAY,KAAK,IAAI,MAAM;EAC3C,KAAK,MAAM,SAAS,OAAO,KAAK,YAAY,GAC1C,IAAI,IAAI,WAAW,KAAA,KAAa,MAAM,MAAM,OAAO,KAAK,UAAU,GAAG,IAAI,SAASA,UAAQ,MAAM,KAAK,CAAC;CAC1G;CACA,MAAM,SAAS,YAA8B,OAAO,YAAY,YAAY,QAAQ,WAAW,UAAU;CACzG,KAAK,MAAM,SAAS,IAAI,QAAQ;EAC9B,IAAI,MAAM,IAAI,MAAM;EACpB,IAAI,IAAI,eAAe,KAAA,KAAa,MAAM,OAAO,UAAU,MAAM,aAAa,oBAAoB,CAAC,MAAM,MAAM,UAAU,GAC1G;OAAA,MAAM,OACX,EAAE,SAAS,aAAa,IAAI,aAAaA,UAAQ,MAAM,MAAM,CAAC;EAAA;EAExE,IAAI,IAAI,mBAAmB,KAAA,KAAa,MAAM,OAAO,UAAU,MAAM,aAAa,sBAAsB,MAAM,MAAM,UAAU,GAC5H,IAAI,iBAAiBA,UAAQ,MAAM,MAAM,CAAC;CAC9C;CACA,MAAM,WAAW,cAAc,KAAK,WAAW,KAAK;CACpD,IAAI,aAAa,KAAA,GAAW,IAAI,iBAAiBA,UAAQ,MAAM,SAAS,CAAC;CACzE,OAAO;AACT;;AAGA,MAAa,iBAA0C;CAAC;CAAgB;CAAW;CAAY;CAAyB;AAAa;;;;;;AAOrI,MAAa,aAAiI;CAC5I,gBAAgB;EAAE,SAAS;EAAuB,IAAI;CAAQ;CAC9D,SAAS;EAAE,SAAS;EAAiC,IAAI;CAAQ;CACjE,UAAU;EAAE,SAAS;EAAyB,IAAI;CAAQ;CAC1D,yBAAyB;EAAE,SAAS;EAA2B,IAAI;CAAM;AAC3E;;;;;;;AAQA,MAAa,mBAAmB,KAAU,MAAc,cAAwD;CAC9G,MAAM,MAAwC,CAAC;CAC/C,MAAM,MAAM,IAAI,OAAO,WAAW;CAClC,KAAK,MAAM,QAAQ,IAAI,OAAO,YAAY,CAAC,GAAG;EAC5C,IAAI,KAAK,OAAO,YAAY,KAAK,IAAI,MAAM;EAC3C,MAAM,SAAS,OAAO,KAAK,aAAa,EAAE;EAC1C,KAAK,MAAM,SAAS,OAAO,KAAK,UAAU,GAAqC;GAC7E,MAAM,OAAO,WAAW;GACxB,IAAI,IAAI,WAAW,KAAA,KAAc,KAAK,OAAO,WAAY,WAAW,QAAQ,KAAK,QAAQ,KAAK,OAAO,KAAK,UAAU,EAAE,CAAC,GAAG,IAAI,SAASA,UAAQ,MAAM,KAAK,CAAC;EAC7J;CACF;CACA,MAAM,WAAW,cAAc,KAAK,WAAW,MAAM;CACrD,IAAI,aAAa,KAAA,GAAW,IAAI,iBAAiBA,UAAQ,MAAM,SAAS,CAAC;CACzE,OAAO;AACT;;AAGA,MAAM,iBAAiB,KAAU,WAAmB,UAAkD;CACpG,MAAM,uBAAO,IAAI,IAAoB;CACrC,KAAK,MAAM,SAAS,IAAI,QAAQ,IAAI,MAAM,OAAO,QAAQ,KAAK,IAAI,OAAO,MAAM,IAAI,GAAG,MAAM,CAAC;CAC7F,MAAM,UAAU,IAAI,OAAO,WAAW;CACtC,OAAO,IAAI,OAAO,MAAM,UAAU;EAChC,IAAI,MAAM,OAAO,UAAU,KAAK,IAAI,OAAO,MAAM,IAAI,CAAC,KAAK,cAAc,WAAW,OAAO;EAC3F,MAAM,SAAS,SAAS,KAAK,MAAM,KAAK;EACxC,OAAO,WAAW,SAAS,UAAU,QAAQ,WAAW,UAAU;CACpE,CAAC;AACH;;AAGA,MAAa,YAAY,KAAU,OAAe,YAA4B;CAC5E,MAAM,EAAE,WAAW;CACnB,MAAM,OAAO,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM;CAEzD,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,MAAM,CAAC,EAAE,KAAK,KAAK,GAAG,EAAE,CAAC,EAAE,KAAK;CACjF,MAAM,uBAAO,IAAI,IAAwB;CACzC,KAAK,MAAM,SAAS,QAAQ,IAAI,MAAM,OAAO,OAAO,KAAK,IAAI,OAAO,MAAM,IAAI,GAAG,KAAK;CACtF,MAAM,QAAQ,IAAI,OAAO,SAAS;CAClC,MAAM,OAAO,UAAU,OAAO,OAAO,IAAI,IAAI,KAAK;CAClD,MAAM,MAAM,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,UAAU,MAAM,IAAI,SAAS,SAAS,KAAK,MAAM,KAAK,MAAM,OAAO,CAAC,CAAC;CAC5G,MAAM,OAAO,SAAS,OAAO,OAAO,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAErG,MAAM,UAAU,KACb,QAAQ,UAAU,MAAM,IAAI,QAAQ,CAAC,KAAK,IAAI,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC,CAClE,KAAK,UAAU;EACd,MAAM,IAAI,OAAO,MAAM,IAAI;EAC3B,OAAO;GAAE;GAAG,MAAM,SAAS,OAAO,OAAO,KAAK,IAAI,CAAC;EAAE;CACvD,CAAC;CAEH,MAAM,aAAa,UAAU,OAAO,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,QAAQ,IAAI,KAAK,OAAO,CAAC;CACpH,MAAM,WAAW,IAAI,OAAO;CAC5B,OAAO;EAAE,MAAM,KAAK;EAAQ,OAAO,KAAK;EAAM;EAAK;EAAM;EAAS;EAAY,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,OAAO,KAAK,KAAK,KAAK,GAAG,SAAS,IAAI,IAAI,QAAQ,CAAC,EAAE;CAAG;AAClL;;;;;AAMA,MAAM,UAAU,KAAU,OAAyB,SAA4B,QAAuC;CACpH,MAAM,OAAO,QAAQ,QAAQ,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC;CAC1D,MAAM,WAAW,QAAQ,QAAQ,SAAS,KAAK,SAAS,QAAQ,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;CACjF,OAAO;EACL,SAAS,QAAQ;EACjB;EACA;EACA,QAAQ,QAAQ,SAAS,OAAO;EAChC,SAAS,CAAC,GAAG,KAAK,CAAC,CAAC,QAAQ,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;EAC/C,UAAU,IAAI,OAAO,QAAQ,UAAU,MAAM,OAAO,YAAY,MAAM,gBAAgB,SAAS,CAAC,CAAC;CACnG;AACF;;AAGA,MAAa,YAAY,QAA+B,UAAmC;CACzF,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,MAAM,CAAC,EAAE,KAAK;CAC/D,MAAM,wBAAQ,IAAI,IAA8C;CAChE,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,MAAM,KAAK,SAAS,MAAM,KAAK,MAAM;EACzC,MAAM,OACJ,MAAM,OAAO,UACT,OAAO,MAAM,YAAY,MAAM,WAAW,OAAO,IACjD,MAAM,OAAO,SACX,OAAO,MAAM,WAAW,MAAM,IAC9B,MAAM,OAAO,mBACX,mBACA;EACV,IAAI,SAAS,MAAM;EACnB,MAAM,OAAO,MAAM,IAAI,IAAI;EAC3B,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM;GAAE,OAAO,MAAM;GAAG,OAAO;EAAE,CAAC;OAC/D,KAAK,SAAS;CACrB;CACA,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,cAAc;EAAE;EAAM,OAAOA,UAAQ,OAAO,KAAK;EAAG;CAAM,EAAE;AACrG;;;;;;AAOA,MAAa,UAAU,KAAU,WAAgD;CAC/E,MAAM,WAAW,IAAI,OAAO,YAAY,CAAC;CACzC,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,QAAQ,UAAU,IAAI,KAAK,OAAO,cAAc,OAAO,IAAI,OAAO,KAAK,QAAQ,GAAG,OAAO,KAAK,QAAQ,CAAC;CAClH,MAAM,MAAkB,CAAC;CACzB,KAAK,MAAM,QAAQ,UAAU;EAC3B,IAAI,KAAK,OAAO,YAAY;EAC5B,MAAM,WAAW,OAAO,KAAK,QAAQ;EACrC,MAAM,QAAQ,OAAO,IAAI,QAAQ;EACjC,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,QAAQ,OACX,QAAQ,WAAW,OAAO,OAAO,QAAQ,OAAO,QAAQ,YAAY,OAAO,QAAQ,SAAS,OAAO,QAAQ,KAAK,CAAC,CAAC,CAClH,GAAG,EAAE;EACR,IAAI,UAAU,KAAA,GAAW,IAAI,KAAKA,UAAQ,MAAM,MAAM,KAAK,CAAC,CAAC;CAC/D;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;AA6BA,MAAa,gBAAgB,MAAY,QAA2B;CAClE,MAAM,EAAE,QAAQ,WAAW;CAC3B,MAAM,EAAE,eAAe;CACvB,MAAM,WAAW,WAAW;CAC5B,MAAM,UAAU,IAAI,OAAO,WAAW;CACtC,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CACzD,MAAM,KAAK,IAAI,OAAO;CACtB,MAAM,QAAuB;EAC3B,MAAM;EACN,IAAI;EACJ,QAAQ,CAAC;EACT,QAAQ;GAAE,MAAM;GAAG,OAAO;GAAG,KAAK;GAAG,MAAM;GAAM,SAAS,CAAC;EAAE;EAC7D,QAAQ,CAAC;CACX;CACA,MAAM,SAAS;EAAE,SAAS,EAAE,MAAM,SAAS;EAAY,SAAS;EAAM,QAAQ;EAAM,SAAS;EAAM,SAAS;CAAK;CACjH,IAAI,UAAU,KAAA,GAAW,OAAO;EAAE,GAAG;EAAQ,MAAM;EAAiC,OAAO;CAAM;CACjG,IAAI,OAAO,KAAA,KAAa,IAAI,UAAU,MAAM,OAAO;EAAE,GAAG;EAAQ,MAAM;EAA6B,OAAO;CAAM;CAChH,IAAI,IAAI,SAAS,MACf,OAAO;EAAE,GAAG;EAAQ,MAAM;EAAiF,OAAO;CAAM;CAC1H,IAAI,IAAI,OAAO,GAAG,OAAO;EAAE,GAAG;EAAQ,MAAM,sBAAsB,IAAI,KAAK;EAAW,OAAO;CAAM;CACnG,MAAM,WAAW,IAAI,OAAO,YAAY,CAAC;CACzC,MAAM,OAAO,IAAI,QAAQ;CACzB,MAAM,QAAQ,UAAU,SAAS;CAGjC,MAAM,UAAU,KAAK,YAAY,KAAA;CAEjC,MAAM,QAAQ,KAAK,UAAU,KAAA;CAC7B,MAAM,UAAU,KAAK,eAAe,KAAA,KAAa,WAAW;CAC5D,MAAM,QAAQ,WAAW,YAAY,SAAS,WAAW,aAAa,KAAA;CACtE,MAAM,SAAS,QAAQ,CAAC,IAAI,UAAU,gBAAgB,KAAK,IAAI,IAAI,MAAM,EAAE,IAAI,UAAU,mBAAmB,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,SAAS,UAAU,EAAE;CAIjK,MAAM,QAAQ,UAAU,UAAU,SAAS,SAAS,CAAC,WAAW,SAAS,KAAK,KAAK;CACnF,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,SAAS,QAAQ,IAAI,MAAM,OAAO,QAAQ,OAAO,IAAI,OAAO,MAAM,IAAI,GAAG,MAAM,CAAC;CAC3F,MAAM,WAAW,OAAO,MAAM,UAAU;EACtC,IAAI,MAAM,OAAO,SAAS,MAAM,KAAK,OAAO,OAAO;EACnD,IAAI,YAAY,OAAO,IAAI,OAAO,MAAM,IAAI,CAAC,KAAK,cAAc,IAAI,MAAO,IAAI,OAAO;EACtF,MAAM,SAAS,SAAS,KAAK,MAAM,KAAK;EACxC,OAAO,WAAW,SAAS,UAAU,SAAS,CAAC,UAAU,WAAW,UAAU;CAChF,CAAC;CACD,MAAM,KAAK,aAAa,KAAA,IAAY,OAAO,SAAS,KAAK,SAAS,KAAK;CAEvE,IAAI,SAAS;EACX,OAAO,OAAO;EACd,IAAI,aAAa,KAAA,GAAW,OAAO,iBAAiBA,UAAQ,IAAI,SAAS,CAAC;CAC5E;CACA,MAAM,QAAuB;EAC3B,MAAM;EACN;EACA;EACA,QAAQ,SAAS,KAAK,IAAI,UAAU,KAAK,OAAO;EAChD,QAAQ,SAAS,QAAQ,EAAE;EAC3B,GAAI,KAAK,eAAe,cAAc,EAAE,MAAM,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC;EACvE,GAAI,KAAK,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,WAAW,KAAK,OAAO,KAAK,EAAE,EAAE;CAClF;CACA,IAAI,SAAwB;CAC5B,MAAM,OAAO,SAAS,MAAM,SAAS,KAAK,OAAO,cAAc,KAAK,UAAU,WAAW,KAAK,KAAK,EAAE;CACrG,IAAI,SAAS,KAAA,GAAW,SAAS,2BAA2BA,UAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM;CACtF,MAAM,QAAQ,SAAS,MAAM,SAAS,KAAK,OAAO,cAAc,KAAK,UAAU,iCAAiC,KAAK,KAAK,EAAE;CAC5H,MAAM,UAAU,SAAS,MAAM,SAAS,KAAK,OAAO,cAAc,KAAK,UAAU,qBAAqB,KAAK,KAAK,EAAE;CAClH,IAAI,WAAW,QAAQ,UAAU,KAAA,MAAc,YAAY,KAAA,KAAa,QAAQ,IAAI,MAAM,IACxF,SAAS;CAGX,MAAM,QAAQ,OAAO;CACrB,IAAI,WAAW,QAAQ,UAAU,KAAA,KAAa,OAAO,qBAAqB,KAAA,GACxE,SAAS;CAGX,IAAI,WAAW,QAAQ,KAAK,SAAS,KAAA,MAAc,WAAW,YAAY,QAAQ,QAAQ;EACxF,IAAI,SAAS,MAAM,SAAS;OACvB;GACH,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,QAAQ,KAAK,MAAM,GAAG;GAC1D,IAAI,OAAO,QAAQ,QAAQ,GAAG,GAC5B,SAAS,iBAAiB,KAAK,MAAM,OAAO,GAAG,IAAI,GAAG;EAC1D;CACF;CAGA,MAAM,eAAe,UACjB,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,CAAC,GAAG,SAAS,EAAE,IACrE,GAAG,IAAI,OAAO,QAAQ,QAAQ,EAAE,GAAG,IAAI,KAAK,SAAS,KAAK,cAAc,KAAK,MAAA,EAAQ;CACzF,MAAM,UAAU,WAAW,YAAY,OAAO,KAAA,IAAY,WAAW;CACrE,MAAM,QAAQ,OAAO,MAClB,WACC,OAAO,UAAU,IAAI,SACrB,OAAO,QAAQ,gBACf,OAAO,KAAK,SAAS,KAAA,CACzB;CACA,MAAM,MAAM,OAAO,KAAK,SAAS,KAAA,IAAY,OAAO,QAAQ,MAAM,IAAI,MAAM,IAAI,IAAI;CACpF,IAAI,WAAW,QAAQ,YAAY,KAAA,KAAa,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,MAAM,IAAI,GAC9F,SAAS,iDAAiD,IAAI,iBAAiB,QAAQ,QAAQ,MAAM,IAAI,EAAE;CAC7G,IAAI,WAAW,QAAQ,WAAW,YAAY,QAAQ,WAAW,SAAS,YAAY,IAAI,MAAM,KAAK,IAAI,MAAM,MAAM,MAAM,QAAQ,QAAQ,IAAI,GAC7I,SAAS,gCAAgC,KAAK,OAAO,IAAI,MAAM,KAAK,IAAI,MAAM,MAAM,GAAG,IAAI,GAAG;CAGhG,IAAI,YAAY;CAChB,IAAI,WAAW,YAAY,SAAS,WAAW,aAAa,KAAA,GAAW;EACrE,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,MAAM,IAAI,IAAI,MAAO,EAAE;EAClF,IAAI,SAAS,KAAA,KAAc,SAAS,QAAQ,KAAK,IAAI,KAAK,IACxD,WAAW;OACN;GACL,YAAY,KAAK;GAEjB,MAAM,EAAE,MAAM,WAAW,WAAW;GACpC,IAAI,SAAS,MAAM,WAAW;QACzB,IACH,QAAQA,UAAQ,WAAW,KAAK,EAAE,GAAG,GAAG,KAAK,QAAQ,OAAO,KAAK,GAAG,KACpE,QAAQA,UAAQ,WAAW,KAAK,EAAE,GAAG,GAAG,KAAK,QAAQ,OAAO,MAAM,GAAG,GAErE,WAAW,mBAAmBA,UAAQ,WAAW,KAAK,EAAE,CAAC,CAAC,MAAM,GAAGA,UAAQ,WAAW,KAAK,EAAE,CAAC,CAAC,MAAM,kCAAkC,OAAO,IAAI,MAAM,GAAG,OAAO,KAAK,MAAM;EACjL;CACF;CAGA,MAAM,WAAqB,CAAC;CAE5B,MAAM,WAAW,UAAU,OAAO,aAAa,OAAO;CACtD,IAAI,UAAU,aAAa,SAAS,aAAa,KAAA,GAC/C,SAAS,KAAK,yBAAyB,SAAS,MAAM,wCAAwC;CAEhG,MAAM,cAAc,IAAI,OAAO,SAAS;CACxC,IAAI,SAAS,aAAa,KAAA,KAAa,gBAAgB,QAAQ,SAAS,cAAc,gBAAgB,UACpG,SAAS,KAAK,SAAS,WAAW,wBAAwB,QAAQ,4BAA4B,uBAAuB,YAAY,4BAA4B,SAAS;CACxK,KAAK,MAAM,SAAS,UAAU,SAAS,CAAC,GAAG;EACzC,MAAM,KAAK,OAAO;EAClB,IAAI,OAAO,KAAA,GAAW,SAAS,KAAK,GAAG,MAAM,QAAQ,GAAG,MAAM,wCAAwC;CACxG;CACA,IAAI,aAAa,KAAA,KAAa,UAAU,UAAU,CAAC,WAAW,CAAC,SAAS,OAAO,SAC7E,SAAS,KAAK,uBAAuB,MAAM,OAAO,SAAS,KAAK,EAAE,4BAA4B,SAAS;CACzG,KAAK,MAAM,SAAS,UAAU,UAAU,CAAC,GAAG;EAC1C,MAAM,MAAM,MAAM,OAAO,MAAM,SAAS,KAAK,SAAS,MAAM,IAAI;EAChE,MAAM,QAAQ,QAAQ,QAAQ,IAAI,GAAG,GAAG;EACxC,IAAI,QAAQ,KAAA,GAAW,SAAS,KAAK,wBAAwB,MAAM,MAAM;OACpE,IAAI,IAAI,MAAM,QAAQ,QAAQ,MAAM,KAAK,GAAG,IAAI,SAAS,IAAI,MAAM,QAAQ,QAAQ,MAAM,MAAM,GAAG,IAAI,OACzG,SAAS,KAAK,kBAAkB,MAAM,KAAK,GAAG,IAAI,MAAM,MAAM,+BAA+B,QAAQ,MAAM,KAAK,GAAG,EAAE,IAAI,QAAQ,MAAM,MAAM,GAAG,EAAE,IAAI;CAC1J;CACA,IAAI,UAAU,SAAS,KAAA,GAAW;EAChC,MAAM,EAAE,KAAK,SAAS,SAAS;EAC/B,MAAM,OAAO,MAAM,OAAO;EAC1B,IAAI,SAAS,MAAM,SAAS,KAAK,4EAA4E;OACxG,IAAI,KAAK,SAAS,OAAO,KAAK,SAAS,MAAM,SAAS,KAAK,kBAAkB,KAAK,OAAO,6BAA6B,IAAI,IAAI,KAAK,EAAE;CAC5I;CACA,IAAI,UAAU,eAAe,KAAA,GAAW;EACtC,MAAM,EAAE,KAAK,SAAS,SAAS;EAC/B,MAAM,SAAS,MAAM,OAAO,cAAc;EAC1C,IAAI,WAAW,MAAM,SAAS,KAAK,6EAA6E;OAE3G,IAAI,IAAI,OAAO,OAAO,WAAW,GAAG,SAAS,KAAK,2EAA2E;OAC7H,IAAI,OAAO,SAAS,OAAO,OAAO,SAAS,MAAM,SAAS,KAAK,mBAAmB,OAAO,OAAO,0BAA0B,IAAI,IAAI,KAAK,EAAE;CAChJ;CACA,MAAM,EAAE,SAAS,MAAM;CACvB,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,UAAU,YAAY,CAAC,CAAC,GAAG;EACnE,MAAM,QAAQ,OAAO;EACrB,IAAI,UAAU,KAAA,GAAW,SAAS,KAAK,2BAA2B,MAAM;OACnE,IAAI,QAAQ,KAAK,OAAO,QAAQ,KAAK,MAAM,SAAS,KAAK,gBAAgB,KAAK,MAAM,MAAM,aAAa,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;CACvI;CACA,IAAI,MAAM,aAAa,KAAA,GAAW,SAAS,KAAK,GAAG,iBAAiB,MAAM,UAAU,MAAM,MAAM,CAAC;CACjG,IAAI,aAAa,KAAA,GAAW;EAC1B,IAAI,WAAW,YAAY,QAAQ,OACjC,SAAS,KAAK,UAAU,QAAQ,0DAA0D,4CAA4C;EACxI,OAAO;GAAE,GAAG;GAAQ,MAAM;GAAQ,SAAS,SAAS,MAAM;GAAM;EAAM;CACxE;CAIA,MAAM,UAAU,OAAO,SAAS,KAAK;CACrC,MAAM,SAAS,IAAI,IAAI,UAAU,MAAM,CAAC,CAAC,QAAQ,WAAW,OAAO,SAAS,MAAM,CAAC,CAAC,KAAK,WAAW,OAAO,KAAK,CAAC;CACjH,MAAM,UAAU,OACb,QACE,WACC,OAAO,UAAU,IAAI,SACrB,OAAO,OAAO,QACd,OAAO,QAAQ,WACf,CAAC,OAAO,IAAI,OAAO,OAAO,GAAG,CAAC,MAC7B,OAAO,KAAK,IAAI,SAAS,KAAK,KAC/B,OAAO,QAAQ,SAAS,KACxB,OAAO,OAAO,KAClB,CAAC,CACA,GAAG,EAAE;CACR,MAAM,KAAK,SAAS,QAAQ,SAAS;CACrC,OAAO;EACL,SAAS,EAAE,MAAM,WAAW;EAC5B,SAASA,UAAQ,WAAW,EAAE;EAC9B,QAAQA,UAAQ,WAAW,SAAS,CAAC;EACrC,SAAS,YAAY,KAAA,IAAY,OAAOA,UAAQ,QAAQ,MAAM,SAAS,CAAC;EACxE,MAAM;EACN,SAAS,SAAS,MAAM;EACxB;CACF;AACF;;;;ACnWA,MAAM,QAA0C;CAC9C,IAAI;CACJ,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;AACP;;AAGA,MAAM,WAAW,MAAc,OAC7B,SAAS,KAAK,OAAO,KAAK,QAAQ,GAAG,IAAI,KAAK,GAAG;;AAGnD,MAAM,YAAY,WAA8C,OAAqC;AACrG,MAAM,YAAY,WAA8C,OAAqC;AAErG,MAAM,SAAS,OAA+B,UAC5C,UAAU,KAAA,IAAY,IAAI,OAAO,MAAM,UAAU,CAAC;;AAGpD,MAAM,iBACJ,MACA,QACA,OACA,YACoB;CACpB,MAAM,EAAE,SAAS,KAAK,WAAW,YAAY,OAAO,KAAK,aAAa,EAAE,MAAM,KAAA,EAAU;CACxF,IAAI,SAAS,KAAA,KAAa,SAAS,iBAAiB,SAAS,WAAW,SAAS,eAAe,SAAS,gBAAgB,SAAS,eAAe,SAAS,cAAc,OAAO;CAC/K,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,MAAM,OAAO,KAAK;CAC/E,MAAM,YACJ,SAAS,kBACL,QACA,SAAS,iBACP,UACA,OAAO,MACJ,UACC,MAAM,OAAO,YAAY,MAAM,KAAK,QAAQ,KAAK,MAAM,OAAO,aAAa,IAAI,CACnF;CACR,OAAO,UAAU,KAAA,KAAa,cAAc,KAAA,IAAY,OAAO,QAAQ,UAAU,GAAG,MAAM,CAAC;AAC7F;AAQA,MAAM,QAAQ,YAA4B,QAAQ,MAAM,GAAG,CAAC,CAAC;;;;;;AAO7D,MAAM,UACJ,KACA,OACA,SAC4B;CAC5B,MAAM,SAAS,IAAI,OAAO,MACvB,SACC,KAAK,UAAU,SACf,KAAK,OAAO,WACZ,SAAS,IAAI,MAAM,KACnB,KAAK,QAAQ,KAAA,KACb,KAAK,KAAK,GAAG,CACjB;CACA,OAAO,QAAQ,WAAW,KAAA,IAAY,KAAA,IAAY;EAAE;EAAO,QAAQ,OAAO;CAAO;AACnF;;;;;;;AAQA,MAAM,WAAW,KAAU,OAAe,WAA4C;CACpF,MAAM,UAAU,IAAI,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC;CAClE,IAAI,YAAY,KAAA,GAAW,OAAO,KAAA;CAClC,MAAM,SAAS,IAAI,OAAO,MACvB,SAAS,KAAK,UAAU,SAAS,KAAK,OAAO,QAAQ,KAAK,QAAQ,WAAW,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK,KAAK,QAAQ,QAAQ,CACtI;CACA,OAAO,QAAQ,WAAW,KAAA,IAAY,KAAA,IAAY;EAAE;EAAO,QAAQ,OAAO;CAAO;AACnF;;AAGA,MAAM,gBAAgB,KAAU,UAA4C;CAC1E,IAAI,IAAI,aAAa,KAAA,GAAW;EAC9B,MAAM,SAAS,IAAI,OAAO,MACvB,WAAW,OAAO,UAAU,IAAI,eAAe,OAAO,QAAQ,KACjE,CAAC,EAAE;EACH,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY;GAAE,OAAO,IAAI;GAAa;EAAO;CAC7E;CACA,MAAM,OAAO,IAAI,SAAS;CAC1B,OAAO,OAAO,KAAK,IAAI,cAAc,QAAQ,KAAK,GAAG,MAAM,IAAI;AACjE;;;;;;;;AASA,MAAa,YAAY,MAAY,QAAsC;CACzE,MAAM,QAAQ,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,CAAC,GAAG;CACrE,MAAM,WAAW,KAAK,YAAY;CAClC,IAAI,aAAa,UAAU;EACzB,MAAM,SAAS,IAAI,OAAO,MAAM,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC,EAAE;EAChG,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY;GAAE,OAAO,IAAI;GAAO;EAAO;CACvE;CACA,IAAI,aAAa,UAAU,OAAO,aAAa,KAAK,KAAK;CACzD,MAAM,MAAM,IAAI,UAAU,KAAK,SAAS;CACxC,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;CAC9B,OAAO,SAAS,WAAW,WACvB,OAAO,KAAK,IAAI,QAAQ,QAAQ,KAAK,GAAG,MAAM,IAAI,MAAM,IACvD,QAAQ,KAAK,IAAI,OAAO,IAAI,MAAM,KAAK,OAAO,KAAK,IAAI,QAAQ,QAAQ,QAAQ,IAAI,MAAM;AAChG;;;;;;AAOA,MAAM,UAAU,MAAY,QAAsC;CAChE,MAAM,QAAQ,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,CAAC,GAAG;CACrE,MAAM,SAAS,KAAK,aAAa;CACjC,IAAI,IAAI,aAAa,KAAA,GAAW,OAAO,SAAS,KAAA,IAAY,aAAa,KAAK,KAAK;CACnF,MAAM,QAAQ,SAAS,IAAI,QAAQ,IAAI;CACvC,MAAM,SAAS,IAAI,OAAO,MACvB,WAAW,OAAO,UAAU,UAAU,SAAS,OAAO,MAAM,OAAO,SAAS,KAC/E,CAAC,EAAE;CACH,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY;EAAE;EAAO;CAAO;AAC5D;;AAGA,MAAM,WAAW,GAAW,OAAyB,IAAI,IAAK,KAAK;;AAGnE,MAAM,QAAQ,SAAkC,UAC9C,QAAQ,QAAuB,KAAK,WAAW;CAC7C,MAAM,QAAQ,MAAM,MAAM;CAC1B,OAAO,UAAU,KAAA,IAAY,MAAM,KAAK,IAAI,OAAO,GAAG,KAAK;AAC7D,GAAG,IAAI;;AAGT,MAAa,gBACX,UACA,WACe;CACf,MAAM,WAAW,SAAS,QACvB,WAAW,OAAO,OAAO,SAAS,OAAO,KAAK,IAAI,SAAS,KAAK,KAAK,OAAO,KAAK,YAAY,KAAA,CAChG;CAKA,OAAO;EACL,YALiB,SAAS,QAAQ,WAAW,QAAQ,OAAO,IAAK,KAAK,OAAO,IAAK,OAAQ,CAAC,CAAC,CAAC;EAM7F,YALiB,SAAS,QACzB,WAAW,CAAC,QAAQ,OAAO,IAAK,MAAM,OAAO,IAAK,IAAI,OAAO,OAAO,IAAK,OAAQ,CACpF,CAAC,CAAC;EAIA,KAAK,KAAK,WAAW,WAAW,OAAO,KAAK,WAAW;EACvD,QAAQ,KAAK,SAAS,WAAW,OAAO,KAAK,MAAM;EACnD,MAAM,KAAK,SAAS,WAAW,OAAO,KAAK,IAAI;EAC/C,QAAQ,KAAK,SAAS,WAAW,OAAO,KAAK,UAAU;EACvD,MAAM,OAAO,QAAQ,WAAW,OAAO,OAAO,aAAa,OAAO,QAAQ,MAAM,CAAC,CAAC;EAClF,QAAQ,KAAK,SAAS,WAAW,OAAO,KAAK,UAAU;EACvD,MAAM,KAAK,SAAS,WAAW,OAAO,KAAK,UAAU;CACvD;AACF;;;;;;;;AASA,MAAa,eACX,KACA,KACA,UACA,aACc;CACd,MAAM,KAAiB,CAAC;CACxB,MAAM,OAAmB,CAAC;CAC1B,IAAI,aAAa,KAAA,KAAa,aAAa,KAAA,GAAW,OAAO;EAAE;EAAK;EAAI;CAAK;CAC7E,MAAM,MAAM,UACV,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,MAAM,SAAS,OAAO,WAAW,MAAM,MAAM;CAC9F,MAAM,OAAO,GAAG,QAAQ;CACxB,MAAM,MAAM,GAAG,QAAQ;CACvB,MAAM,WAAW,SAAkC,MAAc,OAC/D,QAAQ,MAAM,WAAW,OAAO,OAAO,SAAS,OAAO,KAAK,IAAI,SAAS,KAAK,KAAK,OAAO,OAAO,QAAQ,OAAO,OAAO,EAAE;CAC3H,MAAM,SAAS,SAAkC,MAAc,OAC7D,QAAQ,MAAM,WAAW,OAAO,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,OAAO,EAAE;CACxF,MAAM,QAAQ,IAAI,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC;CACvE,MAAM,SAAS,MAAM,MAAM;EACzB,MAAM,OAAO,MAAM,IAAI,EAAE,EAAE,KAAK;EAChC,MAAM,UAAU,QAAQ,MAAM,KAAK,GAAG,IAAI;EAC1C,MAAM,UAAU,YAAY,KAAA,IAAY,KAAA,IAAY,MAAM,KAAK,QAAQ,MAAM,IAAI;EACjF,IAAI,YAAY,KAAA,KAAa,YAAY,KAAA,GAAW;EACpD,GAAG,KAAK,QAAQ,QAAQ,MAAM,QAAQ,IAAI,CAAC;EAC3C,MAAM,QAAQ,QAAQ,KAAK,QAAQ,MAAM,IAAI;EAC7C,MAAM,WAAW,UAAU,KAAA,IAAY,KAAA,IAAY,MAAM,MAAM,MAAM,MAAM,IAAI;EAC/E,IAAI,UAAU,KAAA,KAAa,aAAa,KAAA,GAAW,KAAK,KAAK,QAAQ,MAAM,MAAM,SAAS,IAAI,CAAC;CACjG,CAAC;CACD,OAAO;EAAE;EAAK;EAAI;CAAK;AACzB;;;;;;;;;;;;AAaA,MAAa,WAAW,MAAY,QAAuB;CACzD,MAAM,aAAa,cAAc,MAAM,GAAG;CAE1C,MAAM,OAAiB,IAAI,WAAW,KAAA,IAAY,aAAa;EAAE,GAAG;EAAY,SAAS,UAAU,MAAM,GAAG;CAAE;CAC9G,MAAM,WAAW,KAAK,WAAW;CACjC,IAAI,KAAK,MAAM,SAAS,KAAA,KAAa,aAAa,KAAA,GAAW,OAAO;CACpE,MAAM,UAAU,UAAU,IAAI,MAAM;CACpC,IAAI,aAAa,KAAA,KAAa,KAAK,SAAS,MAAM,OAAO;EAAE,GAAG;EAAM;CAAQ;CAC5E,MAAM,UAAU,eAAe,UAAU,OAAO;CAChD,MAAM,UAAU,KAAK,YAAY,OAAO,UAAU,YAAY,OAAO,KAAK,UAAU,GAAG,KAAK,QAAQ,IAAI;CACxG,OAAO;EAAE,GAAG;EAAM;EAAS;CAAQ;AACrC;;;;;;AAOA,MAAa,YAAY,MAAY,QAAqB;CACxD,MAAM,QAAQ,aAAa,MAAM,GAAG;CACpC,MAAM,QAAQ,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CAC7D,MAAM,QAAQ,MAAM,WAAW,KAAK,UAAU,KAAA,IAAY,KAAA,IAAY,SAAS,MAAM,GAAG;CACxF,IAAI,UAAU,KAAA,KAAa,UAAU,KAAA,GAAW,OAAO;EAAE,MAAM;EAAG,OAAO;CAAK;CAC9E,MAAM,SAAS,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,MAAM,SAAS,OAAO,WAAW,MAAM,MAAM;CAC3G,MAAM,QAAQ,IAAI,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,CAAC,GAAG;CAErE,MAAM,QAAQ,KAAK,aAAa,WAAY,OAAO,MAAM,WAAW,OAAO,QAAQ,KAAA,CAAS,CAAC,EAAE,OAAO,QAAS;CAC/G,OAAO,cAAc,OAAO,QAAQ,OAAO,IAAI,OAAO,MAAM,MAAM,CAAC;AACrE;;AAGA,MAAM,kBAAkB,UAAsD,SAA+C;CAC3H,IAAI,SAAS,MAAM,OAAO,4DAA4D,aAAa,QAAQ;CAM3G,OAJE,KAAK,eAAe,SAAS,cAC7B,KAAK,YAAY,SAAS,WAC1B,KAAK,UAAU,SAAS,SACxB,KAAK,aAAa,SAAS,YAAY,QAC3B,OAAO,2BAA2B,aAAa,IAAI,EAAE,QAAQ,aAAa,QAAQ;AAClG;;;;;;;;;AAUA,MAAa,aAAa,WAAyD;CACjF,MAAM,MAAM,UAAsB,OAAO,MAAM,IAAI,MAAM;CACzD,MAAM,QAAQ,OAAO,QAAQ,WAAW,MAAM,OAAO,aAAa,MAAM,OAAO,YAAY,GAAG,KAAK,CAAC;CACpG,MAAM,QAAQ,MAAM;CACpB,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,MAAM,SAAS,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,GAAG,KAAK,CAAC;CACvE,MAAM,UAAU,OAAO,MAAM,UAAU,MAAM,OAAO,aAAa,GAAG,KAAK,CAAC;CAC1E,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CACzD,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,GAAG,KAAK,CAAC;CACpE,MAAM,MAAM,UAAU,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,GAAG,KAAK,CAAC;CAC7E,MAAM,SAAS,OAAO,MACnB,UAAU,MAAM,OAAO,gBAAgB,MAAM,IAAI,MAAM,MAAM,QAAQ,KAAA,KAAa,MAAM,KAAK,IAAI,EACpG;CACA,OAAO;EACL,YAAY,MAAM,cAAc,OAAO,WAAW;EAClD,SAAS,UAAU,MAAM,MAAM,SAAS,KAAK,OAAO,OAAO;EAC3D,OAAO,WAAW,KAAA,IAAY,OAAO,OAAO,OAAO,QAAQ;EAC3D,SAAS,WAAW,KAAA,KAAa,CAAC;EAClC,KAAK,UAAU,KAAA,KAAa,SAAS,KAAA,IAAY,OAAO,QAAQ,MAAM,GAAG,KAAK,CAAC;CACjF;AACF;;AAGA,MAAM,iBAAiB,MAAY,QAAuB;CACxD,IAAI,IAAI,YAAY,KAAA,GAClB,OAAO;EACL,aAAa,IAAI;EACjB,OAAO,IAAI;EACX,SAAS,EAAE,MAAM,WAAW;EAC5B,SAAS;EACT,QAAQ;EACR,SAAS;EACT,OAAO,CAAC;EACR,QAAQ;EACR,iBAAiB;EACjB,MAAM;EACN,MAAM,wCAAwC,IAAI;EAClD,SAAS;CACX;CACF,IAAI,KAAK,WAAW,YAAY,QAAQ,KAAK,WAAW,UAAU,KAAA,GAAW,OAAO,aAAa,KAAK,KAAK,WAAW,KAAK;CAC3H,IAAI,KAAK,UAAU,KAAA,KAAa,KAAK,eAAe,KAAA,KAAa,KAAK,YAAY,KAAA,KAAa,KAAK,SAAS,KAAA,KAAa,KAAK,UAAU,KAAA,GAAW;EAClJ,MAAM,OAAO,aAAa,MAAM,GAAG;EACnC,OAAO;GACL,aAAa,IAAI;GACjB,OAAO,IAAI;GACX,SAAS,KAAK;GACd,SAAS,KAAK;GACd,QAAQ,KAAK;GACb,SAAS,KAAK;GACd,OAAO,CAAC;GACR,QAAQ;GACR,iBAAiB,IAAI,OAAO,QAAQ,WAAW,OAAO,UAAU,IAAI,SAAS,OAAO,OAAO,SAAS,CAAC,CAAC;GACtG,MAAM,KAAK,MAAM,OAAO;GACxB,MAAM,KAAK;GACX,SAAS,KAAK;GACd,OAAO,KAAK;EACd;CACF;CACA,IAAI,KAAK,WAAW,YAAY,QAAQ,KAAK,WAAW,UAAU,KAAA,GAChE,OAAO,aAAa,KAAK,KAAK,WAAW,KAAK;CAChD,IAAI,KAAK,WAAW,YAAY,QAAQ,KAAK,WAAW,UAAU,KAAA,GAChE,OAAO,aAAa,KAAK,KAAK,WAAW,KAAK;CAChD,IAAI,KAAK,WAAW,YAAY,QAAQ,KAAK,WAAW,cAAc,KAAA,GACpE,OAAO,iBAAiB,KAAK,KAAK,WAAW,SAAS;CAExD,IAAI,KAAK,WAAW,YAAY,QAAQ,KAAK,WAAW,WAAW,KAAA,GAAW,OAAO,cAAc,MAAM,GAAG;CAC5G,MAAM,EAAE,QAAQ,WAAW;CAC3B,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,OAAO;CACzD,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,CAAC,GAAG;CAEjE,MAAM,WAAW,KAAK,MAAM,SAAS,UAAU,KAAK,MAAM,SAAS;CACnE,MAAM,UAAU,WAAW,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC,KAAK;CAC9E,MAAM,SAAS,KAAK,aAAa;CACjC,MAAM,QAAQ,SAAS,MAAM,GAAG;CAChC,MAAM,QAAQ,OAAO;CACrB,MAAM,SAAS,OAAO;CACtB,MAAM,SAAS,OAAO,QAAQ,WAAW,OAAO,UAAU,SAAS,OAAO,WAAW,MAAM;CAE3F,MAAM,YAAY,OAAO,MAAM,GAAG;CAClC,MAAM,YAAY,WAAW;CAC7B,MAAM,aAAa,WAAW;CAE9B,MAAM,QAAQ,YAAY,KAAA,IAAY,CAAC,IAAI,OAAO,QAAQ,UAAU,MAAM,OAAO,UAAU,MAAM,IAAI,QAAQ,CAAC;CAC9G,MAAM,QAAQ,MAAM,QAAQ,KAAK,UAAU,MAAM,OAAO,MAAM,QAAQ,CAAC,GAAG,CAAC;CAE3E,MAAM,aAAa,IAAI,aAAa,CAAC,EAAA,CAAG,MACrC,SACC,KAAK,OAAO,QACZ,KAAK,YAAY,aACjB,OAAO,KAAK,YAAY,YACvB,KAAK,OAAO,CAAY,WAAW,GAAG,OAAO,KAAK,EAAE,EAAE,CAC3D;CACA,MAAM,aAAa,OAAO,QACvB,WAAW,OAAO,OAAO,WAAW,OAAO,SAAS,WACvD;CACA,MAAM,gBAAgB,OAAO,QAAQ,WAAW,OAAO,OAAO,SAAS;;;;;;;;;;CAUvE,MAAM,WAAW,MAAc,IAAY,UAAqD;EAC9F,MAAM,UAAU,OAAO,QACpB,WACC,OAAO,OAAO,WAAW,OAAO,SAAS,SAAS,OAAO,QAAQ,QAAQ,OAAO,QAAQ,EAC5F;EACA,MAAM,OAAO,QAAQ,MAAM,WAAW,WAAW,OAAO,QAAQ,SAAS,GAAG,IAAI,IAAI,QAAQ,IAAI,CAAC,CAAC;EAClG,IAAI,SAAS,KAAA,GACX,OAAO,OAAO,MAAM,aAAa,KAAK,OAAQ,MAAM;EAKtD,OADa,QAAQ,MAAM,WAAW,UAAU,eAAe,OAAO,UAAU,IACtE,MAAM,KAAA,IACZ,OACA;CACN;CACA,MAAM,OACJ,YAAY,KAAA,IACR,IACA,OAAO,QAAQ,WAAW,OAAO,OAAO,QAAQ,OAAO,OAAO,QAAQ,CAAC,CAAC,CAAC;CAE/E,MAAM,OAAO,OAAO,MAAM,WAAW,OAAO,KAAK,SAAS,KAAA,CAAS,CAAC,EAAE,KAAK;CAC3E,MAAM,MAAM,SAAS,KAAA,IAAY,OAAO,SAAS,QAAQ,MAAM,IAAI,IAAI,KAAM,IAAI;CACjF,MAAM,OAAO;EACX,aAAa,IAAI;EACjB,OAAO,IAAI;EACX,QAAQ,WAAW;EACnB,iBAAiB,cAAc;EAC/B;EACA;CACF;CACA,MAAM,UAAU;EACd,SAAS,EAAE,MAAM,SAAS;EAC1B,SAAS;EACT,QAAQ;EACR,SAAS;EACT,OAAO,CAAC;EACR,SAAS;CACX;CAEA,IAAI,UAAU,KAAA,GAAW,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,MAAM;CAAiC;CAC9F,IAAI,YAAY,KAAA,GACd,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,MAAM;CAA4C;CAClF,IAAI,IAAI,SAAS,MACf,OAAO;EACL,GAAG;EACH,GAAG;EACH,MAAM;CACR;CACF,IAAI,IAAI,OAAO,GAAG,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,MAAM,sBAAsB,IAAI,KAAK;CAAU;CAC/F,IAAI,WAAW,KAAA,GACb,OAAO;EAAE,GAAG;EAAM,GAAG;EAAS,MAAM;CAA4C;CAClF,IAAI,SAAwB;CAC5B,IAAI,IAAI,UAAU,MAAM;EAKtB,MAAM,aAAc,UAAU,YAAY,KAAK,UAAU,mBAAoB,aAAa,IAAI;EAC9F,MAAM,UAAU,OAAO,MACpB,UAAU,MAAM,OAAO,UAAU,MAAM,IAAI,QAAQ,KAAK,MAAM,IAAI,IAAI,MAAO,EAChF;EACA,IAAI,YAAY,CAAC,cAAc,IAAI,MAAM,KAAK,QAAQ,GACpD,SAAS;OACN,IAAI,cAAc,IAAI,MAAM,KAAK,QAAQ,GAC5C,SAAS;OACN,IAAI,cAAc,SACrB,SAAS;OACN,IAAI,WAAW,OAAO,KAAA,KAAa,WAAW,EAAE,CAAC,OAAO,IAAI,MAAM,IACrE,SAAS;CACb;CAEA,MAAM,UAAU,KAAK,WAAW,YAAY,OAAO,KAAA,IAAY,KAAK,WAAW;CAC/E,IAAI,WAAW,QAAQ,YAAY,KAAA,KAAa,QAAQ,QAAQ,QAAQ,KAAK,IAAI,IAAI,QAAQ,QAAQ,MAAM,IAAI,GAC7G,SAAS,iDAAiD,IAAI,MAAM,iBAAiB,QAAQ,QAAQ,MAAM,IAAI,EAAE;CAInH,MAAM,SAAS,KAAK,aAAa,KAAA,KAAa,KAAK,aAAa;CAGhE,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,MAAM,CAAC,EAAE,KAAK,OAAO;CACtE,MAAM,UAAU,OAAO,MAAM,WAAW,OAAO,OAAO,YAAY,OAAO,OAAO,OAAO,KAAK,OAAO,OAAO,IAAI;CAC9G,MAAM,OAAO,SACT,KAAA,IACA,OAAO,MAAM,WAAW,MAAM,OAAO,WAAW,MAAM,OAAO,UAAU,MAAM,IAAI,IAAI;CAGzF,MAAM,YAAY,OAAO,MAAM,WAAW,OAAO,OAAO,WAAW,SAAS,MAAM,MAAM,KAAK,OAAO,OAAO,IAAI;CAG/G,MAAM,MACH,KAAK,WAAW,YAAY,QAAQ,KAAK,WAAW,UAAU,YAC9D,KAAK,WAAW,YAAY,QAAQ,KAAK,WAAW,SAAS,cAC1D,OAAO,MAAM,WAAW,OAAO,OAAO,WAAW,SAAS,MAAM,MAAM,KAAK,SAAS,MAAM,MAAM,KAAK,OAAO,OAAO,IAAI,IACvH,KAAA;CAGN,MAAM,WAAW,YAAY,KAAA,KAAa,QAAQ,KAAA,KAAa,IAAI,OAAO,QAAQ,OAAO,KAAA,IAAY;CAGrG,MAAM,QAAQ,aAAa,MAAM,GAAG;CAGpC,MAAM,QAAQ,SAAU,OAAO,MAAM,WAAW,OAAO,QAAQ,KAAA,CAAS,CAAC,EAAE,OAAO,QAAS;CAC3F,MAAM,cAAc,UAAU,QAAQ,WAAW,QAAQ,KAAK,QAAQ,MAAM;CAE5E,MAAM,SAAS,UAAU,MAAM,GAAG,CAAC,CAAC;CACpC,MAAM,QAAQ,OAAO,OAAO,QAAQ,OAAO,MAAM;CACjD,MAAM,OAAO,UAAU,KAAA,MAAc,gBAAgB,KAAA,KAAa,MAAM,MAAM,eAAe,QAAQ,KAAA;CACrG,MAAM,UAAU,SAAS,KAAA;CACzB,MAAM,UAAmB,UACrB,EAAE,MAAM,UAAU,IAClB,aAAa,KAAA,IACX;EAAE,MAAM;EAAS,OAAO,MAAM,SAAS,QAAS,IAAI,SAAS;CAAM,IACnE,cAAc,KAAA,KAAa,MAAM,OAAO,QACtC,EAAE,MAAM,MAAM,IACd,QAAQ,KAAA,IACN,EAAE,MAAM,SAAS,IACjB,SAAS,KAAA,IACP;EAAE,MAAM;EAAS,OAAO,OAAO,KAAK,QAAQ;CAAE,IAC9C,EAAE,MAAM,SAAS;CAC7B,MAAM,QAAQ,MAAM,MAAM;CAC1B,MAAM,UACJ,aAAa,KAAA,KAAa,SAAS,KAAA,KAAa,CAAC,UAAU,QAAQ,SAAS,MAAM,KAAK,CAAC,IAAI;CAC9F,MAAM,EAAE,eAAe;CAEvB,MAAM,QAAQ,QAAQ,OAAO,QAAQ,OAAO,MAAM;CAOlD,MAAM,SAAS,IAAI,OAAO,MAAM,MAAM;CACtC,MAAM,eAAe,SAAwC;EAC3D,IAAI,SAAS,gBAAgB,OAAO,QAAQ;EAC5C,IAAI,SAAS,SAAS,OAAO,IAAI,OAAO;EACxC,IAAI,SAAS,gBAAgB,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,YAAY,KAAK,OAAO,GAAA,EAAK;EACtG,IAAI,SAAS,aAAa,OAAO,gBAAgB,OAAO,QAAQ,KAAK,CAAC,EAAE;EACxE,MAAM,SACJ,SAAS,kBACL,OAAO,QAAQ,SAAS,KAAK,OAAO,QAAQ,KAAK,QAAQ,MAAM,CAAC,CAAC,GAAG,EAAE,IACtE,SAAS,cAEP,OAAO,QAAQ,SAAS,KAAK,OAAO,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK,KAAK,SAAS,SAAS,OAAO,CAAC,CAAC,GAAG,EAAE,IACrH,SAAS,eAEP,OAAO,QAAQ,SAAS,KAAK,OAAO,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK,KAAK,QAAQ,SAAS,SAAS,CAAC,CAAC,GAAG,EAAE,IACtH,SAAS,yBACP,cAAc,MAAM,SAAS,KAAK,QAAQ,SAAS,KAAK,OAAO,MAAM,IACrE,SAAS,eACP,OAAO,MAAM,SAAS,KAAK,OAAO,QAAQ,KAAK,OAAO,WAAW,KAAK,KAAK,IAAI,SAAS,KAAK,CAAC,IAC9F,SAAS,aACP,OAAO,MAAM,SAAS,KAAK,OAAO,WAAW,SAAS,IAAI,MAAM,CAAC,IACjE,SAAS,gBACP,OAAO,MACJ,SACC,KAAK,UAAU,aACf,KAAK,WAAW,cAChB,KAAK,OAAO,WACZ,SAAS,IAAI,MAAM,CACvB,IAEA,KAAA;EAGd,IAAI,WAAW,KAAA,KAAa,SAAS,iBAAiB,eAAe,KAAA,GAAW,OAAO,aAAa,GAAG;EACvG,OAAO,QAAQ;CACjB;CAEA,MAAM,SACJ,OACG,QAAQ,SAAS,KAAK,UAAU,IAAI,SAAS,KAAK,QAAQ,SAAS,KAAK,OAAO,QAAQ,KAAK,QAAQ,MAAM,CAAC,CAC3G,GAAG,EAAE,CAAC,EAAE,QAAQ,MAAM;CAC3B,MAAM,QACJ,IAAI,aAAa,KAAA,IACb,CAAC,IACD;EAAE;EAAO,QAAQ,cAAc,KAAA,IAAY,OAAO,QAAQ,QAAQ,UAAU,CAAC;CAAE;CAIrF,IAAI,WAAW,YAAY,MAAM;EAG/B,MAAM,OACJ,IAAI,YAAY,KAAA,IACX,cAAc,QAAQ,IAAI,OAAO,CAAC,EAAE,QAAQ,OAC7C,IAAI,aAAa,KAAA,IACf,KAAA,IACA,OAAO,QAAQ,IAAI,QAAQ;EACnC,IAAI,SAAS,MAAM,OAAO;GAAE,GAAG;GAAM,GAAG;GAAS,MAAM;EAAwC;EAC/F,MAAM,QAAQ,SAAS,KAAA,IAAY,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;EAE7F,MAAM,UAAU,OAAO,MAAM,UAAU,MAAM,OAAO,SAAS,IAAI,YAAY;EAC7E,MAAM,UAAU,MAAM,SAAS,MAAM,MAAM;GACzC,MAAM,OAAO,MAAM,IAAI,EAAE,EAAE,KAAK;GAChC,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,WAAW,MAAM,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI;GAC/F,OAAO,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,KAAK,GAAG,MAAM,CAAC,CAAC;EAC7D,CAAC;EACD,MAAM,OAAO,WAAW,SAAS,KAAA,IAAY,KAAA,IAAY,YAAY,WAAW,IAAI;EACpF,MAAM,QAAQ,SAAS,MAAM,GAAG,EAAE,CAAC,EAAE;EAErC,MAAM,cACJ,eAAe,KAAA,IACX,CAAC,IACD,OAAO,QAAQ,WAAW,OAAO,UAAU,aAAa,OAAO,WAAW,UAAU;EAC1F,MAAM,QAAQ,KAAK,eAAe,KAAA,IAAY,KAAA,IAAY,IAAI,UAAU,KAAK,KAAK;EAClF,MAAM,YACJ,KAAK,eAAe,KAAA,IAChB,CAAC,IACD,EACE,WAAW,YACT,KACA,KAAK,YACL,UAAU,KAAA,IAAY,KAAA,IAAY,SAAS;GAAE,GAAG;GAAM,UAAU;IAAE,KAAK,KAAK;IAAY,QAAQ;GAAS;EAAE,GAAG,GAAG,GACjH,UAAU,KAAA,IAAY,KAAA,IAAY,SAAS;GAAE,GAAG;GAAM,UAAU;IAAE,KAAK,KAAK;IAAY,QAAQ;GAAS;EAAE,GAAG,GAAG,CACnH,EACF;EAEN,MAAM,YACJ,WAAW,eAAe,KAAA,KAAa,UAAU,KAAA,IAAY,KAAA,IAAY,YAAY,KAAK,OAAO,QAAQ,MAAM,KAAK,KAAK,KAAK;EAChI,MAAM,OAAO,cAAc,KAAA,KAAa,WAAW,eAAe,KAAA,IAAY,OAAO,iBAAiB,WAAW,YAAY,WAAW,QAAQ,IAAI,CAAC;EAErJ,MAAM,UAAU,WAAW,WAAW,KAAA,IAAY,OAAO,aAAa,WAAW,QAAQ,IAAI,UAAU,CAAC,CAAC;EACzG,OAAO;GACL,GAAG;GACH,GAAG;GACH,GAAG;GACH,GAAI,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU;GAC/C,SAAS,QAAQ;GACjB,SAAS,UAAU,KAAA,IAAY,UAAU,EAAE,MAAM,WAAW;GAC5D,GAAI,SAAS,KAAA,KAAa,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,MAAM,KAAK,EAAE;GACrF,SAAS,WAAW,SAAS,KAAA,IAAY,OAAO;GAChD,OAAO,cACJ,QAAQ,WAAW,OAAO,OAAO,QAAQ,CAAC,CAAC,CAC3C,KAAK,WAAW,QAAQ,QAAQ,GAAG,OAAO,IAAI,CAAC;GAClD;GACA,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;GACrC,YAAY,aACV,OAAO,QAAQ,WAAW,OAAO,OAAO,QAAQ,CAAC,GACjD,YAAY,QAAQ,WAAW,OAAO,OAAO,QAAQ,CAAC,CACxD;GACA,GAAG;GACH,MAAM;EACR;CACF;CAIA,IAAI,CAAC,WAAW,WAAW,WAAW,aAAa,KAAA,GAAW;EAC5D,MAAM,EAAE,aAAa;EAErB,MAAM,QACJ,KAAK,MAAM,SAAS,SACf,MAAM,MAAM,SAAS,KAAK,OAAO,UAAU,KAAK,MAAM,IAAI,OAAO,MAAM,EAAE,KAAK,UAC/E;EACN,MAAM,OAAO,IAAI,QAAQ;EACzB,IAAI,WAAW,QAAQ,SAAS,MAAM,SAAS;OAC1C,IAAI,WAAW,QAAQ,SAAS,MAAM;GACzC,MAAM,OAAO,QAAQ,MAAM,GAAG,KAAK,EAAE;GACrC,MAAM,KAAK,QAAQ,MAAM,GAAG,KAAK,EAAE;GACnC,IACE,QAAQ,MAAM,GAAG,KAAK,QAAQ,SAAS,KAAK,KAAK,GAAG,KACpD,QAAQ,IAAI,GAAG,KAAK,QAAQ,SAAS,KAAK,MAAM,GAAG,GAEnD,SAAS,mBAAmB,KAAK,MAAM,GAAG,GAAG,MAAM,iCAAiC,SAAS,KAAK,IAAI,MAAM,GAAG,SAAS,KAAK,KAAK,MAAM;EAC5I;EACA,MAAM,QAAQ,cACX,QAAQ,WAAW,OAAO,OAAO,MAAM,CAAC,CAAC,CACzC,KAAK,WAAW,QAAQ,MAAM,GAAG,OAAO,IAAI,CAAC;EAChD,IAAI,UAAU,KAAA,GACZ,OAAO;GACL,GAAG;GACH,GAAG;GACH;GACA;GACA,MAAM;GACN,SAAS,kBAAkB,QAAQ,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM;EAC3D;EAGF,MAAM,SACJ,SAAS,OACL,KAAA,IACA,OAAO,MAAM,WAAW,OAAO,OAAO,QAAQ,OAAO,OAAO,KAAK,EAAE;EACzE,IAAI,WAAW,KAAA,GACb,OAAO;GACL,GAAG;GACH,GAAG;GACH;GACA,MAAM;GACN,SAAS;EACX;EACF,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,MAAM,IAAI,MAAM,CAAC;EAC7E,WAAW,QAAQ,MAAM,GAAG,OAAO,MAAM,YAAY;EACrD,OAAO;GACL,GAAG;GACH,SAAS,EAAE,MAAM,WAAW;GAC5B,SAAS,QAAQ,MAAM,GAAG,OAAO,IAAI;GACrC,QAAQ,UAAU,KAAA,IAAY,OAAO,QAAQ,MAAM,GAAG,MAAM,CAAC;GAC7D,SAAS,UAAU,KAAA,IAAY,OAAO,QAAQ,OAAO,MAAM,MAAM,CAAC;GAClE;GACA,MAAM;GACN,SAAS;EACX;CACF;CAIA,IAAI,CAAC,WAAW,WAAW,WAAW,YAAY,KAAA,GAAW;EAC3D,MAAM,SAAS,QAAQ,WAAW,QAAQ,GAAG,IAAI;EACjD,IAAI,UAAU,KAAA,KAAa,QAAQ,QAAQ,KAAK,QAC9C,OAAO;GACL,GAAG;GACH,GAAG;GACH,GAAG;GACH;GACA,SAAS,QAAQ,QAAQ,GAAG,KAAK;GACjC,MAAM;GACN,SAAS,kBAAkB,QAAQ,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM;EAC7D;EAEF,MAAM,SAAS,OAAO,MACnB,WAAW,OAAO,OAAO,QAAQ,OAAO,OAAO,QAAQ,MAAM,OAAO,KAAK,IAAI,SAAS,KAAK,CAC9F;EACA,MAAM,QAAQ,MAAM;EACpB,IAAI,WAAW,KAAA,GACb,OAAO;GAAE,GAAG;GAAM,GAAG;GAAS,GAAG;GAAO,MAAM;GAAQ,SAAS;EAAuB;EACxF,OAAO;GACL,GAAG;GACH,GAAG;GACH,SAAS,EAAE,MAAM,WAAW;GAC5B,SAAS,QAAQ,QAAQ,GAAG,OAAO,IAAI;GACvC,QAAQ,UAAU,KAAA,IAAY,OAAO,QAAQ,QAAQ,GAAG,MAAM,CAAC;GAC/D,SAAS,UAAU,KAAA,IAAY,OAAO,QAAQ,OAAO,MAAM,MAAM,CAAC;GAClE,OAAO,CAAC;GACR,MAAM;GACN,SAAS;EACX;CACF;CAEA,IAAI,CAAC,WAAW,SAAS;EAEvB,MAAM,SAAS,QAAQ,WAAW,QAAQ,GAAG,IAAI;EACjD,IAAI,UAAU,KAAA,KAAa,QAAQ,QAAQ,IAAI,QAAQ;GAGrD,MAAM,WAAW,cAAc,KAAA,KAAa,UAAU,IAAI,QAAQ,KAAK,SAAS,YAAY,KAAA;GAC5F,MAAM,WAAW,WAAW,WAAW;GACvC,MAAM,QAAQ,aAAa,KAAA,IAAY,OAAO,QAAQ,QAAQ,SAAS,CAAC;GACxE,IAAI,UAAyB;GAC7B,IAAI,aAAa,KAAA,GACX;QAAA,UAAU,MAAM,UAAU,4BAA4B,MAAM,MAAM;GAAA,OACjE,IAAI,UAAU,MACnB,UAAU;QACL;IACL,MAAM,QAAQ,QAAQ,QAAQ,IAAI,GAAG,GAAG;IACxC,MAAM,MAAM,QAAQ,SAAS,KAAK,GAAG,IAAI;IACzC,MAAM,OAAO,QAAQ,SAAS,MAAM,GAAG,IAAI;IAC3C,IAAI,MAAM,QAAQ,OAAO,MAAM,QAAQ,MACrC,UAAU,4BAA4B,MAAM,MAAM,sCAAsC,KAAK,MAAM,MAAM,GAAG,IAAI,IAAI,IAAI,KAAK,MAAM,OAAO,GAAG,IAAI,IAAI;GACzJ;GACA,OAAO;IAAE,GAAG;IAAM,GAAG;IAAS,GAAG;IAAO,MAAM;IAAQ;GAAQ;EAChE;EACA,OAAO;GACL,GAAG;GACH,GAAG;GACH,GAAG;GACH;GACA,SAAS,QAAQ,QAAQ,GAAG,KAAK;GACjC,MAAM;GACN,SAAS,kBAAkB,QAAQ,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM;EAC7D;CACF;CAEA,IAAI,UAAU,KAAA,GACZ,OAAO;EACL,GAAG;EACH,GAAG;EACH,GAAG;EACH,MAAM;EACN,SAAS,wBAAwB,WAAW,MAAM;CACpD;CACF,MAAM,YAAY,YAAY,WAAW,IAAI;CAC7C,IAAI,cAAc,KAAA,GAChB,OAAO;EACL,GAAG;EACH,GAAG;EACH,GAAG;EACH;EACA;EACA,MAAM;EACN,SAAS,yCAAyC,WAAW,KAAK;CACpE;CAGF,MAAM,QACJ,WAAW,SAAS,cAChB,MAAM,QAAQ,SAAS,KAAK,KAAK,aAAa,KAAK,MAAM,KAAK,CAAC,CAAC,KAAK,SAAS,QAAQ,WAAW,KAAK,EAAE,CAAC,KACxG,WAAW,SAAS,kBACjB,aACA,WAAW,SAAS,yBAClB,cAAc,QAAQ,WAAW,OAAO,QAAQ,SAAS,OAAO,OAAO,SAAS,IAChF,CAAC,EAAA,CACL,KAAK,WAAW,QAAQ,WAAW,OAAO,IAAI,CAAC;CACvD,MAAM,UACJ,WAAW,UAAU,QACjB,QAAQ,SAAS,QACjB,WAAW,UAAU,WACnB,QAAQ,SAAS,WACjB,WAAW,UAAU,YACnB,QAAQ,SAAS,YACjB,QAAQ,SAAS,WAAW,QAAQ,UAAU,WAAW;CACnE,MAAM,QACJ,QAAQ,SAAS,UACb,QAAQ,QACR,QAAQ,SAAS,WACf,kBACA,QAAQ,SAAS,YACf,8BACA;CAEV,MAAM,YAAY,WAAW,eAAe,KAAA,IAAY,KAAA,IAAY,YAAY,KAAK,OAAO,QAAQ,MAAM,KAAK,KAAK,KAAK;CACzH,MAAM,OAAO,cAAc,KAAA,KAAa,WAAW,eAAe,KAAA,IAAY,OAAO,iBAAiB,WAAW,YAAY,WAAW,QAAQ,IAAI,CAAC;CAErJ,MAAM,SAAS,WAAW,SAAS,KAAA,KAAa,SAAS,KAAA,IAAY,KAAA,IAAY,UAAU,QAAQ,KAAK,IAAI;CAE5G,MAAM,EAAE,MAAM,WACZ,WAAW,KAAA,KAAa,SAAS,KAAA,KAAa,WAAW,UAAU,OAC/D;EAAE,MAAM;EAAQ,QAAQ,KAAA;CAAU,IAClC,YAAY,KAAK,MAAM,QAAQ,OAAO,KAAK,MAAM,GAAG,QAAQ,IAAI,CAAC;CACvE,MAAM,MAAM,WAAW,SAAS,KAAA,KAAa,SAAS,KAAA,KAAa,SAAS,KAAA,IAAY,OAAO,YAAY,WAAW,MAAM,MAAM,MAAM,QAAQ,MAAM;CACtJ,MAAM,QAAQ;EAAC,UAAU,OAAO,iBAAiB,MAAM,QAAQ,WAAW;EAAS;EAAM;CAAG,CAAC,CAAC,QAAQ,SAAS,SAAS,IAAI;CAC5H,MAAM,UAAU,MAAM,WAAW,IAAI,OAAO,MAAM,KAAK,IAAI;CAG3D,MAAM,eAAe,KAAK,MAAM,SAAS,KAAA,KAAa,WAAW,SAAS,mBAAmB,WAAW,UAAU;CAGlH,IAAK,WAAW,SAAS,mBAAmB,CAAC,gBAAiB,WAAW,SAAS,wBAChF,WAAW,QACT,WACA,OACA,WAAW,SAAS,kBAAkB,cAAc,YACtD;CAGF,IAAI,WAAW,SAAS,aAAa,WAAW,QAAQ,WAAW,OAAO,YAAY;CAItF,MAAM,OAAO,QAAQ,WAAW,MAAM,GAAG,IAAI,QAAQ,WAAW,KAAK,GAAG,KAAK;CAC7E,MAAM,OAAO,WAAW,MAAM,WAAW,SAAS,KAC7C,IAAI,aAAa,CAAC,EAAA,CAAG,MACnB,SACC,KAAK,OAAO,eACZ,KAAK,KAAK,SACV,KAAK,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,QAAQ,GACnD,IACA,KAAA;CACJ,IAAI,SAAS,KAAA,GACX,WAAW,gCAAgC,KAAK,MAAM,OAAO,KAAK,OAAO,IAAI,GAAG,IAAI,GAAG;CAGzF,MAAM,SAAS,IAAI,UAAU,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,MAAM;CACxE,IAAI,WAAW,SAAS,WAAW,SAAS,QAAQ,QAAQ,IAAI,GAC9D,WAAW,gCAAgC,KAAK,MAAM,SAAS,EAAE,IAAI,GAAG;CAG1E,MAAM,aAAa,WAAW,SAAS,cAAc,gBAAgB,OAAO,QAAQ,KAAK,IAAI,KAAA;CAC7F,MAAM,UAAU,MAAM,QAAQ;CAC9B,MAAM,OACJ,eAAe,KAAA,IACX,YAAY,KAAA,IACV,OACA,QAAQ,WAAW,KAAK,GAAG,QAAQ,CAAC,IACtC,SACE,OACA,cAAc,MAAM,QAAQ,OAAO,OAAO;CAClD,OAAO;EACL,GAAG;EACH,GAAG;EACH;EACA,SAAS,QAAQ,WAAW,KAAK;EACjC,QAAQ;EACR;EACA;EACA,GAAI,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU;EAC/C,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;EACrC,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;EACzC,GAAI,KAAK,MAAM,OAAO,KAAA,KAAa,WAAW,EAAE,MAAM,OAAO,QAAQ,SAAS,KAAK,EAAE,IAAI,CAAC;EAC1F,MAAM;EACN;CACF;AACF;;;;;;;;;;;;;;;AChhCA,MAAa,YACX;;AAGF,MAAa,gBAAgB;;AAE7B,MAAa,gBAAgB;;AAE7B,MAAa,gBAAgB;;AAG7B,MAAM,mBAAmB;;AAEzB,MAAM,WAAW;AACjB,MAAM,gBAAgB;AAetB,MAAM,aAAa;AACnB,MAAM,aAAa;;AAGnB,MAAa,UAA6B;CACxC;EACE,MAAM;EACN,IAAI;EACJ,IAAI;EACJ,YAAY;GAAE,MAAM;GAAe,MAAM;GAAe,MAAM;EAAc;EAC5E,WAAW,CACT;GAAE,SAAS;GAAY,IAAI;GAAO,QAAQ;EAAI,GAC9C;GAAE,SAAS;GAAY,IAAI;EAAM,CACnC;EACA,SAAS;EACT,QAAQ;CACV;CACA;EACE,MAAM;EACN,IAAI;EACJ,IAAI;EACJ,YAAY;GAAE,MAAM;GAAe,MAAM;GAAe,MAAM;EAAc;EAC5E,WAAW,CACT;GAAE,SAAS;GAAY,IAAI;GAAO,QAAQ;EAAI,GAC9C;GAAE,SAAS;GAAY,IAAI;EAAM,CACnC;EACA,SAAS;EACT,QAAQ;CACV;CACA;EACE,MAAM;EACN,IAAI;EACJ,IAAI;EACJ,YAAY;GAAE,MAAM;GAAe,MAAM;EAAc;EACvD,WAAW,CACT;GAAE,SAAS;GAAY,IAAI;EAAM,GACjC;GAAE,SAAS;GAAY,IAAI;EAAM,CACnC;CACF;CACA;EACE,MAAM;EACN,IAAI;EACJ,IAAI;EACJ,YAAY;GAAE,MAAM;GAAe,MAAM;EAAc;EACvD,WAAW,CACT;GAAE,SAAS;GAAY,IAAI;EAAM,GACjC;GAAE,SAAS;GAAY,IAAI;EAAM,CACnC;CACF;AACF;AAEA,MAAM,SAAS,QAAQ,QAAQ,WAAW,OAAO,WAAW,KAAA,CAAS;;AAGrE,MAAM,QAAkD;CACtD,CAAC,cAAc,aAAa;CAC5B,CAAC,cAAc,aAAa;CAC5B,CAAC,cAAc,aAAa;CAC5B,CAAC,cAAc,aAAa;AAC9B;;AAGA,MAAa,UAAkB;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC,CAAC,KAAK,IAAI;;;;;;AAOX,MAAa,WAAW,QAAgB,WAA2B;CACjE,MAAM,YAAY,QAAQ,OAAO,WAAW,GAAG;CAC/C,MAAM,OAAO,QAAQ,OAAO,MAAM,GAAG;CACrC,MAAM,MAAM;EAAC;EAA4B,YAAY,OAAO;EAAQ;EAAiB;CAAG;CACxF,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,OAAO,UAAU,GAC5D,IAAI,KAAK,aAAa,QAAQ,eAAe,WAAW,GAAG;CAC7D,IAAI,OAAO,QAAQ,MAAM;EACvB,MAAM,WAAW,QAAQ,OAAO,IAAI,UAAU,IAAI;EAClD,IAAI,KACF,OACA,iBACA,sBAAsB,YACtB,uBAAuB,YACvB,uBAAuB,OAAO,IAAI,cAClC,SACA,QACA,GACF;CACF;CACA,IAAI,KACF,cAAc,OAAO,MACrB,kBAAkB,OAAO,MACzB,gCACA,gCACA,+BACF;CACA,KAAK,MAAM,YAAY,OAAO,WAAW;EACvC,IAAI,KACF,aAAa,SAAS,QAAQ,aAAa,SAAS,MACpD,aAAa,SAAS,QAAQ,UAAU,UAAU,GAAG,QACrD,aAAa,SAAS,QAAQ,oBAC9B,aAAa,SAAS,QAAQ,0BAChC;EACA,IAAI,OAAO,QAAQ,MAAM,IAAI,KAAK,aAAa,SAAS,QAAQ,kBAAkB;CACpF;CACA,IAAI,KAAK,MAAM,8BAA8B;CAC7C,IAAI,OAAO,YAAY,KAAA,GAAW,IAAI,KAAK,aAAa,OAAO,SAAS;CACxE,IAAI,KAAK,mBAAmB;CAC5B,KAAK,MAAM,YAAY,OAAO,WAC5B,IAAI,SAAS,WAAW,KAAA,GAAW,IAAI,KAAK,cAAc,SAAS,QAAQ,UAAU,SAAS,QAAQ;CACxG,IAAI,KAAK,wBAAwB,QAAQ,EAAE;CAC3C,OAAO,IAAI,KAAK,IAAI;AACtB;;;;;;;AAQA,MAAa,cAAc,KAAa,KAAa,QAAgB,WAA2B;CAC9F,MAAM,QAAQ,QAAQ,SAAS,WAAW;EACxC,OAAO,OAAO,KAAK;EACnB;EACA,gBAAgB;EAChB;EACA,aAAa,IAAI,GAAG,OAAO,KAAK;EAChC,aAAa,IAAI;EACjB;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,QAAQ;EAAC,GAAG;EAAO,CAAC,cAAc,GAAG,OAAO,GAAG,eAAe;EAAG,CAAC,cAAc,GAAG,OAAO,GAAG,eAAe;CAAC;CACnH,OAAO;EACL,SAAS;EACT;EACA,mBAAmB;EACnB;EACA;EACA;EACA,GAAG;EACH,OAAO,OAAO;EACd;EACA,OAAO,OAAO;EACd;EACA;EACA,GAAG,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,sBAAsB,EAAE,MAAM,EAAE,KAAK,iBAAiB,CAAC;EACrF;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;AAYA,MAAa,aAAa,SAAmC;CAC3D,MAAM,OAAO,KAAK,KAAK;CACvB,MAAM,QAAQ,4DAA4D,KAAK,IAAI;CACnF,IAAI,UAAU,MAAM,OAAO;CAC3B,MAAM,CAAC,OAAO,MAAM,OAAO,KAAK,MAAM,QAAQ,QAAQ,SAAS;CAC/D,MAAM,QAAQ,KAAK,MAAM,MAAM,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,SAAS,SAAS,EAAE;CAC9E,MAAM,SAAS,MAAM,OAAO,aAAa,MAAM,OAAO,aAAa,MAAM,KAAK;CAC9E,MAAM,SAAS,MAAM,WAAW,OAAO,IAAI;CAC3C,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,MAAM,SAAS,SAAgC;EAC7C,MAAM,KAAK,MAAM,QAAQ,IAAI;EAC7B,OAAO,OAAO,KAAK,OAAQ,MAAM,KAAK,MAAM;CAC9C;CACA,OAAO;EACL,MACE,KAAK,IAAI,OAAO,IAAI,GAAG,OAAO,KAAK,IAAI,GAAG,OAAO,GAAG,GAAG,OAAO,IAAI,GAAG,OAAO,MAAM,GAAG,OAAO,MAAM,CAAC,IACnG,OAAO,KAAK,IAAI;EAClB,SAAS,WAAW;EACpB;EACA,KAAK,MAAM,KAAK;EAChB,KAAK,MAAM,KAAK;CAClB;AACF;;;;;;AAaA,MAAa,eAAe,MAAc,SAA4B,KAAK,QAAQ,OAAO,KAAK,QAAQ;;AAGvG,MAAa,cAAc,SAAwE;CACjG,MAAM,QAAQ,OAAO,OAAO,KAAK,MAAM,IAAI,CAA2E;CACtH,OAAO;EACL,IAAI,MAAM,QAAQ,SAAS,KAAK,aAAa,aAAa,CAAC,CAAC;EAC5D,aAAa,MAAM,QAAQ,KAAK,SAAS,OAAO,KAAK,0BAA0B,IAAI,CAAC;CACtF;AACF;;;;;;AAkBA,MAAa,aAAa,UAAoC;CAC5D,MAAM,EAAE,OAAO,WAAW,MAAM,SAAS;CACzC,IAAI,KAAK,GAAG,OAAO,GAAG,GAAG;CACzB,IAAI,CAAC,MAAM,MAAM,SAAS,QAAQ,iBAAiB,EAAE,GAAG,OAAO,+BAA+B,MAAM,SAAS;CAC7G,MAAM,QAAS,KAAK,MAAM,MAAM,KAAK,CAAC,CAA2B,OAAO,UAAU;CAClF,IAAI,QAAQ,GAAG,OAAO,aAAa,MAAM;CACzC,IAAI,MAAM,QAAQ,MAAM;EAEtB,MAAM,OADQ,KAAK,MAAM,MAAM,GACd,CAAC,CAAC,QAAQ,SAAS,KAAK,WAAW,IAAI,CAAC,CAAC;EAC1D,IAAI,OAAO,GAAG,OAAO,GAAG,KAAK;CAC/B;CACA,OAAO;AACT;;;;;;AAOA,MAAa,aAAa,QAA6B,UAAiC;CACtF,MAAM,SAAS,OAAO,KACnB,SACC,OAAO,MACJ,UACC,MAAM,SAAS,KAAK,QAAQ,MAAM,WAAW,KAAK,UAAU,MAAM,IAAI,SAAS,CAAC,MAAM,WAAW,MAAM,QAAQ,gBACnH,CAAC,EAAE,CACP;CACA,OAAO,OAAO,OAAO,MAAM,MAAM,KAAA,CAAS,IAAI,KAAK,IAAI,GAAI,MAAmB,IAAI;AACpF;;AAiCA,MAAM,QAAQ,SAAiB,SAC7B,IAAI,SAAS,SAAS,WAAW;CAC/B,SAAS,SAAS,CAAC,GAAG,IAAI,GAAG,EAAE,WAAW,SAAiB,IAAI,OAAO,QAAQ,WAAW;EACvF,IAAI,UAAU,MAAM,QAAQ,MAAM;OAC7B,uBAAO,IAAI,MAAM,GAAG,QAAQ,GAAG,KAAK,KAAK,GAAG,EAAE,IAAI,MAAM,QAAQ,IAAI,QAAQ,CAAC;CACpF,CAAC;AACH,CAAC;AAEH,MAAM,UAAU,cAA4C,UAAU,QAAQ,CAAC,CAAC,QAAQ,OAAO,EAAE;;AAGjG,MAAM,mBAA8B;CAAE,MAAM,OAAO,QAAQ,OAAO,OAAO,CAAC;CAAG,MAAM,KAAK,IAAI;AAAE;;;;;;AAO9F,MAAa,aAAa,OAAO,UAA2C;CAC1E,MAAM,EAAE,QAAQ,OAAO,OAAO,UAAU,QAAQ,WAAW;CAC3D,MAAM,EAAE,qBAAqB,MAAM,OAAO;CAC1C,MAAM,MAAM,MAAM,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK;CAC/C,MAAM,MAAM,MAAM,QAAQ,KAAK,OAAO,GAAG,SAAS,CAAC;CACnD,MAAM,OAAO,KAAK,KAAK,cAAc;CACrC,MAAM,UAAU,KAAK,KAAK,SAAS,GAAG,OAAO;CAC7C,KAAK,MAAM,UAAU,SAAS,MAAM,UAAU,KAAK,KAAK,GAAG,OAAO,KAAK,MAAM,GAAG,QAAQ,QAAQ,MAAM,CAAC;CACvG,MAAM,UAAU,MAAM,WAAW,KAAK,KAAK,OAAO,MAAM,MAAM,GAAG,OAAO,MAAM,MAAM,CAAC,CAAC;CACtF,MAAM,QAAQ,YAA2B;EACvC,MAAM,KAAK,QAAQ;GAAC;GAAgB;GAAW;GAAM;GAAM;EAAW,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EAC9F,MAAM,GAAG,KAAK;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;CACvE;CACA,MAAM,QAAQ,SAAiB,QAAQ,IAAI,GAAG;CAC9C,IAAI;EACF,MAAM,KAAK,QAAQ;GAAC;GAAgB;GAAU;GAAM;EAAI,CAAC;EACzD,MAAM,UAAU,mBAAmB,KAAK,MAAM,KAAK,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM;EACzF,MAAM,OAAO,OAAO;GAAC;GAAM;GAAQ;GAAO,GAAG,cAAc;GAAM;GAAO;EAAa,CAAC;EACtF,MAAM,OAAO,OAAO;GAAC;GAAM;GAAS;GAAW;GAAY;GAAO;GAAY;GAAO;EAAa,CAAC;EACnG,MAAM,OAAO,UAAU;GAAC;GAAM;GAAQ;GAAO,GAAG,cAAc;GAAM;GAAO;EAAa,CAAC;EACzF,MAAM,OAAO,UAAU;GAAC;GAAM;GAAS;GAAW;GAAY;GAAO;GAAY;GAAO;EAAa,CAAC;EAEtG,MAAM,WAAW,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC/C,gBAAgB,aAAa,KAAK,QAAQ,GAAG,CAAC,CAC9C,sBAAsB,aAAa,SAAS,CAAC,CAC7C,MAAM;EACT,OAAO,KAAK,QAAQ;EACpB,MAAM,SAAqB,CAAC;EAC5B,MAAM,2BAAW,IAAI,IAAkC;EACvD,KAAK,MAAM,QAAQ,QAAQ;GACzB,MAAM,UAAU,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC9C,gBAAgB,aAAa,KAAK,KAAK,IAAI,GAAG,CAAC,CAC/C,YAAY;IAAC;IAAM;IAAO;IAAM;IAAW;GAAO,CAAC,CAAC,CACpD,iBAAiB,WAAW;IAC3B,IAAI,OAAO;IACX,OAAO,GAAG,SAAS,UAA2B;KAC5C,MAAM,QAAQ,OAAO,MAAM,SAAS,EAAA,CAAG,MAAM,IAAI;KACjD,OAAO,KAAK,IAAI,KAAK;KACrB,KAAK,MAAM,QAAQ,MAAM;MACvB,MAAM,OAAO,UAAU,IAAI;MAC3B,IAAI,SAAS,MAAM;MACnB,MAAM,EAAE,MAAM,GAAG,UAAU;MAC3B,OAAO,KAAK;OAAE,GAAG;OAAO,MAAM,KAAK;OAAM,GAAG,YAAY,MAAM,UAAU,CAAC;MAAE,CAAC;KAC9E;IACF,CAAC;GACH,CAAC,CAAC,CACD,MAAM;GACT,OAAO,KAAK,OAAO;GACnB,SAAS,IAAI,KAAK,MAAM,OAAO;EACjC;EACA,MAAM,QAAQ,OAAO,WAAwD;GAC3E,MAAM,QAAQ,MAAM,OAAO,UAAU,CAAC,uBAAuB,MAAM,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE;GACxF,MAAM,EAAE,IAAI,OAAO,KAAK,MAAM,IAAI;GAClC,OAAO;IAAE;IAAI;GAAG;EAClB;EACA,MAAM,SAAS,MAAc,SAAiB,KAAK,UAAU;GAAC;GAAQ,KAAK,IAAI;GAAG;GAAS;GAAM;EAAI,CAAC;EACtG,OAAO;GACL;GACA,eAAe,MAAM,SAAS;GAC9B,aAAa,MAAM,eAAe;GAClC,MAAM,QAAQ;IACZ,MAAM,WAAW,KAAK,IAAI,IAAI;IAC9B,SAAS;KACP,MAAM,QAAkB,CAAC;KACzB,KAAK,MAAM,QAAQ,QAAQ;MACzB,MAAM,SAAS,KAAK;MAEpB,MAAM,UAAU,OAAO,YACrB,UAAU;OACR,WAAW,MAAM,MAAM,KAAK,MAAM,yBAAyB;OAC3D,OAAO,GAAG,MAAM,OAAO,SAAS,IAAI,KAAK,IAAI,GAAI;QAAC;QAAM;QAAM;QAAS;QAAQ;OAAM,CAAC,EAAE;OACxF,OAAO,MAAM,MAAM,KAAK,MAAM,yBAAyB,OAAO,MAAM;OACpE,KAAK,OAAO,QAAQ,OAAO,OAAO,MAAM,MAAM,KAAK,MAAM,qBAAqB;MAChF,CAAC,EAAA,CAAG,CAAC,CAAC,OAAO,UAAmB,OAAO,KAAK,CAAC;MAC/C,IAAI,YAAY,MAAM,MAAM,KAAK,GAAG,KAAK,KAAK,IAAI,SAAS;KAC7D;KACA,IAAI,MAAM,WAAW,GAAG;KACxB,IAAI,KAAK,IAAI,IAAI,UAAU,MAAM,IAAI,MAAM,4BAA4B,MAAM,KAAK,IAAI,GAAG;KACzF,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,aAAa,CAAC;IACnE;GACF;GACA,MAAM,WAAW;IACf,MAAM,MAA8B,CAAC;IACrC,KAAK,MAAM,QAAQ,QAAQ,IAAI,KAAK,QAAQ,WAAW,MAAM,MAAM,KAAK,MAAM,yBAAyB,CAAC,CAAC,CAAC;IAC1G,OAAO;GACT;GACA,iBAAiB;IAAE,GAAG;IAAQ,OAAO;IAAW,cAAc;GAAQ;GACtE;EACF;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM;CACR;AACF;;;;AC3ZA,MAAa,WAAW;;AAGxB,MAAa,WAAW,WAAiC;CACvD,IAAI,WAAW,MAAM,OAAO;CAC5B,IAAI,aAAa,KAAK,MAAM,GAAG,OAAO;CACtC,IAAI,UAAU,KAAK,MAAM,GAAG,OAAO;CACnC,OAAO;AACT;AAEA,MAAM,UAAU,SAAgC;CAC9C,IAAI;EACF,OAAO,aAAa,MAAM,MAAM,CAAC,CAAC,KAAK;CACzC,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,MAAa,YAAY,OAAO,KAAK,MAAoD,QAAQ,KAAK,SAAiB,QAAQ,MAAY;CACzI,MAAM,SAAS,OAAO,KAAK,MAAM,QAAQ,UAAU,QAAQ,CAAC;CAC5D,MAAM,KAAK,WAAW,OAAO,KAAA,IAAY,qBAAqB,KAAK,MAAM,CAAC,GAAG;CAC7E,MAAM,KAAK,IAAI;CACf,MAAM,UAAU,IAAI;CACpB,OAAO;EACL;EACA,IAAI,OAAO,KAAA,IAAY,OAAO,OAAO,EAAE;EACvC,QAAQ,OAAO,KAAK,MAAM,OAAO,SAAS,OAAO,MAAM,YAAY,CAAC;EACpE,KAAK,WAAW,KAAK,MAAM,OAAO,KAAK,CAAC;EACxC,OAAO,OAAO,KAAA,KAAa,YAAY,KAAA,IAAY,OAAO,GAAG,GAAG,GAAG;CACrE;AACF;;AAGA,MAAa,eAAe,OAAc,OAAa,SAAS,OAAkB;CAAE;CAAO,OAAO,QAAQ,KAAK,MAAM;CAAG,GAAG;AAAK;;;;;;AAOhI,MAAa,iBAAiB,OAAc,OAAa,SAAS,GAAG,MAAoD,QAAQ,QAAmB;CAClJ,MAAM,SAAS,IAAI;CACnB,IAAI,WAAW,KAAA,KAAa,WAAW,IAAI,OAAO,YAAY,OAAO,IAAI;CACzE,OAAO,YAAY,MAAM;EAAE,GAAI,KAAK,MAAM,MAAM;EAAY,QAAQ,KAAK;EAAQ,IAAI,KAAK;CAAG,CAAC;AAChG;;AAWA,MAAa,WAAW,OAAO,QAAwB;CACrD,MAAM,OAAO,OAAO,KAAK,MAAM,QAAQ,MAAM,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC;CAC7D,IAAI,SAAS,KAAA,KAAa,CAAC,KAAK,WAAW,MAAM,GAAG,OAAO;CAE3D,MAAM,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,MAAM;CAC7D,MAAM,QAAQ,MAAM;CACpB,IAAI,UAAU,KAAA,KAAa,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;CAC5D,OAAO;EAAE;EAAO,OAAO,MAAM,QAAQ,KAAK,SAAS,MAAM,MAAM,CAAC;CAAE;AACpE;;;;;;AAOA,MAAa,cAAc,QAAiB,UAAkC;CAC5E,MAAM,QAAQ,MAAM,QAAQ,OAAO;CACnC,OAAO,SAAS,IAAI,QAAQ,MAAM,QAAQ,OAAO,SAAS;AAC5D;;;;;;AAcA,MAAa,eAAe,QAAyB,IAAY,QAAe,SAC9E,OAAO,aAAa;CAClB;CACA,OAAO,GAAG,MAAM,GAAG,EAAe,IAAA,eAAe,UAAU;CAC3D,QAAQ;CACR,QAAQ,OAAO,UAAU;CACzB,IAAI,OAAO,OAAO,KAAA,KAAa,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,EAAE;CAC3E,KAAK;CACL,OAAO;AACT;AAEF,MAAM,UAAa,GAAa,GAAa,YAAyB,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW,MAAM,WAAW,MAAM;;;;;;AAO1I,MAAa,cAAc,GAAc,MACvC,EAAE,UAAU,EAAE,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC,OAAc,EAAE,OAAO,EAAE,OAAO,SAAS;;AAGlG,MAAa,gBAAgB,cAAiC,GAAG,UAAU,MAAM,GAAG,UAAU,MAAM,GAAG,UAAU,UAAU;;;;;;AAO3H,MAAa,cAAc,eAAkF;CAC3G,KAAK,MAAM,CAAC,OAAO,MAAM,WAAW,QAAQ,GAAG;EAC7C,MAAM,IAAI,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,WAAW,GAAG,KAAK,CAAC;EAC3E,IAAI,MAAM,KAAA,GAAW,OAAO,CAAC,GAAG,CAAC;CACnC;AAEF;;;;ACvIA,MAAa,mBAAmD,OAAO;;;;;AAMvE,MAAa,OAAiB;CAAE,OAAO;CAAK,MAAM;AAAI;;;;;;;AAOtD,MAAa,UAAoB;CAAE,OAAO;CAAI,MAAM;AAAK;;;;;;;;AAQzD,MAAa,aAAuB;CAAE,OAAO;CAAG,MAAM;AAAK;;AAG3D,MAAM,aAAa;;AAGnB,MAAM,eAAe;;AAGrB,MAAM,aAAa;AAEnB,MAAMC,WAAS,OAA8B,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;;AAqB7F,MAAa,cAAc,YAAoC;CAC7D,GAAI,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,CAAC,eAAe,QAAQ,SAAS;CAC5E,GAAI,QAAQ,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC,UAAU,QAAQ,IAAI;CAC7D,GAAI,QAAQ,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,WAAW,OAAO,QAAQ,KAAK,CAAC;AAC1E;;AAGA,MAAa,OAA+C;CAC1D,WAAW;CACX,KAAK;CACL,QAAQ;CACR,KAAK;AACP;;AAmHA,MAAa,SAA4C,SAAuC;CAC9F,MAAM,OAAY,CAAC;CACnB,MAAM,QAAkB,CAAC;CACzB,MAAM,UAA2E,CAAC;CAClF,IAAI,UAAU;CACd,MAAM,QAAQ,SAAiB;EAC7B,IAAI,CAAC,KAAK,WAAW,GAAG,GAAG;GACzB,IAAI,KAAK,SAAS,GAAG,MAAM,KAAK,IAAI;GACpC;EACF;EACA,IAAI;EACJ,IAAI;GACF,OAAO,KAAK,MAAM,IAAI;EACxB,QAAQ;GAEN,MAAM,KAAK,IAAI;GACf;EACF;EACA,KAAK,KAAK,IAAI;EACd,OAAO,IAAI;EACX,KAAK,MAAM,QAAQ,QAAQ,OAAO,CAAC,GACjC,IAAI,KAAK,MAAM,SAAS,KAAK,EAAE,GAAG,KAAK,QAAQ,IAAI;OAC9C,QAAQ,KAAK,IAAI;CAE1B;CACA,OAAO;EACL;EACA;EACA,UAAU,WACR,OAAO,GAAG,SAAS,UAA2B;GAC5C,WAAW,MAAM,SAAS;GAC1B,MAAM,QAAQ,QAAQ,MAAM,IAAI;GAChC,UAAU,MAAM,IAAI,KAAK;GACzB,KAAK,MAAM,QAAQ,OAAO,KAAK,KAAK,KAAK,CAAC;EAC5C,CAAC;EACH,MAAM,OAAO,QAAQ,KAAK;GACxB,MAAM,QAAQ,KAAK,MAAM,SAAS,MAAM,SAAS,KAAK,EAAE,CAAC;GACzD,IAAI,UAAU,KAAA,GAAW,OAAO,QAAQ,QAAQ,KAAK;GACrD,OAAO,IAAI,SAAS,SAAS,WAAW;IACtC,MAAM,QAAQ,iBAAiB;KAE7B,MAAM,SAAS,KAAK,QAAQ,SAAS,KAAK,OAAO,UAAU,KAAK,OAAO,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC;KAC1F,MAAM,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,QAAQ,GAAG,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,KAAK,UAAU,IAAI,CAAC;KAC5F,MAAM,OAAO,CAAC,GAAI,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,mBAAmB,KAAK,KAAK,KAAK,GAAG,GAAI,GAAI,MAAM,WAAW,IAAI,CAAC,IAAI,CAAC,aAAa,MAAM,MAAM,EAAE,CAAC,CAAC,KAAK,KAAK,GAAG,CAAE;KAChK,uBAAO,IAAI,MAAM,MAAM,MAAM,KAAK,MAAM,EAAE,YAAY,IAAI,MAAM,OAAO,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC;IAChI,GAAG,MAAM;IACT,QAAQ,KAAK;KACX;KACA,UAAU,SAAS;MACjB,aAAa,KAAK;MAClB,QAAQ,IAAI;KACd;IACF,CAAC;GACH,CAAC;EACH;CACF;AACF;;AAmKA,MAAa,WAAsD,WAAc,SAAoB;CACnG,UAA+D,WAAW,UAAU;CACpF,OAAO;AACT;;AAGA,MAAM,UAAU,SACd,cAAc,KAAK;CACjB,YAAY,MAAoB;EAC9B,KAA0D,WAAW,UAAU;EAC/E,OAAO;CACT;AACF;;;;;AAMF,MAAa,aAAa,SAAiB,SAAyB;CAClE,MAAM,KAAK,KAAK,YAAY,GAAG;CAC/B,OAAO,QACJ,WAAW,iBAAiB,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,CAC9C,WAAW,iBAAiB,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,CAC/C,WAAW,YAAY,IAAI;AAChC;;AAGA,MAAa,aAAa,UACxB,KAAK,UAAU;CACb,MAAM;CACN,MAAM,MAAM;CACZ,QAAQ,MAAM;CACd,UAAU;CACV,YAAY,MAAM;AACpB,CAAC;;;;;;AAOH,MAAa,YACX,SAEA,KAAK,SAAS,KAAK,OACjB,IAAI,SAAS,WACT,CACE;CACE,MAAM;CACN,KAAK,KAAK;CACV,UAAU,MAAM,KAAK,EAAE,QAAQ,KAAK,SAAS,GAAG,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;AACzE,CACF,IACA,CAAC,CACP;;;;;AAMF,MAAa,iBAAiB,MAAoC,YAA4B;CAC5F,IAAI,KAAK,UAAU;CACnB,OAAO,MAAM,KAAK,UAAU,KAAK,KAAK,EAAE,CAAE,SAAS,UAAU,MAAM;CACnE,OAAO;AACT;AAGA,MAAa,OAAO,EAAE,SAAS,EAAE;;AAGjC,MAAM,QAA2B;CAAC;CAAK;CAAK;CAAK;AAAI;;;;;;AAOrD,MAAa,QAAQ,OAAyC,WAA4D;CACxH,MAAM,WAAW,OAAO,MAAM,MAAM,OAAO;CAC3C,IAAI,EAAE,UAAU,IAAI,OAAO;CAC3B,MAAM,QAAQ,OAAO,UAAU,MAAM,WAAW;CAChD,MAAM,UAAU,MAAM,QAAQ,MAAM,SAAU,KAAK,IAAI,OAAO,IAAI,IAAI,KAAK,IAAI,OAAO,IAAI,IAAI,OAAO,IAAK;CAC1G,OAAO,KAAK,IAAI,UAAU,IAAI,IAAI,WAAW,MAAO,OAAO,OAAO,IAAI;AACxE;;AAGA,MAAM,aAAa,OAAO,cAA4D;CACpF,MAAM,OAAO;CAEb,MAAM,UAAS,MADI,OAAO,WAAW;EAAC;EAAM;EAAM,GAAG,KAAK,aAAa;CAAM,CAAC,CAAC,CAAC,YAAY,EAAE,EAAA,CAC1E,MAAM,KAAK,CAAC,CAAC,QAAQ,SAAS,SAAS,EAAE,CAAC,CAAC,IAAI,MAAM;CACzE,IAAI,OAAO,WAAW,KAAK,OAAO,MAAM,SAAS,CAAC,OAAO,SAAS,IAAI,CAAC,GAAG,OAAO;CACjF,OAAO,KAAK;EAAE,KAAK,OAAO;EAAK,SAAS,OAAO;CAAI,GAAG;EAAE,KAAK,OAAO;EAAK,SAAS,OAAO;CAAI,CAAC;AAChG;AAEA,MAAa,SAAS,OAAO,WAAiC,SAAoC;CAChG,MAAM,SAAS,MAAM,UAAU,KAAK,IAAI;CACxC,IAAI,OAAO,aAAa,GACtB,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,GAAG,EAAE,UAAU,OAAO,SAAS,IAAI,OAAO,OAAO,KAAK,GAAG;CACxF,OAAO,OAAO,OAAO,KAAK;AAC5B;;AAGA,MAAa,UAAU,OAAO,cAAqD;CACjF,MAAM,OAAO,MAAM,OAAO,WAAW,CAAC,YAAY,mBAAmB,CAAC;CACtE,MAAM,QAAQ,kBAAkB,KAAK,IAAI,CAAC,GAAG;CAC7C,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,4BAA4B,MAAM;CAC3E,OAAO,OAAO,KAAK;AACrB;;AAGA,MAAa,WAAW,WAAkF;CACxG,MAAM,QAAQ,cAAc,MAAM;CAClC,OAAO,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;AAC5C;;AAGA,MAAa,uBAAmF;CAC9F,SAAS,eAAe;CACxB,GAAG,QAAQ,cAAc,SAAS,CAAC;AACrC;;;;;AAMA,MAAa,uBAAuB,MAAc,WAAuC;CAAE;CAAM;CAAO,GAAG,QAAQ,gBAAgB,KAAK,CAAC,KAAK;AAAE;;;;;;AAOhJ,MAAa,WAAW,OACtB,SAOI;CACJ,MAAM,SAAS,OAAO,SAAS,WAAY,OAAO,OAAO,iBAAiB,IAAI,IAAI,gBAAgB,QAAQ,KAAA,IAAa;CACvH,IAAI,WAAW,KAAA,GAAW,MAAM,IAAI,MAAM,+BAA+B,OAAO,IAAI,GAAG;CACvF,OAAO;EACL,aAAa,MAAM,QAAQ,OAAO,KAAK;EACvC,SAAS,OAAO;EAChB,YAAY,OAAO,SAAS,WAAW,OAAO;EAC9C,GAAI,OAAO,iBAAiB,KAAA,KAAa,OAAO,aAAa,WAAW,IAAI,CAAC,IAAI,EAAE,cAAc,OAAO,aAAa;EACrH,GAAI,OAAO,OAAO,UAAU,WAAW,CAAC,IAAI,EAAE,QAAQ,OAAO,MAAM;CACrE;AACF;;AAoBA,MAAa,YAAY,UAA0B;CACjD,MAAM,SAAS,cAAc,KAAK,KAAK,CAAC,GAAG;CAC3C,IAAI,WAAW,KAAA,GAAW,MAAM,IAAI,MAAM,2BAA2B,OAAO;CAC5E,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,UAAU,OACrB,QACA,OAA6B,OAC7B,aACiB;CACjB,MAAM,QAAQ,MAAM,aAAa;CACjC,MAAM,EAAE,aAAa,SAAS,YAAY,cAAc,WAAW,MAAM,SAAS,IAAI;CACtF,MAAM,OAAO,UAAU,QAAQ,CAAC;CAChC,MAAM,EAAE,kBAAkB,SAAS,MAAM,8BAA8B,MAAM,WAAW;CACxF,MAAM,UAAU,MAAM,0BAA0B;CAChD,MAAM,SAAiC,CAAC;CACxC,MAAM,WAA6B,CAAC;CAEpC,MAAM,cAAc,MAAkB;CAEtC,IAAI,oBAA2D,QAAQ,QAAQ,CAAC,CAAC;CACjF,IAAI;CACJ,MAAM,QAAQ,YAAY;EAExB,MAAM,WAAW,MAAM,YAAY,CAAC,CAAC,WAC7B,OACL,UAAmB,KACtB;EACA,MAAM,QAAQ,MAAM;EACpB,KAAK,MAAM,aAAa,OAAO,QAAQ,GAAG,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC,YAAY,KAAA,CAAS;EAC1F,KAAK,MAAM,WAAW,SAAS,QAAQ,GAAG,MAAM,QAAQ,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;EACpF,IAAI,aAAa,MAAM,MAAM;CAC/B;;CAEA,MAAM,OAAO,OAAO,WAAiC,YAA6C;EAEhG,MAAM,MAAK,MADQ,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC,EAAA,CACzE,gBAAgB,SAAS,QAAQ,QAAQ,EAAE,EAAE;EAC7D,IAAI,OAAO,KAAA,KAAa,OAAO,IAAI,MAAM,IAAI,MAAM,GAAG,UAAU,QAAQ,EAAE,qBAAqB,QAAQ,QAAQ,GAAG;EAClH,OAAO;CACT;CACA,MAAM,QAAQ,WAAiC,YAC7C,QAAQ,UAAU,iBAChB,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,GAC3C,QAAQ,QAAQ,QAAQ,QAAQ,MAAM,CAAC,GACvC,CAAC,CACH;CACF,MAAM,WAAW,OAAO,YAA6C;EAEnE,MAAM,UAAU,MADG,QAAQ,QAAQ,QAAQ,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAA,CACQ,MAAM,SAAS,EAAE,EAAE;EAC/F,IAAI,WAAW,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,QAAQ,QAAQ,EAAE,eAAe;EAC9E,OAAO;CACT;CACA,IAAI;EAEF,KAAK,IAAI,KAAK,GAAG,MAAM,KAAK,QAAQ,MAAM,GAAG,SAAS,KAAK,MAAM,IAAI,QAAQ,CAAC,CAAC,MAAM,CAAC;EACtF,MAAM,OAAO,SAAS,KAAK;EAE3B,MAAM,cAAc,MAAM,cAAc,MAAM;EAC9C,IAAI,QAAQ,IAAI,iBAAiB,WAAW,CAAC,CAC1C,YAAY,IAAI,CAAC,CACjB,iBAAiB,KAAK,cAAc,OAAO,KAAK,CAAC;EAEpD,IAAI,OAAO,UAAU,KAAA,GACnB,QAAQ,MAAM,2BACZ,OAAO,QAAQ,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,cAAc;GAAE;GAAS,QAAQ;EAAK,EAAE,CACnF;EACF,IAAI,OAAO,UAAU,MAAM,QAAQ,MAAM,gBAAgB,YAAY,OAAO;EAE5E,MAAM,SAAS,OACb,OAAO,YAAY,KAAA,IAAY,QAAQ,MAAM,YAAY,CAAC,GAAG,OAAO,OAAO,CAAC,EAAA,CAC5E,MAAM;EACR,OAAO,KAAK,MAAM;EAClB,MAAM,WAAW,MAAM,KAAK,QAAQ,IAAI;EAGxC,MAAM,YAA8B,CAAC;EAErC,MAAM,4BAAY,IAAI,IAAgD;EACtE,MAAM,UAAmB,CAAC;EAC1B,MAAM,cAAc,YAA4B;GAC9C,MAAM,KAAK,cAAc,MAAM,OAAO;GACtC,IAAI,OAAO,KAAK,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO;GACzD,MAAM,QAAQ,QAAQ,KAAK;GAC3B,OAAO,GAAG,MAAM,GAAG,OAAO,GAAI,MAAM,IAAiB;EACvD;EACA,KAAK,IAAI,KAAK,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG;GAC/C,MAAM,MAAM,KAAK;GACjB,MAAM,CAAC,YAAY,cAAc,CAAC,SAAS,KAAM,SAAS,KAAK,EAAG;GAClE,IAAI,IAAI,SAAS,UAAU;IACzB,MAAM,OAAO,OAAuB,SAAS,UAAU,KAAK;KAAE,GAAG;KAAM,KAAK,IAAI;IAAK,CAAC,CAAC;IAEvF,MAAM,MAAM,MAAM,IAAI,iBAAiB,MAAM,YAAY,CAAC,CAAC,CACxD,YAAY,UAAU,CAAC,CACvB,mBAAmB,CAAC,CACpB,gBAAgB;KACf,MAAM,IAAI;KACV,MAAM,OAAO,QAAQ,IAAI,MAAM,GAAG,CAAC;KACnC,MAAM,OAAO,QAAQ,IAAI,QAAQ,MAAM,GAAG,CAAC;KAC3C,MAAM,OAAO,QAAQ,SAAS,GAAG,CAAC;IACpC,CAAC,CAAC,CACD,gBAAgB,KAAK,OAAO,CAAC,CAC7B,MAAM;IACT,OAAO,KAAK,GAAG;IAEf,MAAM,KAAK,KAAK,UAAU;IAC1B,MAAM,QAAQ,MAAM,KAAK,MAAM,CAAC,WAAW,GAAG,KAAQ,UAAU,IAAI,MAAM;IAC1E,MAAM,KAAK,MAAM,IAAI,SAAS,eAAe,CAAC,UAAU,IAAI,CAAC,UAAU,GAAG,KAAQ,UAAU,IAAI,MAAM;IAEtG,MAAM,WAAW,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC/C,gBAAgB,aAAa,IAAI,MAAM,GAAG,CAAC,CAC3C,sBAAsB,aAAa,SAAS,CAAC,CAC7C,MAAM;IACT,OAAO,KAAK,QAAQ;IACpB,QAAQ,MAAM;KACZ;KACA;KACA;KACA,IAAI;MAAE,QAAQ,MAAM,KAAK,KAAK,UAAU;MAAG,QAAQ,MAAM,KAAK,KAAK,UAAU;KAAE;KAC/E,MAAM;MAAE,QAAQ;MAAI,QAAQ,WAAW,KAAK,CAAC;KAAE;KAC/C,SAAS;MAAE,QAAQ;MAAI,QAAQ;KAAG;KAClC,OAAO,MAAM,QAAQ,GAAG;KACxB,SAAS,EAAE,sDAAsD,OAAO,MAAM,OAAO,EAAE;IACzF;IACA;GACF;GACA,MAAM,OAAO,WAAW,KAAK,CAAC;GAC9B,IAAI,QAAQ,IAAI,iBAAiB,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,YAAY,UAAU;GACjF,IAAI,IAAI,YAAY,KAAA,GAAW,QAAQ,MAAM,YAAY,CAAC,GAAG,IAAI,OAAO,CAAC;GACzE,IAAI,IAAI,gBAAgB,KAAA,GAAW,QAAQ,MAAM,gBAAgB,EAAE,GAAG,IAAI,YAAY,CAAC;GACvF,IAAI,IAAI,UAAU,KAAA,GAChB,QAAQ,MAAM,2BACZ,OAAO,QAAQ,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,cAAc;IAAE,SAAS,UAAU,SAAS,IAAI;IAAG,QAAQ;GAAK,EAAE,CAC1G;GACF,IAAI,IAAI,UAAU,KAAA,GAAW,QAAQ,MAAM,iBAAiB,KAAK,cAAc,IAAI,KAAK,CAAC;GAEzF,MAAM,OAAiB,CAAC;GACxB,MAAM,SAAS;IAAE,OAAO,CAAC;IAAe,OAAO;GAAE;GACjD,UAAU,IAAI,IAAI,MAAM,MAAM;GAC9B,QAAQ,MAAM,iBAAiB,WAAW;IACxC,IAAI,OAAO;IACX,OAAO,GAAG,SAAS,UAA2B;KAC5C,MAAM,SAAS,OAAO,MAAM,SAAS,EAAA,CAAG,MAAM,IAAI;KAClD,OAAO,MAAM,IAAI,KAAK;KACtB,KAAK,MAAM,QAAQ,OAAO;MACxB,KAAK,KAAK,IAAI;MACd,IAAI,KAAK,SAAS,YAAY,KAAK,MAAM;MACzC,OAAO,MAAM,KAAK,IAAI;MACtB,OAAO,SAAS;MAChB,IAAI,OAAO,MAAM,SAAS,cAAc,OAAO,MAAM,MAAM;KAC7D;IACF,CAAC;GACH,CAAC;GACD,MAAM,MAAM,MAAM,MAAM,MAAM,CAAC,CAAC,OAAO,UAAmB;IACxD,MAAM,IAAI,MAAM,WAAW,IAAI,KAAK,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,qBAAqB,KAAK,KAAK,IAAI,GAAG;GACrJ,CAAC;GACD,OAAO,KAAK,GAAG;GACf,MAAM,KAAK,KAAK,UAAU;GAC1B,MAAM,WAAW,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC/C,gBAAgB,aAAa,IAAI,MAAM,GAAG,CAAC,CAC3C,sBAAsB,aAAa,SAAS,CAAC,CAC7C,MAAM;GACT,OAAO,KAAK,QAAQ;GACpB,QAAQ,MAAM;IACZ;IACA;IACA;IACA,IAAI;KAAE,QAAQ,MAAM,KAAK,KAAK,UAAU;KAAG,QAAQ,MAAM,KAAK,KAAK,UAAU;IAAE;IAC/E,MAAM;KAAE,QAAQ;KAAI,QAAQ;IAAK;IACjC,SAAS;KAAE,QAAQ;KAAI,QAAQ;IAAG;IAClC,OAAO,MAAM,QAAQ,QAAQ;IAC7B,SAAS,CAAC;GACZ;EACF;EAEA,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,YAAY,SAAS,EAAG,CAAC,CAAC,MAAM;EACjF,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC5C,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,mBAAmB,CAAC,CACpB,MAAM;EACT,OAAO,KAAK,KAAK;EACjB,MAAM,WAAW,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC/C,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,sBAAsB,aAAa,SAAS,CAAC,CAC7C,MAAM;EACT,OAAO,KAAK,QAAQ;EAEpB,IAAI,UAAU,WAAW,KAAA,GACvB,SAAS,MAAM,WAAW;GACxB,QAAQ,SAAS;GACjB;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EACH,MAAM,SAAS,WAAW,KAAA,IAAY,SAAS;EAC/C,MAAM,WAAW,WAAW,KAAA,IAAY,MAAM,KAAK,QAAQ,SAAS,EAAG,IAAI;EAE3E,KAAK,IAAI,KAAK,GAAG,KAAK,QAAQ,QAAQ,MAAM,GAAG;GAC7C,MAAM,SAAS,OAAO,IAAI,WAAW,QAAQ,KAAK,EAAE,CAAE,GAAG;GACzD,QAAQ,MAAM;IAAE,GAAG,QAAQ;IAAM,MAAM;KAAE,GAAG,QAAQ,GAAG,CAAE;KAAM,QAAQ;IAAO;GAAE;EAClF;EAGA,MAAM,yBAAS,IAAI,IAAkC;EACrD,MAAM,UAAU,OAAO,YAAmD;GACxE,IAAI,YAAY,GAAG,OAAO;GAC1B,MAAM,MAAM,QAAQ,UAAU;GAC9B,IAAI,IAAI,IAAI,SAAS,UAAU,OAAO,IAAI;GAC1C,IAAI,QAAQ,OAAO,IAAI,OAAO;GAC9B,IAAI,UAAU,KAAA,GAAW;IACvB,QAAQ,MAAM,IAAI,iBAAiB,KAAK,CAAC,CACtC,gBAAgB,aAAa,IAAI,IAAI,MAAM,GAAG,CAAC,CAC/C,mBAAmB,CAAC,CACpB,MAAM;IACT,OAAO,KAAK,KAAK;IACjB,OAAO,IAAI,SAAS,KAAK;GAC3B;GACA,OAAO;EACT;EACA,KAAK,MAAM,SAAS,SAAS,IAAI,GAAG;GAClC,MAAM,QAAQ,MAAM,QAAQ,MAAM,IAAI;GACtC,MAAM,MAAM,QAAQ,MAAM,MAAM,EAAE,CAAE,GAAG;GACvC,KAAK,MAAM,WAAW,MAAM,UAC1B,MAAM,OAAO,OAAO;IAAC;IAAM;IAAS;IAAW,MAAM,SAAS,SAAS,QAAS;IAAG;IAAO;GAAG,CAAC;EAClG;EACA,KAAK,IAAI,KAAK,GAAG,KAAK,QAAQ,QAAQ,MAAM,GAAG;GAC7C,MAAM,MAAM,QAAQ;GAEpB,MAAM,SAAS,OAAO,YACpB,SAAS,MAAM,OAAO,IAAI,UAAU;IAAC;IAAM;IAAM;IAAS;IAAO,QAAQ,MAAM,GAAG,CAAC,CAAC;GAAG,CAAC,CAAC;GAC3F,QAAQ,MAAM;IAAE,GAAG;IAAK,SAAS;KAAE,QAAQ,MAAM,OAAO,IAAI,KAAK,MAAM;KAAG,QAAQ,MAAM,OAAO,IAAI,KAAK,MAAM;IAAE;GAAE;GAClH,IAAI,IAAI,IAAI,YAAY,KAAA,GAAW;GAEnC,MAAM,QAAQ,MAAM,QAAQ,KAAK,CAAC;GAClC,MAAM,WAAW,OAAO,QAAQ,IAAI,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO;GACxF,MAAM,OAAO,OAAO;IAAC;IAAU;IAAM;IAAM,GAAG;GAAQ,CAAC;GACvD,KAAK,MAAM,OAAO,OAAO,KAAK,IAAI,IAAI,OAAO,GAAG,IAAI,QAAQ,OAAO,MAAM,OAAO,OAAO;IAAC;IAAU;IAAM;GAAG,CAAC;EAC9G;EAEA,MAAM,QAAQ;GACZ,QAAQ,MAAM,QAAQ,KAAK;GAC3B,QAAQ,MAAM,QAAQ,QAAQ;GAC9B,GAAI,QAAQ,WAAW,IACnB,CAAC,IACD,EAAE,MAAM,OAAO,YAAY,QAAQ,KAAK,QAAQ,CAAC,IAAI,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,EAAE;EAClF;EACA,MAAM,UAAU,MAAoB;EACpC,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC7C,mBAAmB,CAAC,CACpB,gBAAgB,MAAM,CAAC,CACvB,YAAY;GACX;GACA,OAAO,MAAM,MAAM;GACnB,OAAO,MAAM,MAAM;GACnB,GAAG,QAAQ,KAAK,QAAQ,OAAO,IAAI,KAAK,CAAC;EAC3C,CAAC,CAAC,CACD,gBAAgB,QAAQ,OAAO,CAAC,CAChC,MAAM;EACT,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,QAAQ,MAAM,CAAC,SAAS,MAAM,GAAG,KAAQ,QAAQ;EACrE,IAAI,MAAM,OAAO,QAAQ,MAAM,IAAI,MAAM,sBAAsB,OAAO,MAAM,MAAM,GAAG;EACrF,MAAM,QAAQ,cAAc,MAAM,CAAC;EACnC,MAAM,WAAW,WAAW,KAAA,IAAY,gBAAgB,UAAU,KAAK,SAAS,IAAI,WAAW,QAAQ,QAAQ,EAAE,CAAE,GAAG;EACtH,MAAM,aAAa,UAAU,KAAK,SAAS,IAAI,OAAO,OAAQ,QAAQ,QAAQ,EAAE,CAAE,IAAiB;EACnG,MAAM,aAAa,QAAQ,WAAW,IAAI,WAAW,QAAQ,GAAG,EAAE,CAAC,CAAE,GAAG;EACxE,MAAM,SACJ,QAAQ,WAAW,IACf,OACA;GACE;GACA,MAAM,OAAO,YACX,QAAQ,KAAK,QAAQ,CAAC,IAAI,IAAI,MAAM;IAAE,OAAO,IAAI;IAAO,QAAQ,IAAI,KAAK;IAAQ,QAAQ,IAAI,KAAK;GAAO,CAAC,CAAC,CAC7G;EACF;EACN,MAAM,SAAS,QAAQ,UAAU,QAAQ,OAAO,MAAM,CAAC;EACvD,IAAI;EACJ,IAAI;EAEJ,MAAM,gCAAgB,IAAI,IAAkC;EAC5D,MAAM,YAAY,SAAwB;GACxC,MAAM,QAAQ,QAAQ,MAAM,QAAQ,IAAI,IAAI,SAAS,IAAI;GACzD,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,2BAA2B,MAAM;GAC1E,OAAO;EACT;;;;;;;EAOA,MAAM,YAAY,OAA6B;GAC7C,IAAI,CAAC,WAAW,EAAE,GAAG,MAAM,IAAI,MAAM,mCAAmC,KAAK,UAAU,EAAE,EAAE,iCAAiC;GAC5H,OAAO;EACT;EACA,MAAM,WAAW,UAAgE;GAC/E,IAAI,UAAU,UAAU,OAAO;IAAC;IAAO;IAAU,CAAC;GAAC;GACnD,IAAI,UAAU,UAAU,OAAO;IAAC;IAAU;IAAY,CAAC;GAAC;GACxD,MAAM,KAAK,SAAS,KAAK;GACzB,MAAM,MAAM,SAAS,GAAG,GAAG;GAC3B,MAAM,OAAO,GAAG,WAAW,WAAW,IAAI,KAAK,SAAS,IAAI,KAAK,OAAO,MAAM,GAAG,CAAC,CAAC;GACnF,MAAM,MAAM,IAAI,IAAI,SAAS,WAAW,CAAC,SAAS,IAAI,QAAQ,GAAG,OAAO,IAAI,CAAC;GAC7E,OAAO;IAAC,IAAI;IAAU;IAAM;GAAG;EACjC;;EAEA,MAAM,YAAY,UAAsD;GACtE,IAAI,UAAU,UAAU,OAAO,CAAC,OAAO,MAAM;GAC7C,IAAI,UAAU,UAAU,OAAO,CAAC,UAAU,MAAM;GAChD,MAAM,KAAK,SAAS,KAAK;GACzB,MAAM,MAAM,SAAS,GAAG,GAAG;GAC3B,OAAO,CAAC,IAAI,UAAU,IAAI,QAAQ,GAAG,OAAO;EAC9C;EACA,MAAM,kBAAwF;GAC5F,MAAM,QAAQ,QAAQ,MAAM,QAAQ,IAAI,IAAI,SAAS,WAAW,IAAI,IAAI,QAAQ,KAAA,CAAS;GACzF,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,mDAAmD;GAC5F,OAAO;EACT;EACA,MAAM,UAAU,OAAO,OAA6B,SAAmB;GACrE,MAAM,QAAQ,KAAK,OAAO,MAAM,OAAO,OAAO,IAAI,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,CAAE;GACxE,OAAO;IAAE,IAAI,MAAM;IAAI,IAAI,MAAM;GAAG;EACtC;EACA,MAAM,UAAU,QAAQ,QAAQ,QAAQ,IAAI,IAAI,SAAS,OAAO;EAChE,IAAI;EACJ,MAAM,cAA6B,CAAC;EACpC,IAAI;EACJ,cAAc,YAAY;GACxB,IAAI,aAAa,KAAA,GAAW,OAAO;GACnC,MAAM,WAA0B,CAAC;GACjC,KAAK,MAAM,UAAU,CAAC,GAAG,WAAW,CAAC,CAAC,QAAQ,GAAG;IAC/C,MAAM,OAAO,WAAY;KAAC;KAAU;KAAM;KAAM,GAAG,OAAO,KAAK,GAAG,OAAO;IAAQ,CAAC;IAClF,MAAM,OAAO,MAAM,OAAO,WAAY;KAAC;KAAU;KAAM,OAAO;IAAI,CAAC;IACnE,IAAI,SAAS,OAAO,QAAQ,MAAM,IAAI,MAAM,GAAG,OAAO,KAAK,SAAS,KAAK,0BAA0B,OAAO,QAAQ;IAClH,SAAS,QAAQ;KAAE,GAAG;KAAQ,UAAU;IAAK,CAAC;GAChD;GACA,WAAW;GACX,OAAO;EACT;EAEA,OAAO;GACL;GACA;GACA;GACA;GACA;GACA,UAAU;GACV;GACA,QAAQ,YAAY;GACpB,QAAQ,QAAQ;GAChB,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;GACzC,MAAM,OAAO,QAAQ;IACnB,MAAM,WAAW,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO;IAC/E,IAAI,SAAS,SAAS,GAAG,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;KAAM,GAAG;IAAQ,CAAC;IAChF,MAAM,OAA+B,CAAC;IACtC,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAClC,KAAK,OAAO,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;IAAG,CAAC;IACvD,OAAO;GACT;GACA,MAAM,aAAa,QAAQ;IACzB,MAAM,OAA+B,CAAC;IACtC,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GAAG,OAAO;IAE7C,gBAAgB,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC9C,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,mBAAmB,CAAC,CACpB,MAAM;IACT,OAAO,KAAK,WAAW;IACvB,MAAM,WAAW,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO;IAC/E,MAAM,OAAO,aAAa;KAAC;KAAU;KAAM;KAAM,GAAG;IAAQ,CAAC;IAC7D,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAClC,KAAK,OAAO,MAAM,OAAO,aAAa;KAAC;KAAU;KAAM;IAAG,CAAC;IAC7D,OAAO;GACT;GACA,MAAM,eAAe,UAAU;IAC7B,KAAK,MAAM,WAAW,UAAU;KAC9B,MAAM,OAAO,OAAO,CAAC,GAAG,OAAO,CAAC;KAChC,MAAM,OAAO,UAAU,CAAC,GAAG,OAAO,CAAC;IACrC;GACF;GACA,MAAM,WAAW,UAAU;IACzB,IAAI,SAAS,WAAW,GAAG;IAE3B,IAAI,cAAc,KAAA,GAAW;KAC3B,YAAY,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC,MAAM;KACjG,OAAO,KAAK,SAAS;IACvB;IACA,KAAK,MAAM,EAAE,MAAM,OAAO,WAAW,UAAU;KAC7C,IAAI,UAAU,KAAA,GAAW;MACvB,MAAM,QAAQ,OAAO,MAAM,OAAO,WAAW;OAAC;OAAU;OAAM,MAAM;MAAI,CAAC,CAAC;MAC1E,IAAI,EAAE,SAAS,MAAM,SAAS,MAAM,IAAI,MAAM,GAAG,MAAM,KAAK,qBAAqB,MAAM,UAAU,MAAM,QAAQ;KACjH;KACA,MAAM,SAAS,MAAM,OAAO,WAAW;MAAC;MAAU;MAAM;KAAI,CAAC;KAE7D,YAAY,KAAK;MAAE;MAAM;MAAQ,KAAK;MAAO,UAAU;KAAK,CAAC;KAC7D,MAAM,OAAO,WAAW;MAAC;MAAU;MAAM;MAAM,GAAG,KAAK,GAAG;KAAO,CAAC;KAClE,MAAM,MAAM,MAAM,OAAO,WAAW;MAAC;MAAU;MAAM;KAAI,CAAC;KAC1D,IAAI,QAAQ,OAAO,MAAM,IAAI,MAAM,GAAG,KAAK,qBAAqB,IAAI,wBAAwB,OAAO;IACrG;GACF;GACA,mBAAmB,YAAY;GAC/B,MAAM,UAAU,QAAQ;IACtB,MAAM,OAA+B,CAAC;IACtC,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GAAG,OAAO;IAC7C,MAAM,MAAM,OAAO;IACnB,IAAI,QAAQ,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,OAAO,MAAM,kCAAkC;IACzF,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAAG;KAClD,MAAM,OAAO,QAAQ;MAAC,GAAG,IAAI;MAAK;MAAM;KAAK,CAAC;KAC9C,KAAK,SAAS,MAAM,OAAO,QAAQ,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK;IAChF;IACA,OAAO;GACT;GACA,MAAM,MAAM,MAAM,KAAK,UAAU,UAAU,CAAC,GAAG;IAC7C,MAAM,CAAC,OAAO,MAAM,OAAO,QAAQ,EAAE;IACrC,OAAO,QAAQ,OAAO;KAAC;KAAuB;KAAM,QAAQ,OAAO,KAAK,GAAG,KAAK;KAAM,GAAG,WAAW,OAAO;KAAG,GAAG;IAAG,CAAC;GACvH;GACA,MAAM,KAAK,MAAM,KAAK,UAAU,UAAU,CAAC,GAAG;IAC5C,MAAM,CAAC,OAAO,MAAM,OAAO,QAAQ,EAAE;IACrC,MAAM,OAAO,OAAO;KAAC;KAAuB,KAAK;KAAO,QAAQ,OAAO,KAAK,GAAG,KAAK;KAAM,GAAG,WAAW,OAAO;KAAG,GAAG;IAAG,CAAC;GAC3H;GACA,MAAM,MAAM,MAAM,KAAK,UAAU;IAC/B,MAAM,CAAC,OAAO,UAAU,SAAS,EAAE;IACnC,MAAM,OACJ,SAAS,OACL;KAAC;KAAuB;KAAe;IAAM,IAC7C;KAAC;KAAuB;KAAS;KAAQ,GAAG,KAAK,MAAM,KAAK;IAAC;IACnE,OAAO,QAAQ,OAAO,IAAI;GAC5B;GACA,MAAM,QAAQ,IAAI,KAAK,UAAU;IAE/B,MAAM,UAAU,WAAW,EAAE,IAAI,OAAO,OAAO,SAAS,GAAG,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE;IAC3F,MAAM,CAAC,SAAS,SAAS,EAAE;IAC3B,KAAK,MAAM,UAAU,SACnB,MAAM,OAAO,OAAO;KAAC;KAAuB;KAAW;KAAQ,KAAK,OAAO;IAAK,CAAC;GACrF;GACA,MAAM,MAAM,OAAO;IACjB,MAAM,MAAM,UAAU;IACtB,MAAM,MAAM,aAAa,IAAI,IAAI,IAAI;IACrC,MAAM,OAAO,YAAY,IAAI,IAAI,IAAI,MAAM;IAC3C,OAAO,QACL,IAAI,UACJ,UAAU,OACN;KAAC;KAAuB;KAAQ;KAAU;KAAK,GAAG,KAAK;IAAO,IAC9D;KAAC;KAAuB;KAAQ;KAAQ;KAAK;KAAM,UAAU,KAAK;IAAC,CACzE;GACF;GACA,MAAM,cAAc;IAClB,IAAI,OAAO,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,OAAO,MAAM,mCAAmC;IACnG,MAAM,OAAO,QAAQ,CAAC,GAAG,OAAO,KAAK,CAAC;GACxC;GACA,MAAM,KAAK,MAAM;IACf,OAAO,OAAO,QAAQ,CAAC,GAAG,IAAI,CAAC;GACjC;GACA,MAAM,QAAQ,cAAc,MAAM,OAAO;IACvC,MAAM,UAAU,MAAM,IAAI,iBAAiB,YAAY,CAAC,CACrD,YAAY,IAAI,CAAC,CACjB,iBAAiB,KAAK,cAAc,KAAK,CAAC,CAAC,CAC3C,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC,CACtB,MAAM;IACT,OAAO,KAAK,OAAO;IACnB,OAAO;KACL,IAAI,MAAM,KAAK,SAAS,IAAI;KAC5B,OAAO,MAAM,QAAQ,OAAO;KAC5B,OAAO,YAAY,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC;IACjD;GACF;GACA,MAAM,MAAM,YAAY,MAAM,UAAU,CAAC,GAAG;IAC1C,MAAM,SAAS,OAAO,gBAAgB;IACtC,MAAM,OAAO,MAA+B;IAC5C,IAAI,UAAU,IAAI,OAAO,UAAU,CAAC,CACjC,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC,CACtB,gBAAgB,KAAK,OAAO;IAC/B,IAAI,QAAQ,QAAQ,MAAM,UAAU,QAAQ,YAAY,aAAa,OAAO,MAAM,GAAG;IACrF,MAAM,YAAY,MAAM,QAAQ,MAAM;IACtC,OAAO,KAAK,SAAS;IACrB,OAAO;KACL,OAAO;KACP,OAAO,SAAS,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC;KAC3C,YACE,UACG,KAAK,IAAI,CAAC,CACV,WAAW,KAAA,CAAS,CAAC,CACrB,YAAY,KAAA,CAAS;IAC5B;GACF;GACA,MAAM,OAAO;IACX,IAAI,OAAO,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,OAAO,MAAM,iCAAiC;IAChG,MAAM,OAAO,QAAQ,CAAC,GAAG,OAAO,IAAI,CAAC;GACvC;GACA,MAAM,OAAO;IACX,MAAM,OAAO,OAAO;KAAC;KAAQ;KAAM;KAAK;KAAM;KAAK;IAAQ,CAAC;IAC5D,MAAM,OAAO,UAAU;KAAC;KAAQ;KAAM;KAAK;KAAM;KAAK;IAAU,CAAC;IACjE,KAAK,MAAM,OAAO,SAChB,MAAM,OAAO,IAAI,UAAU;KAAC;KAAQ;KAAM;KAAK;KAAM;KAAK,IAAI,KAAK,OAAO,MAAM,GAAG,CAAC,CAAC;IAAG,CAAC;GAC7F;GACA,MAAM,MAAM,UAAU;IACpB,KAAK,MAAM,QAAQ,UAAU,MAAM,OAAO,QAAQ,CAAC,GAAG,IAAI,CAAC;GAC7D;GACA,MAAM,KAAK,IAAI,MAAM;IACnB,MAAM,CAAC,OAAO,MAAM,OAAO,QAAQ,EAAE;IACrC,OAAO,QAAQ,OAAO;KAAC;KAAuB;KAAS;KAAM;KAAQ,OAAO,KAAK,MAAM,IAAI,CAAC;KAAG,GAAG;IAAG,CAAC;GACxG;GACA,MAAM,SAAS;IACb,MAAM,OAAO,OAAO;KAAC;KAAM;KAAe;KAAS;IAAK,CAAC;IACzD,MAAM,OAAO,UAAU;KAAC;KAAM;KAAe;KAAS;IAAK,CAAC;IAC5D,KAAK,MAAM,OAAO,SAAS,MAAM,OAAO,IAAI,UAAU;KAAC;KAAM;KAAe;KAAS;IAAK,CAAC;GAC7F;GACA,cAAc,OAAO,MAAM,CAAC,CAAC,WAAW,KAAA,CAAS;GACjD,YAAY,OAAO,QAAQ,CAAC,CAAC,WAAW,KAAA,CAAS;GACjD,MAAM,OAAO,QAAQ,IAAI;IACvB,IAAI,OAAO,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,OAAO,MAAM,mCAAmC;IAErG,cAAc,MAAM,QAClB,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAAC,sBAAsB,aAAa,SAAS,GACvH,aAAa,OAAO,MAAM,GAC5B,CAAC,CAAC,MAAM;IACR,IAAI,CAAC,OAAO,SAAS,SAAS,GAAG,OAAO,KAAK,SAAS;IACtD,MAAM,OAAO,OAAO,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;IACpE,OAAO,QAAQ,WAAW;KAAC;KAAuB;KAAU,OAAO;KAAS;KAAQ,GAAG;IAAI,CAAC;GAC9F;GACA,MAAM,MAAM,OAAO,OAAO,OAAO,IAAI;IACnC,MAAM,MAAM,SAAS,MAAM,GAAG;IAC9B,IAAI,IAAI,IAAI,SAAS,SAAS,MAAM,IAAI,MAAM,WAAW,MAAM,IAAI,uCAAuC;IAC1G,MAAM,UAAU,IAAI,IAAI;IAGxB,MAAM,YAAY,YAA2C;KAC3D,IAAI,UAAU,cAAc,IAAI,MAAM,GAAG;KACzC,IAAI,YAAY,KAAA,GAAW;MACzB,UAAU,MAAM,QACd,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,IAAI,IAAI,MAAM,GAAG,CAAC,CAAC,sBAAsB,aAAa,WAAW,YAAY,GACtI,aAAa,IAAI,IAAI,MAAM,GAC7B,CAAC,CAAC,MAAM;MACR,cAAc,IAAI,MAAM,KAAK,OAAO;MACpC,OAAO,KAAK,OAAO;KACrB;KACA,OAAO;IACT;IACA,IAAI,YAAY,OAAO;KACrB,IAAI,MAAM,OAAO;KACjB,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,WAAW,MAAM,IAAI,4BAA4B;KAC5F,MAAM,OAAO,OAAO,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;KACpE,OAAO,QAAQ,MAAM,UAAU,GAAG;MAAC;MAAuB;MAAU;MAAS,MAAM;MAAQ,GAAG;KAAI,CAAC;IACrG;IACA,IAAI,WAAW,OAAO;KACpB,MAAM,UAAU,OAAO,MAAM,MAAM,OAAO,MAAM,MAAM;KACtD,IAAI,YAAY,KAAA,GAAW,OAAO;KAClC,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,WAAW,MAAM,IAAI,6CAA6C;KAC7G,MAAM,SAAS,UAAU,IAAI,MAAM,GAAG;KACtC,MAAM,SAAS,QAAQ,SAAS;KAChC,MAAM,QAAQ,MAAM,QAAQ,MAAM,UAAU,GAAG;MAAC;MAAuB;MAAS;MAAS,MAAM,MAAM;MAAM;KAAO,CAAC;KACnH,MAAM,UAAU,MAAM,MAAM;KAC5B,IAAI,YAAY,KAAA,GAAW;MAEzB,MAAM,UAAU,KAAK,IAAI;MACzB,MAAM,kBAA2B;OAC/B,IAAI,WAAW,KAAA,GAAW,OAAO;OACjC,MAAM,QAAQ,KAAK,IAAI,OAAO,QAAQ,QAAQ,OAAO,MAAM,MAAM;OACjE,OAAO,OAAO,MAAM,MAAM,OAAO,MAAM,SAAS,KAAK,CAAC,CAAC,MAAM,SAAS,KAAK,SAAS,OAAO,CAAC;MAC9F;MACA,OAAO,CAAC,UAAU,GAAG;OACnB,IAAI,KAAK,IAAI,IAAI,UAAU,YACzB,MAAM,IAAI,MAAM,WAAW,MAAM,IAAI,gCAAgC,MAAM,MAAM,KAAK,aAAa,QAAQ,OAAO,aAAa,IAAK,GAAG;OACzI,MAAMA,QAAM,EAAE;MAChB;KACF;KACA,OAAO;IACT;IACA,MAAM,QAAQ,OAAO,MAAM,QAAQ,OAAO,MAAM,QAAQ;IACxD,IAAI,UAAU,KAAA,GAAW,OAAO;IAChC,MAAM,EAAE,MAAM,MAAM,aAAa,MAAM;IACvC,OAAO,QAAQ,IAAI,UAAU;KAAC;KAAuB;KAAS,aAAa;KAAQ;KAAM;KAAU;IAAK,CAAC;GAC3G;GACA,MAAM,MAAM,MAAM,QAAQ,CAAC,GAAG;IAC5B,MAAM,SAAS,MAAkB;IACjC,MAAM,SAAS,IAAI,iBAAiB,WAAW,CAAC,CAC7C,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,YAAY,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC,CAClC,2BAA2B,MAAM,KAAK,UAAU,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAC9D,gBAAgB,OAAO,OAAO;IACjC,MAAM,YAAY,OAAO,iBAAiB,KAAA,IAAY,SAAS,OAAO,sBAAsB,GAAG,YAAY,EAAA,CAAG,MAAM;IACpH,OAAO;KACL,QAAQ,OAAO;KACf,QAAQ,OAAO,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAQ;KAC9D,UAAU,OAAO,WAAW,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,WAAW,KAAA,CAAS;KACtE,cACE,QAAQ,UACL,QAAQ,UAAU,MAAM,CAAC,CAAC,CAC1B,MAAM,CAAC,CACP,WAAW,KAAA,CAAS;KACzB,YACE,QAAQ,UACL,QAAQ,UAAU,MAAM,CAAC,CAAC,CAC1B,QAAQ,CAAC,CACT,WAAW,KAAA,CAAS;KACzB,YACE,QAAQ,UACL,QAAQ,UAAU,MAAM,CAAC,CAAC,CAC1B,KAAK,EAAE,QAAQ,UAAU,CAAC,CAAC,CAC3B,WAAW,KAAA,CAAS;KAEzB,YACE,UACG,KAAK,IAAI,CAAC,CACV,WAAW,KAAA,CAAS,CAAC,CACrB,YAAY,KAAA,CAAS;IAC5B;GACF;GACA,MAAM,SAAS;IAEb,MAAM,QAAQ,QAAQ,KAAK;IAC3B,MAAM,QAAQ,MAAM,IAAI,SAA8B,YAAY;KAChE,MAAM,UAAU,KAAK,IAAI;KACzB,MAAM,aAAa;MACjB,MAAM,OAAO,QAAQ,KAAK,MAAM,KAAK,CAAC,CAAC,MAAM,WAAW,OAAO,OAAO,OAAO;MAC7E,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI;WAC/B,IAAI,KAAK,IAAI,IAAI,UAAU,KAAO,QAAQ,IAAI;WAC9C,WAAW,MAAM,EAAE;KAC1B;KACA,KAAK;IACP,CAAC;IACD,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM,WAAW,CAAC;GAC1D;GACA,MAAM,SAAS,SAAS,WAAW,CAAC,GAAG,gBAAgB,CAAC,GAAG;IACzD,MAAM,SAAS,MAAM,OAAO,OAAO,CAAC,QAAQ,iBAAiB,CAAC,CAAC,CAAC,YAAY,EAAE;IAC9E,MAAM,UAAU,OAAO,cACrB,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC;IACxE,MAAM,SAAS,YAAoC;KACjD,MAAM,MAAqB,CAAC;KAC5B,KAAK,MAAM,OAAO,SAAS;MACzB,MAAM,MAAM,IAAI;MAChB,IAAI,KAAK;OACP,MAAM,IAAI;OACV,MAAM,IAAI;OACV,OAAO,IAAI,SAAS,WAAW,MAAM,YAAY,IAAI,MAAM,QAAQ,IAAI,KAAK;OAC5E,KAAK,MAAM,QAAQ,IAAI,GAAG,EAAA,CAAG;OAC7B,UACE,IAAI,SAAS,WACT;QACE,MAAM,IAAI;QACV,MAAM,OAAO,QAAQ,IAAI,MAAM,GAAG,CAAC;QACnC,MAAM,OAAO,QAAQ,IAAI,QAAQ,MAAM,GAAG,CAAC;QAC3C,MAAM,OAAO,QAAQ,SAAS,GAAG,CAAC;QAClC,WAAW,MAAM,OAAO,IAAI,KAAK;SAAC;SAAO;SAAQ;QAAI,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG;OACtF,IACA;QAAE,GAAG,IAAI;QAAU,GAAG,IAAI;OAAM;OACtC,SAAS,IAAI;MACf,CAAC;KACH;KACA,OAAO;IACT;IACA,OAAO;KACL,QAAQ,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAC5C,cAAc,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAClD,GAAI,OAAO,YAAY;MACrB,MAAM,aAAa,qBAAqB,KAAK,MAAM,CAAC,GAAG;MACvD,IAAI,eAAe,KAAA,GAAW,OAAO;OAAE,IAAI;OAAY,QAAQ;MAAkB;MACjF,MAAM,WAAW,MAAM,WAAW,KAAK;MACvC,OAAO,aAAa,OAAO,EAAE,IAAI,KAAK,IAAI;OAAE,IAAI;OAAU,QAAQ;MAAoB;KACxF,EAAA,CAAG;KACH,SAAS,MAAM,OAAO,QAAQ,CAAC,OAAO,iCAAiC,CAAC;KACxE,QAAQ,GAAG,QAAQ,KAAK,iBAAiB,cAAc,MAAM,QAAQ,KAAK,iBAAiB;KAC3F,WAAW,cAAc,WAAW,KAAA,IAAY,OAAO,IAAI;KAC3D,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,OAAO,SAAS,EAAE;KAC5D,QAAQ;MACN,OAAO;MACP,GAAI,OAAO,YAAY,KAAA,IAAY,CAAC,IAAI;OAAE,SAAS,OAAO;OAAS,MAAM,OAAO;MAAM;MACtF,KAAK,MAAM,QAAQ,MAAM,EAAA,CAAG;MAC5B;MACA,SAAS;MACT,GAAI,OAAO,UAAU,KAAA,IACjB,CAAC,IACD,EACE,OAAO,OAAO,YACZ,OAAO,QAAQ,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,aAAa,CAAC,MAAM,WAAW,QAAQ,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAClH,EACF;MACJ,GAAI,YAAY,KAAK,OAAO,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,YAAY,KAAK,GAAG;MAC1E,GAAG,QAAQ,eAAe,MAAM,CAAC;KACnC;KACA,SAAS;MACP;MACA,KAAK,MAAM,QAAQ,MAAM,EAAA,CAAG;MAC5B,WAAW,MAAM,OAAO,QAAQ;OAAC;OAAO;OAAQ;MAAI,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,KAAK;MACzE,GAAG,cAAc;KACnB;KACA,QAAQ;MACN,MAAM;MACN,OAAO;MACP,GAAI,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa;MACrD,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI;OAAE;OAAQ,GAAG,QAAQ,MAAM;MAAE;KAC/D;KACA;KACA;KACA,GAAI,QAAQ,WAAW,IAAI,CAAC,IAAI,EAAE,MAAM,MAAM,OAAO,EAAE;IACzD;GACF;GACA;EACF;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM;CACR;AACF;;;;;;;;;;;;;;;;;;AC3xCA,MAAM,QAAQ;;AAEd,MAAM,WAAW;;AAEjB,MAAMC,WAAS;;AAEf,MAAM,gBAAgB;;AAEtB,MAAM,UAAU;;AAGhB,MAAa,gBAAwB;;AAErC,MAAa,SAAiB,eAAe,MAAM;AAEnD,MAAMC,WAAS,OAA8B,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;;AAG7F,MAAa,QAAQ,cAAgC;CAAC;CAAQ;CAAM;CAAa;CAAM;CAAY;CAAO;CAAM;AAAS;;AAGzH,MAAa,kBAAkB,YAA8B;CAC3D;CACA;CACA,iGAAiG,QAAQ;AAC3G;;AAGA,MAAa,UAA6B;CAAC;CAAM;CAAM;AAA2E;;AAGlI,MAAa,aAAa,SACxB,KACG,MAAM,IAAI,CAAC,CACX,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,QAAQ,SAAS,SAAS,EAAE,CAAC,CAC7B,IAAI,MAAM,CAAC,CACX,MAAM,GAAG,MAAM,IAAI,CAAC;;AAGzB,MAAa,YAAY,MAAY,QAAwD;CAC3F,MAAM,OAAO,KAAK;CAClB,MAAM,OAAO,KAAK,SAAS,KAAA,IAAY,IAAI,QAAQ,KAAK,MAAM,GAAG;CACjE,OAAO;EACL,IAAI;EACJ,OAAO,IAAI,UAAU;EACrB;EACA;EACA;EACA,OAAO,QAAQ,KAAK,UAAU,IAAI,CAAC;EACnC;EACA,OAAO,KAAK,OAAO;EACnB;EACA;EACA;EACA,OAAO,KAAK,KAAK,IAAI,IAAI,EAAE;EAC3B,GAAI,KAAK,kBAAkB,KAAA,IAAY,CAAC,IAAI,CAAC,aAAa,KAAK,UAAU,KAAK,aAAa,CAAC;CAC9F;AACF;;AAGA,MAAaC,aAAW,MAAY,SAAiB,QACnD,KAAK,SAAS,YAAY,CAAC,OAAO,IAAI,CAAC,SAAS,IAAI,UAAU,cAAc,IAAI,QAAQ;;AAG1F,MAAa,aAAa,MAAY,WAA6B;CACjE,MAAM,QAAQ,KAAK,WAAW;CAC9B,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,QAAS,KAAK,KAAK,UAAW,QAAQ,EAAE;AACnF;;AAGA,MAAM,iBAAiB,OAAO,KAAU,UAAiC;CACvE,MAAM,UAAU,KAAK,IAAI;CACzB,SAAS;EACP,MAAM,OAAO,MAAM,IAAI,KAAK,KAAK,sEAAsE,CAAC;EACxG,IAAI,SAAS,OAAO;EACpB,IAAI,KAAK,IAAI,IAAI,UAAU,UAAU,MAAM,IAAI,MAAM,iCAAiC,MAAM,MAAM,SAAS,mBAAmB,KAAK,EAAE;EACrI,MAAMD,QAAM,GAAG;CACjB;AACF;;;;;AAMA,MAAa,cAAc,OAAO,KAAU,SAAiC;CAC3E,MAAM,OAAO,KAAK;CAClB,MAAM,IAAI,KAAK;EAAC;EAAM;EAAM;CAAgE,CAAC;CAC7F,MAAM,IAAI,KAAK,KAAK,yBAAyB,CAAC;CAC9C,MAAM,IAAI,KAAK,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;CACpE,MAAM,UAAU,MAAM,IAAI,QAAQ,MAAM,cAAc,KAAK,MAAM,GAAG,eAAe,IAAI,QAAQ,GAAG,aAAa;CAC/G,MAAM,eAAe,KAAK,OAAO;CACjC,IAAI,KAAK,aAAa;EACpB,MAAM,IAAI,KAAK,KAAK,kDAAkD,CAAC;EACvE,MAAM,IAAI,KAAK,KAAK,yBAAyB,CAAC;EAC9C,MAAM,eAAe,KAAK,MAAM;CAClC;CACA,OAAO;AACT;;AAGA,MAAM,cAAc,OAAO,UAAgC;CACzD,MAAM,UAAU,KAAK,IAAI;CACzB,OAAO,MAAM,OAAO,QAAQ,UAAU,MAAM,OAAO,KAAK,CAAC,CAAC,SAASD,UAAQ;EACzE,IAAI,KAAK,IAAI,IAAI,UAAU,UAAU,MAAM,IAAI,MAAM,4BAA4BA,SAAO,YAAY,SAAS,IAAI;EACjH,MAAMC,QAAM,EAAE;CAChB;AACF;;AAGA,MAAME,kBAAgB,YAA6C;CACjE,KAAK,IAAI,KAAK,QAAQ,SAAS,GAAG,MAAM,GAAG,MAAM,GAC/C,IAAI,QAAQ,GAAG,CAAE,OAAO,SAAS,OAAO,OAAO,QAAQ,GAAG,CAAE,WAAW,CAAC;CAC1E,OAAO;AACT;;;;;AAMA,MAAa,WAAW,OAAO,KAAU,SAAkB,MAAY,aAAqB,OAAe,MAAM,UAAwB;CACvI,MAAM,OAAO,KAAK;CAClB,MAAM,IAAI,OAAO;CACjB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,aAAaA,eAAa,IAAI,MAAM;CAC1C,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS,MAAM,GAAG,CAAC;CACjD,MAAM,SAAS,KAAK,SAAS,KAAA,IAAY,IAAI,QAAQ,KAAK,MAAM,GAAG,IAAI;CACvE,IAAI,QAAsB;CAC1B,IAAI,OAAoB;CACxB,IAAI;EACF,MAAM,MAAM,MAAM,CAAC,OAAO,GAAG,IAAM;EACnC,MAAM,YAAY,KAAK;EACvB,IAAI,CAAC,KAAK;GACR,QAAQ,MAAM,IAAI,MAAM,aAAa,UAAU,EAAE,OAAOD,UAAQ,MAAM,QAAQ,IAAI,GAAG,EAAE,CAAC;GACxF,MAAM,UAAU,KAAK,IAAI;GACzB,KAAK,MAAM,MAAM,UAAU,MAAM,MAAM,GAAG;IACxC,MAAMD,QAAM,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,IAAI,IAAI,QAAQ,CAAC;IAC1D,MAAM,IAAI,KAAK,KAAK,yFAAyF,CAAC;GAChH;GACA,OAAO,MAAM,IAAI,OAAO,QAAQ,MAAM,KAAK,MAAM;GACjD,MAAMA,QAAM,aAAa;GAEzB,IAAI,KAAK,OAAO,SAAS,KAAA,GAAW,MAAM,IAAI,KAAK,KAAK,OAAO,IAAI;EACrE;EAEA,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,KAAA,CAAS;EACtC,MAAM,MAAM,MAAM,CAAC,MAAM,GAAG,OAAO;CACrC,UAAU;EACR,MAAM,MAAM,KAAK;CACnB;CACA,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK,YAAY,OAAO,CAAC;CACjD,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,MAAM,OAAO,YAAY,OAAO,OAAO,UAAU;CACjD,MAAM,OAAO,iBAAiB,MAAM;CACpC,IAAI,QAAkC;CACtC,IAAI,WAA8B,CAAC;CACnC,IAAI,CAAC,KAAK;EACR,MAAM,QAAQ,KAAK,KAAK,6BAA6B,CAAC;EACtD,QAAQ,UAAU,MAAM,QAAQ,KAAK,KAAK,IAAI,CAAC,CAAC;EAChD,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,CAAC;EAC3B,WAAW,UAAU,MAAM,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC;CACjD;CACA,OAAO;EACL;EACA;EACA,QAAQ,CAAC,GAAG,MAAM,MAAM;EACxB;EACA,GAAI,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK;EAChC,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,MAAM;EACvB;EACA,GAAI,IAAI,aAAa,OAAO,CAAC,IAAI;GAAE,UAAU,IAAI;GAAU,WAAW,CAAC;EAAE;EACzE,OAAO;GACL,SAAS;IAAE,SAAS;KAAE,IAAI,IAAI;KAAU,OAAO,IAAI,MAAM;IAAO;IAAG,SAAS;KAAE,IAAI,QAAQ;KAAI,OAAO,QAAQ;IAAM;GAAE;GACrH,WAAW,CAAC;GACZ,SAAS;GACT,IAAI;GACJ,UAAU,CAAC;GACX,OAAO,MAAM,YAAY;GACzB;GACA;EACF;CACF;AACF;;;;;;;;;;;;AC/LA,MAAM,WAAW;;AAEjB,MAAM,YAAY;;AAElB,MAAM,SAAS;;AAGf,MAAM,iBAAiB,MAAc,UAAiC,CACpE,GAAI,UAAU,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,0BAA0B,MAAM,IAAI,gCAAgC,GAClH,GAAG,MAAM,MAAM,QAAQ,SAAS,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,GAAG,KAAK,aAAa,KAAK,yBAAyB,CACvH;;;;;;AAOA,MAAM,eAAe,MAAc,OAAe,IAAwB,OAAgC,eAAkC;CAC1I,IAAI,OAAO,KAAK,KAAK,GAAG,OAAO,CAAC;CAChC,IAAI,UAAU,KAAA,GAAW,OAAO,cAAc,MAAM,KAAK;CACzD,IAAI,UAAU,KAAK,KAAK,KAAK,CAAC,cAAc,OAAO,KAAA,KAAa,SAAS,KAAK,EAAE,GAAG,OAAO,CAAC;CAC3F,OAAO,UAAU,KAAK,KAAK,KAAK,aAC5B,CAAC,GAAG,KAAK,cAAc,MAAM,iCAAiC,IAC9D,CAAC,GAAG,KAAK,cAAc,MAAM,eAAe;AAClD;;;;;;;;;;AAWA,MAAa,oBAAoB,aAAiC;CAChE,GAAG,YAAY,cAAc,SAAS,OAAO,OAAO,SAAS,OAAO,IAAI,SAAS,OAAO,OAAO,SAAS,OAAO,YAAY,KAAA,CAAS;CACpI,GAAI,SAAS,OAAO,YAAY,KAAA,MAAc,SAAS,OAAO,SAAS,KAAA,KAAa,CAAC,OAAO,KAAK,SAAS,OAAO,IAAI,KACjH,CAAC,wBAAwB,SAAS,OAAO,QAAQ,SAAS,wCAAwC,IAClG,CAAC;CACL,GAAI,SAAS,QAAQ,YAAY,KAAA,IAAY,CAAC,yDAAyD,IAAI,CAAC;CAC5G,GAAI,SAAS,QAAQ,UAAU,KAAA,IAAY,CAAC,4CAA4C,IAAI,cAAc,eAAe,SAAS,QAAQ,KAAK;CAC/I,GAAG,YAAY,cAAc,SAAS,OAAO,OAAO,KAAA,GAAW,SAAS,OAAO,OAAO,IAAI;CAC1F,IAAI,SAAS,QAAQ,CAAC,EAAA,CAAG,SAAS,QAAQ,YAAY,WAAW,IAAI,QAAQ,IAAI,OAAO,IAAI,IAAI,KAAA,GAAW,KAAK,CAAC;AACnH;;AAGA,MAAa,kBAAkB,WAC7B,WAAW,KAAA,IACP,CAAC,oDAAoD,IACrD,OAAO,KAAK,MAAM,IAChB,CAAC,IACD,CAAC,6BAA6B,OAAO,6BAA6B;;AAiB1E,MAAa,QAAQ;;AAGrB,MAAa,QAAQ;;;;;;AAOrB,MAAa,kBAAkB,WAA+B,CAC5D,mBAAG,IAAI,IAAI;CACT,GAAG,eAAe,OAAO,MAAM,MAAM;CACrC,GAAI,OAAO,MAAM,UAAU,OAAO,CAAC,KAAK,IAAI,CAAC;CAC7C,GAAG,OAAO,UAAU,SAAS,aAAa,iBAAiB,QAAQ,CAAC;CACpE,GAAI,OAAO,UAAU,OAAO,CAAC,KAAK,IAAI,CAAC;AACzC,CAAC,CACH;;;;ACZA,MAAa,gBAAgB,OAAc,YACzC;CACE,QAAQ,MAAM;CACd,GAAG,OAAO,QAAQ,MAAM,cAAc,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO;CAC/E,GAAI,YAAY,OAAO,CAAC,IAAI,CAAC,aAAa,QAAQ,GAAG,MAAM,MAAM;CACjE;AACF,CAAC,CAAC,KAAK,IAAI;;AAGb,MAAa,kBAAkB,OAAc,YAC3C;CACE,QAAQ,MAAM;CACd,oBAAoB,MAAM,KAAK,GAAG,QAAQ,GAAG,MAAM,KAAK,GAAG,MAAM;CACjE,GAAG,OAAO,QAAQ,MAAM,gBAAgB,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,YAAY,IAAI,GAAG,MAAM,KAAK,GAAG,OAAO;CACxG;AACF,CAAC,CAAC,KAAK,IAAI;;;;;;;AAQb,MAAa,WACX,OACA,QACA,MACA,SACa;CACb,MAAM,SAAS,CAAC,GAAG,OAAO,QAAQ,MAAM,OAAO,GAAG,GAAG,OAAO,QAAQ,MAAM,SAAS,CAAC,CAAC,CAClF,QAAQ,CAAC,UAAU,SAAS,IAAI,CAAC,CACjC,KAAK,GAAG,QAAQ,GAAG,EAAE;CACxB,IAAI,SAAS,aAAa,SAAS,cAAc,OAAO,CAAC,MAAM;CAC/D,IAAI,SAAS,SAAS,OAAO;CAC7B,IAAI,SAAS,SAAS,SAAS,WAC7B,OAAO,OAAO,QAAQ,MAAM,OAAO,CAAC,CACjC,QAAQ,CAAC,UAAU,SAAS,IAAI,CAAC,CACjC,MAAM,GAAG,CAAC,CAAC,CACX,KAAK,GAAG,QAAQ,GAAG,EAAE;CAC1B,OAAO,CAAC,GAAG,QAAQ,MAAM;AAC3B;;AAGA,MAAM,eAAe,SAAqD,SAAS,aAAa,SAAS,eAAe,CAAC,eAAe,KAAK,IAAI,CAAC;;AAGlJ,MAAa,YAAY,SAAgD;CACvE,MAAM,MAAqC,CAAC;CAC5C,MAAM,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,SAAS,KAAK,QAAQ,OAAO,EAAE,CAAC;CACpE,IAAI,UAAyC;CAC7C,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI,MAAM,QAAQ,MAAM,GAAG;EAC/C,MAAM,CAAC,KAAK,SAAS,CAAC,MAAM,KAAM,MAAM,KAAK,EAAG;EAEhD,IAAI,QAAQ,UAAU,YAAY,MAAM;GACtC,UAAU,CAAC;GACX,IAAI,KAAK,OAAO;EAClB;EACA,QAAQ,OAAO;CACjB;CACA,OAAO;AACT;;AAGA,MAAa,UAAU,SAAyC;CAC9D,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,MAAM,KAAK,KAAK,QAAQ,GAAG;EAC3B,IAAI,KAAK,WAAW,GAAG,KAAK,OAAO,IAAI;EACvC,IAAI,KAAK,MAAM,GAAG,EAAE,KAAK,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK;CACnD;CACA,OAAO;AACT;;AAeA,MAAa,UACX,OACA,KACA,WACA,YACc;CACd,MAAM,SAAS,OAAO,MAAM,UAAU,SAAS,CAAC;CAChD,MAAM,WAAW,MAAM,QAAQ,SAAS;CACxC,MAAM,YAAY,IAAI,IAAI,UAAU,KAAK,SAAS,KAAK,OAAO,KAAK,CAAC;CACpE,IAAI,UAAU,SAAS,GAAG,OAAO;EAAE,SAAS;EAAM,SAAS;EAAO,KAAK,sBAAsB,UAAU,KAAK;CAAY;CACxH,MAAM,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC;CAC1B,MAAM,UAAU,OAAO,QAAQ,GAAG,CAAC,CAAC,MAAM,GAAG,QAAQ,OAAO,EAAE,CAAC,GAAG,MAAM;CACxE,IAAI,YAAY,MAAM,OAAO;EAAE,SAAS;EAAM,SAAS;EAAO,KAAK,6BAA6B;CAAK;CACrG,KAAK,MAAM,CAAC,IAAI,SAAS,UAAU,QAAQ,GAAG;EAC5C,IAAI,KAAK,OAAO,aAAa,UAAU,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,YAAY,GAAG,qBAAqB,KAAK,OAAO;EAAW;EACzI,IAAI,KAAK,OAAO,2BAA2B,QAAQ,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,YAAY,GAAG,SAAS,KAAK,OAAO,uBAAuB;EAAkB;EACvK,MAAM,OAAO,KAAK,SAAS,QACxB,YAAY,QAAQ,aAAa,WAAW,QAAQ,0BAA0B,QAAQ,QAAQ,mBAAmB,EACpH;EACA,IAAI,KAAK,WAAW,YAAY,KAAK,SAAS,WAAW,UACvD,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,YAAY,GAAG,OAAO,KAAK,OAAO,uBAAuB,KAAK,SAAS;EAAS;CAC3H;CACA,MAAM,OAAO,QAAQ,YAAY,CAAC;CAClC,IAAI,KAAK,YAAY,UAAU,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,GAAG,QAAQ,oBAAoB,KAAK;CAAU;CACpH,IAAI,KAAK,6BAA6B,KAAA,KAAa,KAAK,6BAA6B,eACnF,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,GAAG,QAAQ,4BAA4B,KAAK;CAA2B;CAChH,MAAM,SAAS,OAAO,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,WAAW,aAAa,KAAK,GAAG,KAAK,MAAM,SAAS,cAAc,CAAC,CAAC,CAAC;CACvH,IAAI,WAAW,UAAU,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,GAAG,QAAQ,OAAO,OAAO;CAAkB;CAC3G,KAAK,MAAM,QAAQ,MAAM,SAAS;EAChC,IAAI,SAAS,SAAS;EACtB,MAAM,OAAO,QAAQ,SAAS,CAAC;EAC/B,IAAI,KAAK,YAAY,WAAW,KAAK,mBAAmB,MAAM,KAAK,0BAA0B,MAC3F,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,GAAG,KAAK,uBAAuB,QAAQ;EAAmB;CACrG;CACA,OAAO;EAAE;EAAS,SAAS;EAAM,KAAK;CAAU;AAClD;AAEA,MAAMG,WAAS,OAA8B,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;;AAG7F,MAAa,cAAc;;;;;;;;;;;;AAa3B,MAAa,eAAe,OAAO,OAAc,UAAiD,CAAC,MAAyB;CAC1H,MAAM,QAAQ,MAAM,aAAa;CACjC,MAAM,OAAO,MAAM,gBAAgB;CACnC,MAAM,EAAE,kBAAkB,SAAS,MAAM,8BAA8B,MAAM,WAAW;CACxF,MAAM,UAAU,MAAM,0BAA0B;CAChD,MAAM,SAAiC,CAAC;CACxC,IAAI;CACJ,MAAM,QAAQ,YAAY;EACxB,KAAK,MAAM,aAAa,OAAO,QAAQ,GAAG,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC,YAAY,KAAA,CAAS;EAC1F,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;CAC7C;CACA,MAAM,OAAO,OAAO,cAAqD;EAEvE,MAAM,MAAK,MADQ,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC,EAAA,CACzE,gBAAgB,SAAS,QAAS,QAAQ,EAAE,EAAE;EAC9D,IAAI,OAAO,KAAA,KAAa,OAAO,IAAI,MAAM,IAAI,MAAM,GAAG,UAAU,QAAQ,EAAE,qBAAqB,QAAS,QAAQ,GAAG;EACnH,OAAO;CACT;CACA,IAAI;EACF,UAAU,MAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;EACpC,MAAM,wBAAQ,IAAI,IAAkC;EACpD,MAAM,4BAAY,IAAI,IAAkC;EACxD,MAAM,QAAQ;GAAE,SAAS,CAAC;GAA8B,WAAW,CAAC;EAA6B;;EAEjG,MAAM,QAAQ,OAAO,MAAc,SAAiB,MAAc,SAAiB,UAAkB;GACnG,MAAM,MAAM,MAAM,IAAI,iBAAiB,MAAM,KAAK,CAAC,CAChD,YAAY,OAAQ,CAAC,CACrB,mBAAmB,IAAI,CAAC,CACxB,2BAA2B,CAAC;IAAE;IAAS,QAAQ;GAAK,CAAC,CAAC,CAAC,CACvD,YAAY;IAAC;IAAM;IAAM,GAAG,QAAQ,GAAG,KAAK;GAAgC,CAAC,CAAC,CAC9E,iBAAiB,KAAK,cAAc,KAAK,CAAC,CAAC,CAC3C,MAAM;GACT,OAAO,KAAK,GAAG;GACf,MAAM,IAAI,MAAM,GAAG;GACnB,MAAM,WAAW,MAAM,QACrB,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC,sBAAsB,aAAa,SAAS,GACpH,aAAa,IAAI,MAAM,GACzB,CAAC,CAAC,MAAM;GACR,OAAO,KAAK,QAAQ;GACpB,UAAU,IAAI,MAAM,QAAQ;GAC5B,OAAO;IAAE,IAAI,MAAM,KAAK,GAAG;IAAG,OAAO,MAAM,QAAQ,QAAQ;GAAE;EAC/D;EACA,MAAM,CAAC,OAAO,GAAG,QAAQ,MAAM;EAC/B,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,uBAAuB;EAChE,MAAM,QAAQ,SAAS,MAAM,MAAM,OAAO,MAAM,SAAS,QAAQ,qBAAqB,aAAa,OAAO,IAAI,GAAG,MAAM,MAAM,MAAM;EACnI,MAAM,YAAY,MAAM,QAAQ,MAAM,CAAC;EACvC,KAAK,MAAM,QAAQ,MACjB,MAAM,QAAQ,QAAQ,MAAM,MAAM,MAAM,MAAM,SAAS,QAAQ,qBAAqB,aAAa,OAAO,SAAS,GAAG,MAAM,MAAM,MAAM;EACxI,KAAK,MAAM,QAAQ,MAAM,WACvB,MAAM,UAAU,QAAQ,MAAM,MAAM,MAAM,MAAM,SAAS,UAAU,uBAAuB,eAAe,OAAO,SAAS,GAAG,MAAM,MAAM,QAAQ;EAElJ,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,YAAY,OAAO,CAAC,CAAC,MAAM;EAC5E,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC5C,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,mBAAmB,CAAC,CACpB,MAAM;EACT,OAAO,KAAK,KAAK;EACjB,MAAM,WAAW,MAAM,KAAK,MAAM;EAElC,MAAM,oBAAoB,MAAM,UAAU,KAAK,SAAS,GAAG,MAAM,UAAU,KAAK,CAAE,GAAG,GAAG,MAAM,cAAc;EAC5G,MAAM,WAAW,MAAqB;EACtC,MAAM,WAAW,MAAM,IAAI,iBAAiB,IAAI,CAAC,CAC9C,YAAY,OAAO,CAAC,CACpB,YAAY;GAAC;GAAQ;GAAkC,kBAAkB,KAAK,GAAG;EAAC,CAAC,CAAC,CACpF,gBAAgB,SAAS,OAAO,CAAC,CACjC,MAAM;EACT,OAAO,KAAK,QAAQ;EACpB,MAAM,aAAa,MAAM,KAAK,QAAQ;EACtC,KAAK,MAAM,WAAW,mBACpB,MAAM,IAAI,SAAe,SAAS,WAAW;GAC3C,MAAM,UAAU,KAAK,IAAI;GACzB,MAAM,aAAa;IACjB,IAAI,SAAS,KAAK,MAAM,SAAS,KAAK,OAAO,gBAAgB,KAAK,gBAAgB,OAAO,GAAG,QAAQ;SAC/F,IAAI,KAAK,IAAI,IAAI,UAAU,KAAQ,uBAAO,IAAI,MAAM,oCAAoC,SAAS,CAAC;SAClG,WAAW,MAAM,EAAE;GAC1B;GACA,KAAK;EACP,CAAC;EAEH,MAAM,cAAc,MAAM,QAAQ,KAAK;EACvC,MAAM,UAAU,CAAC,aAAa,GAAI,QAAQ,mBAAmB,OAAO,MAAM,UAAU,KAAK,SAAS,MAAM,UAAU,KAAK,CAAE,KAAK,IAAI,CAAC,CAAE;EACrI,MAAM,UAAU,MAAoB;EACpC,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC7C,mBAAmB,CAAC,CACpB,gBAAgB,MAAM,CAAC,CACvB,YAAY,CAAC,uBAAuB,GAAG,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,CAC5D,gBAAgB,QAAQ,OAAO,CAAC,CAChC,MAAM;EACT,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,QAAQ,MAAM,CAAC,SAAS,MAAM,GAAG,KAAQ,QAAQ;EACrE,IAAI,MAAM,OAAO,QAAQ,MAAM,IAAI,MAAM,sBAAsB,OAAO,MAAM,MAAM,GAAG;EAErF,MAAM,OAAO,SAAuC;GAClD,MAAM,QAAQ,MAAM,IAAI,IAAI;GAC5B,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,yBAAyB,MAAM;GACxE,OAAO;EACT;EACA,MAAM,cAAc,SAAuC;GACzD,MAAM,QAAQ,UAAU,IAAI,IAAI;GAChC,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,yBAAyB,MAAM;GACxE,OAAO;EACT;EACA,MAAM,OAAO,MAAc,SAA6C;GACtE,MAAM,OAAO,MAAM,UAAU,SAAS,IAAI,IAAI,MAAM,eAAe,MAAM;GACzE,OAAO,OAAO,IAAI,IAAI,GAAG;IAAC,MAAM,SAAS;IAAK;IAAM,OAAO,IAAI;IAAG,GAAG;GAAI,CAAC;EAC5E;EACA,MAAM,UAAU,OAAO,OAA6B,SAAmC;GACrF,MAAM,QAAQ,KAAK,OAAO,MAAM,OAAO,OAAO,IAAI,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,CAAE;GACxE,OAAO;IAAE,IAAI,MAAM;IAAI,IAAI,MAAM;GAAG;EACtC;EACA,MAAM,MAA8B,OAAO,YAAY,OAAO,QAAQ,MAAM,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;EACvH,MAAM,OAAO,YAAgC;GAC3C,MAAM,YAAY,CAAC;GACnB,KAAK,MAAM,QAAQ,MAAM,WAAW;IAClC,MAAM,SAAS,SAAS,MAAM,IAAI,MAAM;KAAC;KAAY;KAAU,MAAM;IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACpF,MAAM,WAAW,SAAS,MAAM,IAAI,MAAM;KAAC;KAAY;KAAY,MAAM;IAAI,CAAC,CAAC;IAC/E,UAAU,KAAK;KAAE;KAAQ;IAAS,CAAC;GACrC;GACA,MAAM,UAAkD,CAAC;GACzD,KAAK,MAAM,QAAQ,MAAM,SAAS,QAAQ,QAAQ,OAAO,MAAM,IAAI,MAAM,CAAC,QAAQ,aAAa,CAAC,CAAC;GACjG,OAAO,OAAO,OAAO,KAAK,WAAW,OAAO;EAC9C;EACA,MAAM,SAAS,OAAsC,OAAO,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;EAC5G,MAAM,SAAS,MAAiB,YAA4B;GAC1D,IAAI,SAAS,WAAW,OAAO;GAC/B,IAAI,SAAS,YAAY,OAAO,MAAM,UAAU;GAChD,MAAM,UAAU,MAAM,QAAQ,MAAM,SAAS,SAAS,OAAO;GAC7D,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,0BAA0B;GACrE,OAAO;EACT;EAEA,OAAO;GACL;GACA;GACA;GACA,SAAS,MAAM;GACf,WAAW,MAAM;GACjB,OAAO;IAAE,QAAQ;IAAa;GAAQ;GACtC,QAAQ,QAAQ;GAChB,UAAU,SAAS;GACnB,MAAM,OAAO,QAAQ;IACnB,MAAM,WAAW,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO;IAC/E,IAAI,SAAS,SAAS,GAAG,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;KAAM,GAAG;IAAQ,CAAC;IAChF,MAAM,OAA+B,CAAC;IACtC,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG,KAAK,OAAO,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;IAAG,CAAC;IAC5F,OAAO;GACT;GACA,MAAM,SAAS,SAAS,aAAa;IACnC,MAAM,UAAU,KAAK,IAAI;IACzB,IAAI,OAAO;IACX,IAAI,OAAkB;KAAE,SAAS;KAAM,SAAS;KAAO,KAAK;IAAc;IAC1E,OAAO,KAAK,IAAI,IAAI,UAAU,QAAQ;KACpC,OAAO,MAAM,KAAK,CAAC,CAAC,OAAO,WAAoB;MAAE,SAAS;MAAM,SAAS;MAAO,KAAM,MAAgB;KAAQ,EAAE;KAEhH,OAAO,KAAK,UAAU,OAAO,IAAI;KACjC,IAAI,QAAQ,KAAK,KAAK,YAAY,MAAM,OAAO,KAAK;KACpD,MAAMA,QAAM,GAAK;IACnB;IACA,MAAM,IAAI,MAAM,iCAAiC,OAAO,OAAO,KAAK,KAAK;GAC3E;GACA,MAAM,MAAM,SAAS;IACnB,MAAM,IAAI,SAAS,CAAC,UAAU,CAAC;IAC/B,MAAM,QAAQ,OAAO,MAAM,IAAI,SAAS;KAAC;KAAQ,OAAO,MAAM,QAAQ,SAAS,CAAC;KAAG;IAAM,CAAC,CAAC;IAC3F,IAAI,UAAU,MAAM,QAAQ,SAAS,GAAG,MAAM,IAAI,MAAM,GAAG,MAAM,iCAAiC;GACpG;GACA,MAAM,QAAQ;IACZ,KAAK,MAAM,QAAQ,MAAM,WAAW,MAAM,IAAI,MAAM;KAAC;KAAY;KAAS,MAAM;IAAI,CAAC;GACvF;GACA,MAAM,MAAM,SAAS;IACnB,OAAO,QAAQ,MAAM,IAAI,SAAS;KAAC;KAAU;KAAa;IAAK,CAAC,GAAG,MAAM,IAAI,SAAS;KAAC;KAAU;KAAK;KAAK;IAAI,CAAC,CAAC;GACnH;GACA,QAAQ;GACR,MAAM,OAAO,MAAM;IACjB,MAAM,SAAS,MAAkB;IACjC,MAAM,YAAY,MAAM,IAAI,iBAAiB,IAAI,CAAC,CAC/C,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,YAAY;KAAC;KAAQ;KAAyC,GAAG;IAAI,CAAC,CAAC,CACvE,gBAAgB,OAAO,OAAO,CAAC,CAC/B,MAAM;IACT,OAAO;KACL,QAAQ,OAAO;KACf,QAAQ,OAAO,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAQ;KAE9D,YACE,UACG,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CACpB,WAAW,KAAA,CAAS,CAAC,CACrB,YAAY,KAAA,CAAS;IAC5B;GACF;GACA,MAAM,MAAM,MAAM,MAAM,IAAI;IAC1B,MAAM,QAAQ,QAAQ,OAAO,UAAU,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG;IAC3D,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB;KAAM;KAAO,GAAG,YAAY,IAAI;KAAG,GAAG,MAAM,EAAE;IAAC,CAAC;GAC3G;GACA,KAAK,MAAM,MAAM,MAAM,IAAI;IACzB,MAAM,QAAQ,QAAQ,OAAO,UAAU,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG;IAC3D,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB,SAAS,QAAQ,cAAc;KAAS;KAAO,GAAG,YAAY,IAAI;KAAG,GAAG,MAAM,EAAE;IAAC,CAAC;GAC7I;GACA,OAAO,MAAM,QAAQ,IAAI;IACvB,MAAM,UAAU,MAAM,UAAU,SAAS,IAAI,IAAI,MAAM,SAAS,WAAW,MAAM,SAAS;IAC1F,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB;KAAU;KAAS;KAAQ,GAAG,MAAM,EAAE;IAAC,CAAC;GACnG;GACA,MAAM,QAAQ,QAAQ;IACpB,MAAM,OAAO,IAAI,MAAM,GAAG;KAAC;KAAM;KAAM,GAAG,MAAM,SAAS,OAAO;IAAmC,CAAC;IACpG,MAAM,UAAU,KAAK,IAAI;IACzB,OAAQ,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,EAAE,MAAO,QAAQ;KAC/D,IAAI,KAAK,IAAI,IAAI,UAAU,KAAQ,MAAM,IAAI,MAAM,GAAG,OAAO,qBAAqB;KAClF,MAAMA,QAAM,GAAG;IACjB;GACF;GACA,SAAS,aAAa;IACpB,MAAM,WAAW,MAAM,UAAU;IACjC,OAAO,QAAQ,WAAW,QAAQ,GAAG;KACnC;KACA;KACA,aAAa,MAAM;KACnB;KACA;KACA,MAAM;KACN,GAAI,cAAc,CAAC,aAAa,IAAI,CAAC;IACvC,CAAC;GACH;GACA,MAAM,SAAS;IACb,MAAM,OAAO,OAAO;KAAC;KAAM;KAAe;KAAS;IAAK,CAAC;GAC3D;GACA,MAAM,SAAS;IACb,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,QAAQ,MAAM,IAAI,SAA8B,YAAY;KAChE,MAAM,UAAU,KAAK,IAAI;KACzB,MAAM,aAAa;MACjB,MAAM,OAAO,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,WAAW,OAAO,OAAO,OAAO;MAC5E,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI;WAC/B,IAAI,KAAK,IAAI,IAAI,UAAU,KAAO,QAAQ,IAAI;WAC9C,WAAW,MAAM,EAAE;KAC1B;KACA,KAAK;IACP,CAAC;IACD,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM,WAAW,CAAC;GAC1D;GACA,MAAM,SAAS,SAAS;IACtB,MAAM,SAAS,MAAM,OAAO,OAAO,CAAC,QAAQ,iBAAiB,CAAC,CAAC,CAAC,YAAY,EAAE;IAC9E,MAAM,UAAU,OAAO,cACrB,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC;IACxE,MAAM,iBAAiB,OAAO,SAAiB;KAC7C,MAAM,OAA+B,CAAC;KAEtC,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,cAAc,GAAG,KAAK,QAAQ,MAAM,IAAI,MAAM;MAAC;MAAU;MAAO;KAAG,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,MAAM;KAC7H,OAAO;IACT;IACA,MAAM,mBAAmB,OAAO,SAAiB;KAC/C,MAAM,SAAS,SAAS,MAAM,IAAI,MAAM;MAAC;MAAY;MAAU,MAAM;KAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;KACpF,MAAM,OAA+B,EAAE,QAAQ,OAAO,aAAa,GAAG;KACtE,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,gBAAgB,GAAG,KAAK,OAAO,OAAO,QAAQ;KAClF,OAAO;IACT;IACA,MAAM,UAAU,CAAC;IACjB,KAAK,MAAM,QAAQ,MAAM,SACvB,QAAQ,KAAK;KAAE;KAAM,IAAI,MAAM,QAAQ,KAAK,CAAE;KAAI,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,EAAA,CAAG;KAAO,UAAU,MAAM,eAAe,IAAI;IAAE,CAAC;IAChI,MAAM,YAAY,CAAC;IACnB,KAAK,MAAM,QAAQ,MAAM,WACvB,UAAU,KAAK;KAAE;KAAM,IAAI,MAAM,UAAU,KAAK,CAAE;KAAI,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,EAAA,CAAG;KAAO,UAAU,MAAM,iBAAiB,IAAI;IAAE,CAAC;IACtI,OAAO;KACL,QAAQ,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAC5C,cAAc,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAClD,IAAI,qBAAqB,KAAK,MAAM,CAAC,GAAG,MAAM;KAC9C,SAAS,MAAM,OAAO,QAAQ,CAAC,OAAO,iCAAiC,CAAC;KACxE,QAAQ,GAAG,QAAQ,KAAK,iBAAiB,cAAc,MAAM,QAAQ,KAAK,iBAAiB;KAC3F,QAAQ;MAAE,OAAO,MAAM;MAAO,IAAI,QAAQ,EAAE,CAAE;MAAI,UAAU,QAAQ,EAAE,CAAE;MAAU,SAAS,CAAC;KAAE;KAC9F,SAAS;MACP;MACA,KAAK,MAAM,QAAQ,MAAM,EAAA,CAAG;MAC5B,WAAW,MAAM,OAAO,QAAQ;OAAC;OAAO;OAAQ;MAAI,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,KAAK;MACzE,GAAG,cAAc;KACnB;KACA,QAAQ,oBAAoB,WAAW,IAAI;KAC3C,OAAO;MAAE,QAAQ;MAAa,QAAQ,MAAM,QAAQ,MAAM,CAAE;KAAM;KAClE;KACA,OAAO;MAAE;MAAS;MAAW,UAAU,EAAE,OAAO,KAAK;KAAE;IACzD;GACF;GACA;EACF;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM;CACR;AACF;;AAOA,MAAMC,WAAS;;AAEf,MAAMC,YAAU;;AAGhB,MAAM,aAAa,KAAe,WAA2B,GAAG,IAAI,QAAQ,OAAO,CAAE,GAAG,GAAG,IAAI,MAAM;;AAGrG,MAAa,cAAc,SAAuB;CAChD,MAAM,EAAE,eAAe;CAOvB,QALE,WAAW,YAAY,OACnB,QAAQ,WAAW,MAAM,GAAG,IAC5B,WAAW,YAAY,SAAS,WAAW,aAAa,KAAA,IACtD,QAAQ,WAAW,SAAS,MAAM,GAAG,IACrC,QAAQ,WAAW,QAAQ,GAAG,KACrB,MAAQ;AAC3B;;;;;;AAOA,MAAa,WAAW,MAAc,SACpC,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,QAAQ,OAAO,IAAI,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,UAAU,OAAO,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACtH,QAAQ,MAAM,OAAO,UAAU,CAAC,KAAK,IAAI,CAAC,CAAC,CAC3C,MAAM,GAAG,MAAM,IAAI,CAAC;;AAGzB,MAAM,cAAc,MAAY,QAA4B;CAC1D,MAAM,YAAY,KAAK,MAAO,UAAU,KAAK,SAAS,GAAG,IAAI,UAAU,KAAK,CAAE,GAAG,GAAG,KAAK,MAAO,cAAc;CAC9G,MAAM,SAAS,KAAK,MAAM,QAAQ,SAAS,YAAY,KAAK,MAAM,SAAS,KAAA;CAC3E,OAAO;EACL;EACA,UAAU,KAAK,GAAG;EAClB;EACA,KAAK,MAAO;EACZ;EACA,OAAO,KAAK,MAAM,aAAa,KAAA,IAAY,KAAK,QAAQ,KAAK,MAAM,UAAU,IAAI,CAAC;EAClF;EACA,OAAO,KAAK,KAAK,WAAW,IAAI,IAAI,MAAQ,GAAG,CAAC;EAChD,GAAI,KAAK,kBAAkB,KAAA,IAAY,CAAC,IAAI,CAAC,aAAa,KAAK,UAAU,KAAK,aAAa,CAAC;EAC5F,GAAI,QAAQ,OAAO,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,OAAO,EAAE;EACtD,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,CAAC,YAAY,OAAO,OAAO,MAAM,CAAC;CAC5E;AACF;;AAGA,MAAMC,aACJ,QACA,OACA,WAEA,IAAI,SAAS,YAAY;CACvB,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,aAAa;EACjB,MAAM,QAAQ,OAAO,OAAO,KAAK,KAAK;EACtC,IAAI,UAAU,KAAA,KAAa,KAAK,IAAI,IAAI,UAAU,QAAQ,QAAQ,KAAK;OAClE,WAAW,MAAM,EAAE;CAC1B;CACA,KAAK;AACP,CAAC;;AAGH,MAAa,mBAAmB,aAAwD;CACtF,MAAM,yBAAS,IAAI,IAA2B;CAC9C,KAAK,MAAM,QAAQ,UAAU,IAAI,KAAK,OAAO,cAAc,OAAO,IAAI,OAAO,KAAK,QAAQ,GAAG,IAAI;CACjG,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;;AAGA,MAAMC,kBAAgB,YAA6C;CACjE,KAAK,IAAI,KAAK,QAAQ,SAAS,GAAG,MAAM,GAAG,MAAM,GAC/C,IAAI,QAAQ,GAAG,CAAE,OAAO,SAAS,OAAO,OAAO,QAAQ,GAAG,CAAE,WAAW,CAAC;CAC1E,OAAO;AACT;;;;;;;;;;;;AAaA,MAAa,YAAY,OAAO,KAAe,MAAY,aAAqB,UAAgC;CAC9G,MAAM,QAAQ,KAAK;CACnB,MAAM,UAAU,MAAM,IAAI,SAAS;CACnC,MAAM,IAAI,MAAM,OAAO;CACvB,MAAM,IAAI,OAAO;CACjB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,eAAe,IAAI,SAAS;CAClC,MAAM,aAAaA,eAAa,IAAI,MAAM;CAC1C,MAAM,SAAS,MAAM,IAAI,OAAO,WAAW,MAAM,GAAG,CAAC;CACrD,MAAM,QAAQ,KAAK,WAAW,OAAO,SAAS;CAC9C,MAAM,QAAS,KAAK,WAAW,EAAE,MAAM,UAAU;CACjD,IAAI,QAAsB;CAC1B,IAAI,OAAoB;CACxB,IAAI,KAAoB;CACxB,MAAM,OAAsC,CAAC;CAC7C,IAAI;EACF,MAAM,OAAO,MAAM,CAAC,OAAO,GAAG,GAAM;EAEpC,IAAI,MADiBD,UAAQ,SAAS,UAAU,MAAM,OAAO,SAAS,OAAO,MAAM,IAAI,KAAKF,UAAQ,GAAM,MAC3F,KAAA,GAAW,MAAM,IAAI,MAAM,4BAA4BA,SAAO,eAAe;EAC5F,IAAI,UAAuC;EAC3C,QAAQ,KAAK,OAAb;GACE,KAAK;GACL,KAAK;GACL,KAAK,OAAO;IACV,MAAM,OAAO,KAAK,UAAU,QAAQ,QAAQ;IAC5C,MAAM,OAAO,MAAM,SAAS,KAAK,UAAU,cAAc,UAAU;IACnE,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,OAAO;IAC3C,KAAK;IACL,QAAQ,MAAM,IAAI,MAAM,MAAM,MAAM,IAAI;IACxC,KAAK,WAAW,IAAI,KAAK,MAAM,MAAM,IAAI,CAAC;IAC1C,IAAI,KAAK,UAAU,KAAA,GAAW;KAE5B,MAAM,KAAK,MAAM;KACjB,MAAM,OAAO,MAAME,UAAQ,SAAS,UAAU,MAAM,OAAO,UAAU,MAAM,IAAI,IAAI,GAAK;KACxF,IAAI,SAAS,KAAA,GAAW,UAAU,IAAI,KAAK,MAAM,MAAM,MAAM,KAAK,IAAI,QAAQ,KAAK,OAAO,GAAG,IAAI,GAAG;IACtG,OAAO,IAAI,KAAK,SAAS,KAAA,GACvB,UAAU,IAAI,KAAK,MAAM,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;IAE/E;GACF;GACA,KAAK,kBAAkB;IACrB,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,OAAO;IAC3C,KAAK;IACL,QAAQ,MAAM,IAAI,OAAO,MAAM,MAAM;IACrC,KAAK,WAAW,IAAI,OAAO,MAAM,MAAM,CAAC;IACxC,IAAI,KAAK,SAAS,KAAA,GAAW,UAAU,IAAI,OAAO,MAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;IACxG;GACF;GACA,KAAK,OAAO;IACV,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,OAAO;IAC3C,KAAK;IACL,QAAQ,MAAM,IAAI,OAAO,MAAM,MAAM;IACrC,IAAI,MAAM,QAAQ,SAAS,IAAI,GAAG,KAAK,WAAW,IAAI,QAAQ,IAAI,CAAC;IACnE;GACF;GACA,KAAK;IACH,QAAQ,MAAM,IAAI,SAAS,KAAK,gBAAgB,IAAI;IACpD;GACF,SACE,MAAM,IAAI,MAAM,6BAA6B,KAAK,OAAO;EAC7D;EAEA,MAAM,SACJ,YAAY,OACR,QAAQ,QAAQ,IAAI,IACpB,QAAQ,MAAM,UAAU;GACtB,OAAO;GAEP,KAAK,SAAS;GACd,OAAO;EACT,CAAC;EAEP,OAAO,YAAY,KAAA,CAAS;EAC5B,MAAM,KAAK,MAAM;EACjB,MAAM,MAAM,UAAU,KAAK,OAAO;EAClC,MAAM,WAAW,WAAW,IAAI;EAahC,KAXE,UAAU,QACN,MAAMA,UACJ,SACC,UAAU,MAAM,OAAO,SAAS,MAAM,IAAI,MAAM,OAAO,MAAM,UAAU,YAAY,MAAM,UAAU,KACpG,QACF,IACA,OAAO,YAAY;GACjB,MAAM;GACN,MAAM,QAAS,MAAsB,MAAM;GAC3C,OAAOA,UAAQ,SAAS,UAAU,MAAM,OAAO,SAAS,MAAM,IAAI,OAAO,QAAQ;EACnF,EAAA,CAAG,OACO,KAAA,GAAW,MAAMH,QAAME,SAAO;EAC9C,MAAM;CACR,UAAU;EAER,KAAK,MAAM,QAAQ,KAAK,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;EACrE,MAAM,OAAO,KAAK;CACpB;CACA,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,MAAM,OAAO,YAAY,OAAO,OAAO,UAAU;CACjD,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,CAAC,YAAY,IAAI;CACnD,MAAM,QAAQ,UAAU,OAAO,OAAO,MAAM,IAAI,MAAM,KAAK;CAI3D,IAAI,IAAI,SAAS,MAAM,YAAY,CAAC,CAAC,MAAM,SAAS,KAAK,OAAO,cAAc,OAAO,KAAK,KAAK,CAAC,CAAC,WAAW,iBAAiB,CAAC,GAC5H,MAAM,IAAI,MAAM;CAClB,OAAO;EACL;EACA;EACA,QAAQ,CAAC,GAAG,OAAO,MAAM;EACzB;EACA,GAAI,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK;EAChC,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,QAAQ,QAAQ,CAAE;EACnC;EACA,OAAO;GACL,SAAS,IAAI;GACb,WAAW,IAAI;GACf;GACA;GAGA,UAAU,CAAC,GAAG,gBAAgB,IAAI,SAAS,MAAM,GAAG,YAAY,CAAC,GAAG,GAAG,IAAI,SAAS,MAAM,YAAY,CAAC;GACvG;GACA;EACF;CACF;AACF;;;;ACzrBA,MAAa,uBAA4B,IAAI,IAAI;CAAC;CAAQ;CAAW;CAAY;CAAY;AAAS,CAAC;;AAGvG,MAAa,gBAAgB,QAAgB,SAAoC;CAC/E,IAAI,CAAC,KAAK,WAAW,GAAG,GAAG,OAAO;CAClC,IAAI;CACJ,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,QAAQ;EACN,OAAO;CACT;CACA,MAAM,OAAO,KAAK,MAAM,KAAK,GAAG,SAAS,EAAE;CAC3C,IAAI,CAAC,OAAO,SAAS,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,KAAK,EAAE,GAAG,OAAO;CAC9D,OAAO;EAAE,IAAI;EAAU,GAAG;EAAG;EAAQ;EAAM,IAAI,OAAO,KAAK,MAAM,CAAC;EAAG,GAAG,KAAK,KAAK;EAAI,KAAK,KAAK,OAAO;EAAI,MAAM,KAAK,QAAQ,CAAC;CAAE;AACnI;;;;;;AAOA,MAAa,iBAAiB,WAAiD;CAC7E,MAAM,UAAU,OAAO,QAAQ,UAAU,MAAM,OAAO,QAAQ,CAAC,CAAC,KAAK,UAAU,OAAO,MAAM,OAAO,IAAI,MAAM,MAAM,CAAC;CACpH,OAAO,QAAQ,WAAW,IAAI,OAAO,KAAK,IAAI,GAAG,OAAO;AAC1D;;AAGA,MAAa,eAAe,KAA4B,WACtD,IAAI,KAAK,UAAU;CAAE,GAAG;CAAM,GAAG,WAAW,OAAO,IAAI,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM;AAAE,EAAE;;;;;;;AAchG,MAAa,SACX,KACA,SACA,QACA,MACA,SACQ;CACR,MAAM,SAAS,IAAI,QAAQ,QAAQ,SAAS,SAAS,IAAI,CAAC,CAAC,KAAK,SAAS,QAAQ,KAAK,CAAE,EAAE;CAC1F,IAAI,SAAS,WAAW,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE;CACjD,IAAI,SAAS,SAAS,OAAO,EAAE,OAAO,OAAO;CAC7C,IAAI,SAAS,OAAO,OAAO,EAAE,OAAO,OAAO,MAAM,GAAG,CAAC,EAAE;CACvD,IAAI,SAAS,WAAW,OAAO;EAAE,OAAO,OAAO,MAAM,GAAG,CAAC;EAAG,WAAW;CAAM;CAC7E,IAAI,SAAS,cAAc,OAAO;EAAE,OAAO,CAAC,MAAM;EAAG,WAAW;CAAM;CACtE,OAAO,EAAE,OAAO,CAAC,GAAG,QAAQ,MAAM,EAAE;AACtC;;AAGA,MAAa,iBAAiB,QAC5B,GAAG,IAAI,SAAS,OAAO,aAAa,IAAI,KAAK,wBAAwB,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,EAAA,CAAG,KAAK,GAAG,IAAI,KAAK;;AAGrH,MAAa,kBAAkB,KAAiB,QAAkD;CAChG,MAAM,SAAS;EACb,KAAK,IAAI;EACT,SAAS,IAAI,QAAQ,KAAK,MAAM,QAAQ;GAAE,KAAK;GAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI;EAAO,EAAE;EACtF,UAAU,IAAI;CAChB;CACA,OAAO,oCAAoC,KAAK,UAAU,MAAM,EAAE;AACpE;;AAGA,MAAa,gBACX;;;;;;AAeF,MAAa,gBAAgB,KAAiB,KAAuC,WAA8B;CACjH,MAAM,YAAY,IAAI,IAAI,IAAI,QAAQ,KAAK,SAAS,CAAC,GAAG,IAAI,MAAM,GAAG,IAAI,QAAQ,IAAI,CAAC,CAAC;CACvF,MAAM,YAAY,OAAO,QAAQ,QAAQ,WAAW,OAAO,UAAU,SAAS;CAC9E,IAAI,UAAU,WAAW,GAAG,OAAO;EAAE,SAAS;EAAM,SAAS;EAAO,KAAK,eAAe,UAAU,OAAO;CAAY;CACrH,MAAM,UAAU,UAAU,IAAI,UAAU,EAAE,CAAE,IAAI,KAAK;CACrD,IAAI,YAAY,MAAM,OAAO;EAAE,SAAS;EAAM,SAAS;EAAO,KAAK,6BAA6B,UAAU,EAAE,CAAE;CAAO;CACrH,IAAI,OAAO,OAAO,UAAU,EAAE,CAAE,QAAQ,CAAC,OAAO,UAAU,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,GAAG,QAAQ;CAA6B;CACzI,IAAI,OAAO,QAAQ,WAAW,IAAI,QAAQ,QAAQ,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,eAAe,OAAO,QAAQ,OAAO;CAAU;CACxI,KAAK,MAAM,UAAU,OAAO,SAAS;EACnC,IAAI,OAAO,WAAW,GAAG,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,GAAG,OAAO,KAAK;EAAiB;EAChG,IAAI,OAAO,UAAU,aAAa,OAAO,UAAU,aAAa,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,GAAG,OAAO,KAAK,MAAM,OAAO;EAAQ;EAC3I,IAAI,OAAO,WAAW,UAAU,EAAE,CAAE,QAAQ,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,GAAG,OAAO,KAAK;EAAwB;CAC5H;CACA,OAAO;EAAE;EAAS,SAAS;EAAM,KAAK;CAAU;AAClD;;AAsDA,MAAaG,WAAS,OAA8B,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;;AAGpG,MAAa,YAAY;CAAE,SAAS;CAAI,SAAS;AAAG;;;;;;;;;;;;AAapD,MAAa,oBAAoB,OAAO,KAAiB,UAAU,UAAkC;CACnG,MAAM,QAAQ,MAAM,aAAa;CACjC,MAAM,QAAQ,MAAM,iBAAiB;CACrC,MAAM,EAAE,kBAAkB,SAAS,MAAM,8BAA8B,MAAM,WAAW;CACxF,MAAM,UAAU,MAAM,0BAA0B;CAChD,MAAM,SAAiC,CAAC;CACxC,IAAI;CACJ,MAAM,QAAQ,YAAY;EACxB,KAAK,MAAM,aAAa,OAAO,QAAQ,GAAG,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC,YAAY,KAAA,CAAS;EAC1F,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;CAC7C;CACA,MAAM,OAAO,OAAO,cAAqD;EAEvE,MAAM,MAAK,MADQ,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC,EAAA,CACzE,gBAAgB,SAAS,QAAS,QAAQ,EAAE,EAAE;EAC9D,IAAI,OAAO,KAAA,KAAa,OAAO,IAAI,MAAM,IAAI,MAAM,GAAG,UAAU,QAAQ,EAAE,qBAAqB,QAAS,QAAQ,GAAG;EACnH,OAAO;CACT;CACA,IAAI;EACF,UAAU,MAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;EACpC,MAAM,wBAAQ,IAAI,IAAkC;EACpD,MAAM,4BAAY,IAAI,IAAkC;EACxD,MAAM,UAAmC,CAAC;EAC1C,MAAM,MAAoB,CAAC;EAC3B,KAAK,MAAM,QAAQ,IAAI,SAAS;GAC9B,IAAI,UAAU;GACd,MAAM,MAAM,MAAM,IAAI,iBAAiB,IAAI,KAAK,CAAC,CAC9C,YAAY,OAAO,CAAC,CACpB,mBAAmB,IAAI,CAAC,CACxB,YAAY;IAAC;IAAM;IAAM,GAAG,cAAc,GAAG,EAAE;GAA2D,CAAC,CAAC,CAC5G,iBAAiB,KAAK,cAAc,IAAI,KAAK,CAAC,CAAC,CAC/C,iBAAiB,WAChB,OAAO,GAAG,SAAS,UAA2B;IAC5C,WAAW,MAAM,SAAS;IAC1B,MAAM,QAAQ,QAAQ,MAAM,IAAI;IAChC,UAAU,MAAM,IAAI,KAAK;IACzB,KAAK,MAAM,QAAQ,OAAO;KACxB,MAAM,OAAO,aAAa,MAAM,KAAK,KAAK,CAAC;KAC3C,IAAI,SAAS,MAAM,IAAI,KAAK,IAAI;IAClC;GACF,CAAC,CACH,CAAC,CACA,MAAM;GACT,OAAO,KAAK,GAAG;GACf,MAAM,IAAI,MAAM,GAAG;GACnB,MAAM,WAAW,MAAM,QACrB,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC,sBAAsB,aAAa,SAAS,GACpH,aAAa,IAAI,MAAM,GACzB,CAAC,CAAC,MAAM;GACR,OAAO,KAAK,QAAQ;GACpB,UAAU,IAAI,MAAM,QAAQ;GAC5B,QAAQ,QAAQ;IAAE,IAAI,MAAM,KAAK,GAAG;IAAG,OAAO,MAAM,QAAQ,QAAQ;GAAE;EACxE;EACA,MAAM,MAA8B,OAAO,YAAY,OAAO,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;EAEjH,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,YAAY,OAAO,CAAC,CAAC,MAAM;EAC5E,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAC,MAAM;EAC1H,OAAO,KAAK,KAAK;EACjB,MAAM,WAAW,MAAM,KAAK,MAAM;EAElC,MAAM,YAAY,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAChD,YAAY,OAAO,CAAC,CACpB,YAAY;GAAC;GAAM;GAAM;EAA8B,CAAC,CAAC,CACzD,MAAM;EACT,OAAO,KAAK,SAAS;EACrB,MAAM,aAAa,UACf,MAAM,IAAI,iBAAiB,IAAI,KAAK,CAAC,CAAC,YAAY,OAAO,CAAC,CAAC,YAAY;GAAC;GAAM;GAAM;EAA8B,CAAC,CAAC,CAAC,MAAM,IAC3H;EACJ,IAAI,eAAe,MAAM,OAAO,KAAK,UAAU;EAE/C,MAAM,cAAc,MAAM,QAAQ,KAAK;EACvC,MAAM,UAAU,MAAoB;EACpC,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC7C,mBAAmB,CAAC,CACpB,gBAAgB,MAAM,CAAC,CACvB,YAAY,CAAC,uBAAuB,OAAO,WAAW,CAAC,CAAC,CAAC,CACzD,gBAAgB,QAAQ,OAAO,CAAC,CAChC,MAAM;EACT,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,QAAQ,MAAM,CAAC,SAAS,MAAM,GAAG,KAAQ,QAAQ;EACrE,IAAI,MAAM,OAAO,QAAQ,MAAM,IAAI,MAAM,sBAAsB,OAAO,MAAM,MAAM,GAAG;EAErF,MAAM,OAAO,SAAuC;GAClD,MAAM,QAAQ,MAAM,IAAI,IAAI;GAC5B,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,yBAAyB,MAAM;GACxE,OAAO;EACT;EACA,MAAM,cAAc,SAAuC;GACzD,MAAM,QAAQ,UAAU,IAAI,IAAI;GAChC,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,yBAAyB,MAAM;GACxE,OAAO;EACT;;EAEA,MAAM,SAAS,MAAc,QAAgB,OAAe,IAAI,SAC9D,OAAO,IAAI,IAAI,GAAG;GAChB,IAAI,SAAS;GACb;GACA;GACA,uBAAuB,KAAK;GAC5B;GACA;EACF,CAAC;EACH,MAAM,YAAY,SAAyB,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,SAAS,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK;EAC3G,MAAM,UAAU,OAAO,OAA6B,SAAmC;GACrF,MAAM,QAAQ,KAAK,MAAM,SAAS,MAAM,OAAO,OAAO,IAAI,CAAC,CAAC;GAC5D,OAAO;IAAE,IAAI,MAAM;IAAI,IAAI,MAAM;GAAG;EACtC;EACA,MAAM,SAAS,OAAsC,OAAO,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;EAC5G,IAAI,QAAgB,IAAI,QAAQ;;EAEhC,MAAM,OAAO,YAAgC;GAC3C,IAAI,OAAkB;IAAE,SAAS;IAAM,SAAS;IAAO,KAAK;GAAqB;GACjF,KAAK,MAAM,QAAQ,CAAC,OAAO,GAAG,IAAI,QAAQ,QAAQ,SAAS,SAAS,KAAK,CAAC,GAAG;IAC3E,MAAM,OAAO,MAAM,MAAM,MAAM,aAAa,CAAC,CAC1C,MAAM,SAAS,aAAa,KAAK,KAAK,KAAK,MAAM,SAAS,IAAI,CAAC,CAAW,CAAC,CAAC,CAC5E,OAAO,WAAoB;KAAE,SAAS;KAAM,SAAS;KAAO,KAAK,GAAG,KAAK,IAAK,MAAgB,QAAQ,MAAM,GAAG,GAAG;IAAI,EAAE;IAC3H,IAAI,KAAK,YAAY,QAAQ,KAAK,YAAY,MAAM,OAAO;IAC3D,OAAO;GACT;GACA,OAAO;EACT;EACA,MAAM,WAAW,OAAO,SAAS,gBAAiC;GAChE,MAAM,UAAU,KAAK,IAAI;GACzB,IAAI,OAAO;GACX,IAAI,OAAkB;IAAE,SAAS;IAAM,SAAS;IAAO,KAAK;GAAc;GAC1E,OAAO,KAAK,IAAI,IAAI,UAAU,QAAQ;IACpC,OAAO,MAAM,KAAK;IAElB,OAAO,KAAK,UAAU,OAAO,IAAI;IACjC,IAAI,KAAK,YAAY,MAAM,QAAQ,KAAK;IACxC,IAAI,QAAQ,KAAK,KAAK,YAAY,MAAM,OAAO,KAAK;IACpD,MAAMA,QAAM,GAAK;GACnB;GACA,MAAM,IAAI,MAAM,+BAA+B,OAAO,OAAO,KAAK,KAAK;EACzE;EAGA,MAAM,YAAY,MAAM,MAAM,IAAI,QAAQ,IAAK,eAAe,KAAK,GAAG,CAAC;EACvE,IAAI,CAAC,SAAS,SAAS,CAAC,CAAC,SAAS,UAAQ,GAAG,MAAM,IAAI,MAAM,uBAAuB,SAAS,SAAS,GAAG;EACzG,MAAM,SAAS;EAEf,OAAO;GACL;GACA;GACA;GACA,OAAO,EAAE,QAAQ,YAAY;GAC7B,QAAQ,QAAQ;GAChB;GACA,MAAM,OAAO,QAAQ;IACnB,MAAM,WAAW,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO;IAC/E,IAAI,SAAS,SAAS,GAAG,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;KAAM,GAAG;IAAQ,CAAC;IAChF,MAAM,OAA+B,CAAC;IACtC,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG,KAAK,OAAO,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;IAAG,CAAC;IAC5F,OAAO;GACT;GACA;GACA,MAAM,MAAM,SAAS;IACnB,MAAM,SACJ,4EAA4E,IAAI,QAAQ,OAAO;IAEjG,MAAM,QAAQ,SAAS,MAAM,MAAM,SAAS,MAAM,CAAC;IACnD,IAAI,CAAC,MAAM,SAAS,aAAW,GAAG,MAAM,IAAI,MAAM,qBAAqB,OAAO;GAChF;GACA,MAAM,SAAS,SAAS;IACtB,KAAK,MAAM,QAAQ,IAAI,SAAS;KAC9B,IAAI,SAAS,SAAS;KACtB,MAAM,QAAQ,SAAS,MAAM,MAAM,MAAM,qCAAqC,CAAC;KAC/E,IAAI,CAAC,MAAM,SAAS,UAAQ,GAAG,MAAM,IAAI,MAAM,GAAG,KAAK,qBAAqB,OAAO;IACrF;GACF;GACA,MAAM,MAAM,SAAS;IAGnB,OADa,KAAK,MAAM,SAAS,MAAM,MAAM,SAAS,0GAAM,CAAC,CACnD,CAAC,CACR,IAAI,MAAM,CAAC,CACX,QAAQ,MAAM,OAAO,UAAU,CAAC,KAAK,IAAI,CAAC,CAAC,CAC3C,MAAM,GAAG,MAAM,IAAI,CAAC;GACzB;GACA,OAAO,MAAM,SAAS;IACpB,IAAI,SAAS,WAAW,OAAO;IAC/B,IAAI,SAAS,YAAY,MAAM,IAAI,MAAM,+BAA+B;IACxE,MAAM,YAAY,IAAI,QAAQ,MAAM,SAAS,SAAS,OAAO;IAC7D,IAAI,cAAc,KAAA,GAAW,MAAM,IAAI,MAAM,0BAA0B;IACvE,OAAO;GACT;GACA,MAAM,OAAO,MAAM;IACjB,MAAM,SAAS,MAAkB;IACjC,MAAM,YAAY,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAChD,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,YAAY;KAAC;KAAQ;KAAuC,GAAG;IAAI,CAAC,CAAC,CACrE,gBAAgB,OAAO,OAAO,CAAC,CAC/B,MAAM;IACT,OAAO;KACL,QAAQ,OAAO;KACf,QAAQ,OAAO,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAQ;KAE9D,YACE,UACG,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CACpB,WAAW,KAAA,CAAS,CAAC,CACrB,YAAY,KAAA,CAAS;IAC5B;GACF;GACA,MAAM,MAAM,MAAM,MAAM,IAAI;IAC1B,MAAM,MAAM,MAAM,KAAK,SAAS,UAAU,MAAM,IAAI;IACpD,MAAM,YAAY,IAAI,cAAc,KAAA,IAAY,CAAC,IAAI,CAAC,eAAe,IAAI,SAAS;IAClF,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB;KAAM,IAAI,MAAM,KAAK,GAAG;KAAG,GAAG;KAAW,GAAG,MAAM,EAAE;IAAC,CAAC;GACjH;GACA,KAAK,MAAM,MAAM,MAAM,IAAI;IACzB,MAAM,MAAM,MAAM,KAAK,SAAS,UAAU,MAAM,IAAI;IACpD,MAAM,YAAY,IAAI,cAAc,KAAA,IAAY,CAAC,IAAI,CAAC,eAAe,IAAI,SAAS;IAClF,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB,SAAS,QAAQ,cAAc;KAAS,IAAI,MAAM,KAAK,GAAG;KAAG,GAAG;KAAW,GAAG,MAAM,EAAE;IAAC,CAAC;GACnJ;GACA,OAAO,MAAM,QAAQ,IAAI;IACvB,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB;KAAU,IAAI,SAAS;KAAQ;KAAQ,GAAG,MAAM,EAAE;IAAC,CAAC;GAC/G;GACA,MAAM,QAAQ,QAAQ;IAEpB,MAAM,OAAO,IAAI,MAAM,GAAG;KAAC;KAAM;KAAM,GAAG,cAAc,GAAG,EAAE;IAAiD,CAAC;IAC/G,MAAM,UAAU,KAAK,IAAI;IACzB,OAAO,EAAE,MAAM,MAAM,QAAQ,sBAAsB,CAAC,CAAC,YAAY,EAAE,EAAA,CAAG,SAAS,GAAG,GAAG;KACnF,IAAI,KAAK,IAAI,IAAI,UAAU,KAAQ,MAAM,IAAI,MAAM,GAAG,OAAO,qBAAqB;KAClF,MAAMA,QAAM,GAAG;IACjB;GACF;GACA,KAAK,QAAQ,MAAM;IACjB,OAAO,OAAO,IAAI,MAAM,GAAG,IAAI;GACjC;GACA,QAAQ;GACR,MAAM,MAAM;IACV,IAAI,eAAe,MAAM,MAAM,IAAI,MAAM,6BAA6B;IACtE,OAAO,OAAO,YAAY,IAAI;GAChC;GACA,SAAS,SAAS;IAChB,OAAO,QAAQ,WAAW;KACxB;KACA;KACA,GAAG,QAAQ,QAAQ,CAAE,GAAG,GAAG,IAAI;KAC/B,OAAO,UAAU,OAAO;KACxB,OAAO,UAAU,OAAO;IAC1B,CAAC;GACH;GACA,MAAM,SAAS;IACb,MAAM,OAAO,OAAO;KAAC;KAAM;KAAe;KAAS;IAAK,CAAC;GAC3D;GACA,MAAM,SAAS;IACb,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,QAAQ,MAAM,IAAI,SAA8B,YAAY;KAChE,MAAM,UAAU,KAAK,IAAI;KACzB,MAAM,aAAa;MACjB,MAAM,OAAO,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,WAAW,OAAO,OAAO,OAAO;MAC5E,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI;WAC/B,IAAI,KAAK,IAAI,IAAI,UAAU,KAAO,QAAQ,IAAI;WAC9C,WAAW,MAAM,EAAE;KAC1B;KACA,KAAK;IACP,CAAC;IACD,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM,WAAW,CAAC;GAC1D;GACA,MAAM,SAAS,SAAS;IACtB,MAAM,SAAS,MAAM,OAAO,OAAO,CAAC,QAAQ,iBAAiB,CAAC,CAAC,CAAC,YAAY,EAAE;IAC9E,MAAM,UAAU,OAAO,cAAoC,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC;IACjI,MAAM,SAAS;IACf,MAAM,OAAO,CAAC;IACd,KAAK,MAAM,QAAQ,IAAI,SAAS;KAC9B,MAAM,OAAO,KAAK,MAAM,SAAS,MAAM,MAAM,MAAM,MAAM,CAAC,CAAC;KAC3D,MAAM,WAAmC,EAAE,SAAS,KAAK,QAAQ;KACjE,KAAK,MAAM,OAAO,OAAO,KAAK,IAAI,QAAQ,GAAG,SAAS,OAAO,OAAO,KAAK,SAAS,QAAQ,EAAE;KAC5F,KAAK,KAAK;MAAE;MAAM,IAAI,QAAQ,KAAK,CAAE;MAAI,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,EAAA,CAAG;MAAO;KAAS,CAAC;IAC3F;IACA,OAAO;KACL,QAAQ,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAC5C,cAAc,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAClD,IAAI,qBAAqB,KAAK,MAAM,CAAC,GAAG,MAAM;KAC9C,SAAS,MAAM,OAAO,QAAQ,CAAC,OAAO,iCAAiC,CAAC;KACxE,WAAW,cAAc,IAAI;KAC7B,QAAQ,GAAG,QAAQ,KAAK,iBAAiB,cAAc,MAAM,QAAQ,KAAK,iBAAiB;KAC3F,QAAQ;MAAE,OAAO,IAAI;MAAO,IAAI,KAAK,EAAE,CAAE;MAAI,UAAU,KAAK,EAAE,CAAE;MAAU,SAAS,CAAC;KAAE;KACtF,SAAS;MACP;MACA,KAAK,MAAM,QAAQ,MAAM,EAAA,CAAG;MAC5B,WAAW,MAAM,OAAO,QAAQ;OAAC;OAAO;OAAQ;MAAI,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,KAAK;MACzE,GAAG,cAAc;KACnB;KACA,QAAQ,oBAAoB,WAAW,KAAK;KAC5C,OAAO;MAAE,QAAQ;MAAa,QAAQ,QAAQ,IAAI,QAAQ,GAAI,CAAE;KAAM;KACtE;KACA,OAAO;MAAE,SAAS;MAAM,WAAW,CAAC;MAAG,UAAU,EAAE,OAAO,MAAM;KAAE;IACpE;GACF;GACA;EACF;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM;CACR;AACF;;AASA,MAAaE,YAAU;;AAGvB,MAAa,eAAe,SAAuBA,aAAW,KAAK,UAAU,KAAA,IAAY,IAAI,QAAQ,KAAK,OAAO,GAAG,IAAI;;AAGxH,MAAa,kBAAkB,MAAY,YAAyD;CAClG,MAAM,MAAM,KAAK;CACjB,MAAM,QAAQ,IAAI,QAAQ,KAAK,SAAS,GAAG,QAAQ,KAAK,CAAE,GAAG,GAAG,IAAI,MAAM;CAC1E,OAAO;EACL,QAAQ,IAAI,QAAQ,GAAI,CAAE;EAC1B,OAAO,IAAI,IAAI;EACf;EACA;EACA;EACA,MAAM,KAAK,GAAG;EACd;EACA,IAAI;EACJ;EACA,OAAO,KAAK,MAAM,aAAa,KAAA,IAAY,KAAK,QAAQ,KAAK,MAAM,UAAU,IAAI,CAAC;EAClF;EACA,OAAO,KAAK,KAAK,WAAW,IAAI,IAAI,OAAS,KAAK,SAAS,KAAA,IAAY,IAAI,QAAQ,KAAK,MAAM,GAAG,MAAM,KAAK,UAAU,KAAA,IAAY,IAAI,UAAU,KAAK,KAAK,KAAK,GAAG,CAAC;EACnK;EACA,OAAO,KAAK,gBAAgB,UAAU;EACtC,GAAI,KAAK,kBAAkB,KAAA,IAAY,CAAC,IAAI,CAAC,aAAa,KAAK,UAAU,KAAK,aAAa,CAAC;CAC9F;AACF;;AAGA,MAAaC,aAAW,QAAqB,OAAuC,WAClF,IAAI,SAAS,YAAY;CACvB,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,aAAa;EACjB,MAAM,QAAQ,OAAO,OAAO,KAAK,KAAK;EACtC,IAAI,UAAU,KAAA,KAAa,KAAK,IAAI,IAAI,UAAU,QAAQ,QAAQ,KAAK;OAClE,WAAW,MAAM,EAAE;CAC1B;CACA,KAAK;AACP,CAAC;;AAGH,MAAaC,kBAAgB,YAA6C;CACxE,KAAK,IAAI,KAAK,QAAQ,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,QAAQ,GAAG,CAAE,OAAO,SAAS,OAAO,OAAO,QAAQ,GAAG,CAAE,WAAW,CAAC;CAC5H,OAAO;AACT;;;;;;;;;;;;;;AAeA,MAAa,iBAAiB,OAAO,KAAoB,MAAY,aAAqB,UAAgC;CACxH,MAAM,MAAM,KAAK;CACjB,MAAM,UAAU,MAAM,IAAI,SAAS;CACnC,MAAM,IAAI,MAAM,OAAO;CAEvB,MAAM,IAAI,SAAS,OAAO;CAC1B,MAAM,IAAI,OAAO;CACjB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,UAAU,IAAI,IAAI;CACxB,MAAM,aAAaA,eAAa,IAAI,MAAM;CAC1C,MAAM,SAAS,MAAM,IAAI,OAAO,eAAe,MAAM,IAAI,OAAO,CAAC;CACjE,MAAM,QAAQ,KAAK,WAAW,OAAO,SAAS;CAC9C,MAAM,QAAS,KAAK,WAAW,EAAE,MAAM,UAAU;CACjD,IAAI,QAAsB;CAC1B,IAAI,OAAoB;CACxB,IAAI,KAAoB;CACxB,MAAM,OAAsC,CAAC;CAC7C,IAAI;EACF,MAAM,OAAO,MAAM,CAAC,OAAO,GAAG,GAAM;EAEpC,IAAI,MADiBD,UAAQ,SAAS,UAAU,MAAM,OAAO,SAAS,OAAO,MAAM,IAAI,KAAA,IAAa,GAAM,MAC3F,KAAA,GAAW,MAAM,IAAI,MAAM,2CAAkD;EAC5F,IAAI,UAAuC;EAC3C,QAAQ,KAAK,OAAb;GACE,KAAK;GACL,KAAK;GACL,KAAK,OAAO;IACV,MAAM,OAAO,KAAK,UAAU,QAAQ,QAAQ;IAC5C,MAAM,OAAO,MAAM,SAAS,KAAK,UAAU,cAAc,UAAU;IACnE,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,OAAO;IAC3C,KAAK;IACL,QAAQ,MAAM,IAAI,MAAM,MAAM,MAAM,IAAI;IACxC,KAAK,WAAW,IAAI,KAAK,MAAM,MAAM,IAAI,CAAC;IAC1C,IAAI,KAAK,UAAU,KAAA,GAAW;KAI5B,MAAM,KAAK,MAAM;KACjB,MAAM,OAAO,MAAMA,UAAQ,SAAS,UAAU,MAAM,OAAO,UAAU,MAAM,IAAI,IAAI,GAAK;KACxF,UAAU,IAAI,KAAK,MAAM,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,KAAK,OAAO,GAAG,IAAI,GAAG;IACvF,OAAO,IAAI,KAAK,SAAS,KAAA,GACvB,UAAU,IAAI,KAAK,MAAM,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;IAE/E;GACF;GACA,KAAK,kBAAkB;IACrB,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,OAAO;IAC3C,KAAK;IACL,QAAQ,MAAM,IAAI,OAAO,MAAM,MAAM;IACrC,KAAK,WAAW,IAAI,OAAO,MAAM,MAAM,CAAC;IACxC,IAAI,KAAK,SAAS,KAAA,GAAW,UAAU,IAAI,OAAO,MAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;IACxG;GACF;GACA,KAAK,OAAO;IACV,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,OAAO;IAC3C,KAAK;IACL,QAAQ,MAAM,IAAI,OAAO,MAAM,MAAM;IACrC,KAAK,WAAW,IAAI,QAAQ,IAAI,CAAC;IACjC;GACF;GACA,KAAK;IACH,KAAK;IACL,QAAQ,MAAM,IAAI,SAAS,OAAO;IAClC;GACF,SACE,MAAM,IAAI,MAAM,mCAAmC,KAAK,OAAO;EACnE;EAEA,MAAM,SACJ,YAAY,OACR,QAAQ,QAAQ,IAAI,IACpB,QAAQ,MAAM,UAAU;GACtB,OAAO;GAEP,KAAK,SAAS;GACd,OAAO;EACT,CAAC;EAEP,OAAO,YAAY,KAAA,CAAS;EAC5B,MAAM,KAAK,MAAM;EACjB,MAAM,MAAM,GAAG,IAAI,QAAQ,QAAQ,CAAE,GAAG,GAAG,IAAI;EAC/C,MAAM,UAAU,MAAsB,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,OAAO,MAAM,IAAI,MAAM,CAAC,CAAC,EAAE,KAAK;EAM3H,IAAI,MALkBA,UACpB,SACC,UAAU,MAAM,OAAO,SAAS,OAAO,OAAO,MAAM,IAAI,CAAC,IAAI,OAAO,UAAU,UAAW,OAAO,MAAM,UAAU,YAAY,MAAM,UAAU,MAC7I,WAAW,IAAI,CACjB,MACgB,KAAA,GAAW,MAAMH,QAAME,SAAO;EAE9C,IAAI,YAAY,MAAM;GACpB,MAAM,OAAO,YAAY,KAAA,CAAS;GAClC,MAAMF,QAAM,YAAY,IAAI,CAAC;EAC/B;CACF,UAAU;EAER,KAAK,MAAM,QAAQ,KAAK,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;EACrE,MAAM,OAAO,KAAK;CACpB;CACA,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,MAAM,OAAO,YAAY,OAAO,OAAO,UAAU;CACjD,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,CAAC,YAAY,IAAI;CACnD,MAAM,QAAQ,UAAU,OAAO,OAAO,MAAM,IAAI,MAAM,KAAK;CAC3D,OAAO;EACL;EACA;EACA,QAAQ,CAAC,GAAG,OAAO,MAAM;EACzB;EACA,GAAI,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK;EAChC,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,QAAQ,QAAQ,CAAE;EACnC;EACA,OAAO;GACL,SAAS,IAAI;GACb,WAAW,CAAC;GACZ;GACA;GACA,UAAU,YAAY,IAAI,IAAI,MAAM,OAAO,GAAG,cAAc,OAAO,MAAM,CAAC;GAC1E;GACA;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;AC7pBA,MAAM,QAAQ;;AAEd,MAAM,gBAAgB;;AAGtB,MAAM,QAAQ,OAAO,MAAc,OAA+B,WAAkC;CAClG,MAAM,UAAU,KAAK,IAAI;CACzB,OAAO,CAAE,MAAM,MAAM,CAAC,CAAC,YAAY,KAAK,GAAI;EAC1C,IAAI,KAAK,IAAI,IAAI,UAAU,QAAQ,MAAM,IAAI,MAAM,GAAG,KAAK,mBAAmB,OAAO,IAAI;EACzF,MAAMK,QAAM,GAAG;CACjB;AACF;;AAGA,MAAM,WAAW,QAA+B,MAAiC;CAC/E,MAAM,OAAO,MAAM,IAAI,KAAA,IAAY,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,OAAO,MAAM,IAAI,MAAM,CAAC;CACzG,OAAO,SAAS,KAAA,IAAY,OAAO;EAAE;EAAG,GAAG,KAAK;CAAE;AACpD;;AAGA,MAAM,SAAS,OAAO,KAAoB,SAA6C;CACrF,MAAM,CAAC,UAAU,MAAM,IAAI,MAAM;EAAC;EAAM;EAAO;CAAI,CAAC,EAAA,CAAG,MAAM,KAAK;CAClE,OAAO;EAAE,OAAO,OAAO,KAAK;EAAG,MAAM;CAAI;AAC3C;;AAGA,MAAM,YAAY,OAAO,KAAoB,OAAc,SAAiB,WAA8C;CACxH,MAAM,OAAO,GAAG,IAAI,QAAQ,QAAQ,CAAE,GAAG,GAAG,IAAI,IAAI;CACpD,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,IAAI,MAAM;EAAC;EAAa;EAAU;EAAM;EAAW;EAAS,GAAG,MAAM;CAAQ,CAAC;CACpF,MAAM,QAAQ,KAAK,IAAI;CACvB,MAAM,QAAQ,UAAU,MAAM,IAAI,MAAM;EAAC;EAAY;EAAW,GAAG,MAAM;CAAmB,CAAC,CAAC;CAC9F,MAAM,OAAO,YAAY,MAAM,IAAI,MAAM;EAAC;EAAY;EAAW,GAAG,MAAM;CAAqB,CAAC,CAAC;CACjG,IAAI,MAAM,SAAS,MAAM,MAAM,IAAI,MAAM,oCAAoC;CAC7E,IAAI,UAAU,KAAK,IAAI,MAAM,WAAW,GAAG,QAAQ,CAAC;CACpD,IAAI,OAAkB,MAAM;CAC5B,MAAM,UAAuB,CAAC;EAAE,MAAM;EAAQ;EAAS;EAAO,MAAM,QAAQ,OAAO,QAAQ,OAAO;EAAG,MAAM,MAAM,OAAO,KAAK,GAAG,MAAM,QAAQ;CAAE,CAAC;CACjJ,MAAM,QAAQ,QAAQ,MAAM,YAAY,GAAG,IAAI;CAC/C,KAAK,IAAI,QAAQ,GAAG,SAAS,MAAM,QAAQ,SAAS,GAAG;EACrD,MAAMA,QAAM,KAAK,IAAI,GAAG,QAAQ,QAAQ,QAAQ,KAAK,IAAI,CAAC,CAAC;EAC3D,MAAM,MAAM,GAAG,MAAM,SAAS;EAC9B,MAAM,QAAQ,KAAK,IAAI;EACvB,MAAM,IAAI,MAAM;GAAC;GAAa;GAAU;GAAM;GAAQ;GAAS;GAAgB;GAAY;GAAW,WAAW,IAAI;GAAG;GAAS;EAAG,CAAC;EACrI,MAAM,WAAW,KAAK,IAAI;EAC1B,MAAM,OAAO,UAAU,MAAM,IAAI,MAAM;GAAC;GAAY;GAAW,GAAG,IAAI;EAAqB,CAAC,CAAC;EAC7F,UAAU,KAAK,IAAI,SAAS,KAAK,WAAW,CAAC;EAC7C,OAAO,KAAK,QAAQ;EACpB,QAAQ,KAAK;GAAE,MAAM;GAAS,SAAS;GAAO,OAAO;GAAU,MAAM,QAAQ,OAAO,QAAQ,OAAO;GAAG,MAAM,MAAM,OAAO,KAAK,GAAG;EAAE,CAAC;CACtI;CACA,OAAO;AACT;;;;;;;AAQA,MAAM,OAAO,OAAO,KAAoB,OAAc,SAAiB,SAA4C;CACjH,MAAM,QAAQ,MAAM,aAAa,YAAY,CAAC,SAAS,GAAG,IAAI,IAAI,QAAQ,QAAQ,SAAS,SAAS,OAAO,CAAC,IAAI,CAAC,OAAO;CACxH,MAAM,MAAM,QAAQ,MAAM,KAAK,GAAG;CAClC,MAAM,KAAK,SAAS,QAAQ,MAAM,UAAU,OAAO,KAAA,IAAY,KAAK,IAAI,MAAM;CAC9E,IAAI,OAAO,KAAA,GAAW,MAAMA,QAAM,MAAM,GAAK;CAC7C,MAAM,SAAS,MAAM,QAAQ,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,MAAM,QAAQ,EAAE,CAAC,CAAC;CAClF,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,IAAI,KAAK,MAAM;GAAC;GAAM;GAAM,WAAW,KAAK;EAAC,CAAC;EACpD,MAAM,IAAI,KAAK,MAAM;GAAC;GAAQ;GAAY;GAAa;GAAK;EAAS,CAAC;CACxE;CACA,OAAO,OAAO;AAChB;;;;;;;;AASA,MAAM,UAAU,OAAO,KAAoB,OAAc,YAAiE;CACxH,MAAM,EAAE,QAAQ;CAChB,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,SAAS,MAAM,KAAK,EAAE,QAAQ,MAAM,OAAO,IAAI,GAAG,OAAO,GAAG,MAAM,SAAS,KAAK,EAAE,qBAAqB;CAC7G,IAAI,OAAO,SAAS,GAAG,MAAM,IAAI,MAAM;EAAC;EAAM;EAAM,OAAO,OAAO,KAAK,GAAG,EAAE,MAAM,MAAM;CAAmB,CAAC;CAC5G,MAAM,IAAI,KAAK,SAAS;EAAC;EAAM;EAAM,GAAG,kBAAkB,KAAK,IAAI,EAAE;CAAiD,CAAC;CACvH,MAAM,MAAM,6BAA6B,aAAa,MAAM,IAAI,OAAO,SAAS,wBAAwB,IAAI,EAAA,CAAG,SAAS,GAAG,GAAG,aAAa;CAC3I,MAAM,IAAI,MAAM;EAAC;EAAgB;EAAU,GAAG,IAAI,QAAQ,QAAQ,CAAE,GAAG,GAAG;EAAQ;EAAiB,GAAG,MAAM;CAAQ,CAAC;CACrH,MAAM,IAAI,KAAK,SAAS;EAAC;EAAM;EAAM,WAAW,IAAI;CAAC,CAAC;CACtD,KAAK,MAAM,QAAQ,IAAI,SAAS,IAAI,SAAS,SAAS,MAAM,IAAI,QAAQ,IAAI;CAC5E,MAAM,IAAI,QAAQ,OAAO;CACzB,MAAM,MAAM,OAAO,YAAY,OAAO,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;CAC7F,MAAM,YAAY,MAAM,IAAI,OAAO,SAAS,eAAe,KAAK,GAAG,CAAC;CACpE,IAAI,CAAC,UAAU,SAAS,UAAQ,GAAG,MAAM,IAAI,MAAM,yCAAyC,WAAW;CACvG,MAAM,MAAM,iCAAiC,aAAa,MAAM,IAAI,OAAO,SAAS,qCAAqC,EAAA,CAAG,SAAS,MAAM,GAAG,aAAa;CAC3J,OAAO;EAAE;EAAS,OAAO,KAAK,IAAI;CAAE;AACtC;;;;;;;;;;AAWA,MAAa,YAAY,OAAO,KAAoB,MAAY,aAAqB,UAAgC;CACnH,MAAM,QAAQ,KAAK;CACnB,MAAM,EAAE,QAAQ;CAChB,MAAM,UAAU,MAAM,IAAI,SAAS;CACnC,MAAM,IAAI,MAAM,OAAO;CACvB,MAAM,IAAI,SAAS,OAAO;CAC1B,MAAM,IAAI,OAAO;CACjB,MAAM,IAAI,MAAM;EAAC;EAAM;EAAM,UAAU,MAAM,eAAe;CAAO,CAAC;CACpE,MAAM,SAAS,MAAM,IAAI,OAAO,SAAS,WAAW,OAAO,IAAI,QAAQ,MAAM,CAAC;CAC9E,IAAI,CAAC,OAAO,SAAS,aAAW,GAAG,MAAM,IAAI,MAAM,oBAAoB,QAAQ;CAC/E,MAAM,SAAS,OAAO,MAAM,IAAI,OAAO,SAAS,WAAW,CAAC;CAC5D,MAAM,QAAQ,MAAM,IAAI,MAAM,CAAC,aAAa,WAAW,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,EAAE,CAAE,KAAK;CAChF,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,UAAU,IAAI,IAAI;CACxB,MAAM,aAAaC,eAAa,IAAI,MAAM;CAC1C,MAAM,SAAS,MAAM,IAAI,OAAO,eAAe,MAAM,IAAI,OAAO,CAAC;CACjE,MAAM,WAAW,MAAM,aAAa;CACpC,IAAI,YAAgC;CACpC,IAAI,SAAwB;CAC5B,IAAI,QAAsB;CAC1B,IAAI,WAAsD;CAC1D,MAAM,UAAuB,CAAC;CAC9B,IAAI;EACF,MAAM,OAAO,MAAM,CAAC,OAAO,GAAG,GAAM;EAEpC,IAAI,MADiBC,UAAQ,SAAS,UAAU,MAAM,OAAO,SAAS,OAAO,MAAM,IAAI,KAAA,IAAa,GAAM,MAC3F,KAAA,GAAW,MAAM,IAAI,MAAM,2CAAkD;EAC5F,IAAI,MAAM,UAAU,MAAM,MAAM,OAAO,KAAK;EAC5C,IAAI,UAAU,QAAQ,KAAK,GAAI,MAAM,UAAU,KAAK,OAAO,SAAS,MAAM,CAAE;EAC5E,MAAM,QAAQ,MAAM,KAAK,KAAK,OAAO,SAAS,QAAQ,GAAG,EAAE,CAAC,EAAE,QAAQ,IAAI;EAC1E,QAAQ;EACR,IAAI,UAAU;GACZ,MAAM,OAAO,KAAK;GAClB,WAAW,MAAM,QAAQ,KAAK,OAAO,OAAO;GAC5C,SAAS,KAAK,IAAI,GAAG,GAAG,OAAO,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC,KAAK,UAAU,OAAO,MAAM,IAAI,CAAC,CAAC,IAAI;GACnH,YAAY,MAAM,IAAI,OAAO;IAAC,GAAG,eAAe,MAAM,IAAI,OAAO;IAAG;IAAU,OAAO,MAAM;GAAC,CAAC;GAE7F,IAAI,MADmBA,UAAQ,YAAY,UAAU,MAAM,OAAO,OAAO,WAAW,IAAI,CAAC,MACxE,KAAA,GAAW,MAAMF,QAAMG,SAAO;EACjD,OAAO;GACL,MAAM,MAAM,GAAG,IAAI,QAAQ,QAAQ,CAAE,GAAG,GAAG,IAAI;GAC/C,MAAM,UAAU,MAAsB,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,OAAO,MAAM,IAAI,MAAM,CAAC,CAAC,EAAE,KAAK;GAM3H,IAAI,MALmBD,UACrB,SACC,UAAU,MAAM,OAAO,SAAS,OAAO,OAAO,MAAM,IAAI,CAAC,IAAI,MAAM,MAAM,OAAO,MAAM,UAAU,YAAY,MAAM,UAAU,KAC7H,WAAW,IAAI,CACjB,MACiB,KAAA,GAAW,MAAMF,QAAMG,SAAO;GAC/C,MAAM,IAAI,QAAQ,OAAO;EAC3B;CACF,UAAU;EACR,MAAM,OAAO,KAAK;EAClB,MAAM,WAAW,KAAK;CACxB;CACA,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,MAAM,OAAO,YAAY,OAAO,OAAO,UAAU;CACjD,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,CAAC,YAAY,IAAI;CACnD,MAAM,QAAQ,UAAU,OAAO,OAAO,MAAM,IAAI,MAAM,KAAK;CAC3D,MAAM,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM,IAAI,OAAO,OAAO,WAAW,CAAC;CAChF,MAAM,SAAS,CAAC,GAAG,OAAO,QAAQ,GAAI,WAAW,UAAU,CAAC,CAAE,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;CACxF,OAAO;EACL;EACA;EACA;EACA;EACA,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,QAAQ,QAAQ,CAAE;EACnC;EACA,OAAO;GACL,SAAS,IAAI;GACb,WAAW,CAAC;GACZ;GACA,IAAI;GACJ,UAAU,YAAY,IAAI,IAAI,MAAM,OAAO,GAAG,cAAc,MAAM,CAAC;GACnE;GACA;GACA,OAAO;IAAE;IAAM,MAAM;IAAa;IAAS;IAAQ,OAAO;IAAM;IAAU;GAAO;EACnF;CACF;AACF;;;;AC9KA,MAAM,OAAO;;AAGb,MAAM,OAAO,IAAI,OAAO,OAAO,aAAa,EAAE,IAAI,eAAe,GAAG;;AAGpE,MAAa,WAAW,SAAyB,KAAK,QAAQ,MAAM,EAAE,CAAC,CAAC,KAAK;;AAG7E,MAAa,aAAa,UAA0B,UAAU,MAAM;;;;;;AAOpE,MAAa,cAAc,QAAgB,MAAc,UAAmC;CAC1F,MAAM,QAAQ,KAAK,KAAK,QAAQ,IAAI,CAAC;CACrC,IAAI,UAAU,MAAM,OAAO;CAC3B,MAAM,GAAG,KAAK,MAAM,IAAI,IAAI,QAAQ,OAAO,OAAO;CAElD,IAAI,EADS,IAAI,SAAS,UAAU,KAAK,CAAC,KAAK,UAAU,aAAa,UAAU,WAAW,IAAI,SAAS,aAAa,IAC1G,OAAO;CAClB,MAAM,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,QAAQ,KAAK,OAAO,KAAK,IAAI,OAAO,KAAK,IAAI;CAC5F,IAAI,CAAC,OAAO,SAAS,IAAI,GAAG,OAAO;CACnC,OAAO;EAAE,IAAI;EAAU,GAAG;EAAG;EAAQ;EAAM;EAAO;CAAI;AACxD;;AAGA,MAAa,oBAAoB,KAA0B,WACzD,IAAI,KAAK,UAAU;CAAE,GAAG;CAAM,GAAG,WAAW,OAAO,IAAI,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM;AAAE,EAAE;;;;;AAMhG,MAAa,cAAc,SAA0B;CACnD,MAAM,KAAK,KAAK,OAAO,MAAM;CAC7B,IAAI,OAAO,IAAI,MAAM,IAAI,MAAM,0BAA0B,KAAK,MAAM,GAAG,GAAG,GAAG;CAC7E,OAAO,KAAK,MAAM,KAAK,MAAM,EAAE,CAAC;AAClC;;AAGA,MAAa,cAAc,WAA2B,UAAU;;;;;AAMhE,MAAa,eAAe,YAC1B;CACE;CACA,GAAG,QAAQ,QAAQ,KAAK,MAAM,OAAO,0CAA0C,KAAK,EAAE,KAAK,WAAW,IAAI,GAAG;CAC7G;CACA,GAAG,QAAQ;CACX;AACF,CAAC,CAAC,KAAK,IAAI;;;;;;AAOb,MAAa,eAAe,YAC1B;CACE;CACA;CAEA,GAAG,QAAQ,SAAS,MAAM;AAC5B,CAAC,CAAC,KAAK,IAAI;;;;;;AAeb,MAAa,iBAAiB,SAAkB,SAA0C;CACxF,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAQ,KAAK,SAAS,CAAC,WAAW,IAAI,GAAG,IAAI,CAAC,CAAC;CAC9E,MAAM,UAAU,KAAK,QAAQ,QAAQ,IAAI,kBAAkB,QAAQ;CACnE,IAAI,QAAQ,WAAW,GAAG,OAAO;EAAE,SAAS;EAAM,SAAS;EAAO,KAAK,iBAAiB,QAAQ,OAAO;CAAU;CACjH,MAAM,SAAS,QAAQ;CACvB,MAAM,UAAU,OAAO,IAAI,OAAO,YAAY,KAAK;CACnD,IAAI,YAAY,MAAM,OAAO;EAAE,SAAS;EAAM,SAAS;EAAO,KAAK,wBAAwB,OAAO;CAAe;CACjH,IAAI,KAAK,WAAW,QAAQ,QAAQ,QAAQ,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,iBAAiB,KAAK,OAAO;CAAU;CAC1H,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,QAAQ,UAAU,IAAI,kBAAkB,YAAY,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,GAAG,IAAI,aAAa,MAAM,IAAI;EAAgB;EAC7I,IAAI,IAAI,SAAS,OAAO,MAAM,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,GAAG,IAAI,aAAa,cAAc,IAAI;EAAO;EAClH,IAAI,IAAI,oBAAoB,OAAO,iBAAiB,OAAO;GAAE;GAAS,SAAS;GAAO,KAAK,GAAG,IAAI,aAAa;EAAuB;CACxI;CACA,OAAO;EAAE;EAAS,SAAS;EAAM,KAAK;CAAU;AAClD;;;;;;;AAQA,MAAa,gBACX,SACA,SACA,QACA,MACA,SACQ;CACR,MAAM,SAAS,QAAQ,QAAQ,QAAQ,SAAS,SAAS,IAAI,CAAC,CAAC,KAAK,SAAS,QAAQ,KAAK,CAAE,EAAE;CAC9F,IAAI,SAAS,WAAW,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE;CACjD,IAAI,SAAS,SAAS,OAAO,EAAE,OAAO,OAAO;CAC7C,IAAI,SAAS,OAAO,OAAO,EAAE,OAAO,OAAO,MAAM,GAAG,CAAC,EAAE;CACvD,IAAI,SAAS,WAAW,OAAO;EAAE,OAAO,OAAO,MAAM,GAAG,CAAC;EAAG,WAAW;CAAM;CAC7E,IAAI,SAAS,cAAc,OAAO;EAAE,OAAO,CAAC,MAAM;EAAG,WAAW;CAAM;CACtE,OAAO,EAAE,OAAO,CAAC,GAAG,QAAQ,MAAM,EAAE;AACtC;AAsDA,MAAMC,WAAS,OAA8B,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;;;;;;;;;;;;AAgB7F,MAAa,iBAAiB,OAAO,YAA0C;CAC7E,MAAM,QAAQ,MAAM,aAAa;CACjC,MAAM,OAAO,MAAM,gBAAgB;CACnC,MAAM,EAAE,kBAAkB,SAAS,MAAM,8BAA8B,MAAM,WAAW;CACxF,MAAM,UAAU,MAAM,0BAA0B;CAChD,MAAM,SAAiC,CAAC;CACxC,IAAI;CACJ,MAAM,QAAQ,YAAY;EACxB,KAAK,MAAM,aAAa,OAAO,QAAQ,GAAG,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC,YAAY,KAAA,CAAS;EAC1F,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;CAC7C;CACA,MAAM,OAAO,OAAO,cAAqD;EAEvE,MAAM,MAAK,MADQ,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC,EAAA,CACzE,gBAAgB,SAAS,QAAS,QAAQ,EAAE,EAAE;EAC9D,IAAI,OAAO,KAAA,KAAa,OAAO,IAAI,MAAM,IAAI,MAAM,GAAG,UAAU,QAAQ,EAAE,qBAAqB,QAAS,QAAQ,GAAG;EACnH,OAAO;CACT;CACA,IAAI;EACF,UAAU,MAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;EACpC,MAAM,wBAAQ,IAAI,IAAkC;EACpD,MAAM,4BAAY,IAAI,IAAkC;EACxD,MAAM,UAAmC,CAAC;EAC1C,MAAM,MAAkB,CAAC;EACzB,MAAM,MAAgC,CAAC;EACvC,KAAK,MAAM,QAAQ,QAAQ,SAAS;GAClC,IAAI,UAAU;GACd,MAAM,MAAM,MAAM,IAAI,iBAAiB,QAAQ,KAAK,CAAC,CAClD,YAAY,OAAO,CAAC,CACpB,mBAAmB,IAAI,CAAC,CACxB,aAAa,IAAI,CAAC,CAClB,2BAA2B,CAC1B;IAAE,SAAS,YAAY,OAAO;IAAG,QAAQ;GAAuC,GAChF;IAAE,SAAS,QAAQ;IAAQ,QAAQ;GAAc,CACnD,CAAC,CAAC,CACD,YAAY;IAAC;IAAM;IAAM,YAAY,OAAO;GAAC,CAAC,CAAC,CAC/C,iBAAiB,KAAK,cAAc,QAAQ,KAAK,CAAC,CAAC,CACnD,mBAAmB,IAAO,CAAC,CAC3B,iBAAiB,WAChB,OAAO,GAAG,SAAS,UAA2B;IAC5C,WAAW,MAAM,SAAS;IAC1B,MAAM,QAAQ,QAAQ,MAAM,IAAI;IAChC,UAAU,MAAM,IAAI,KAAK;IACzB,KAAK,MAAM,QAAQ,OAAO;KACxB,MAAM,OAAQ,IAAI,UAAU,CAAC;KAC7B,KAAK,KAAK,IAAI;KACd,IAAI,KAAK,SAAA,KAAmB,KAAK,MAAM;KACvC,MAAM,OAAO,WAAW,MAAM,KAAK,KAAK,GAAG,QAAQ,KAAK;KACxD,IAAI,SAAS,MAAM,IAAI,KAAK,IAAI;IAClC;GACF,CAAC,CACH,CAAC,CACA,MAAM;GACT,OAAO,KAAK,GAAG;GACf,MAAM,IAAI,MAAM,GAAG;GACnB,MAAM,WAAW,MAAM,QACrB,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC,sBAAsB,aAAa,SAAS,GACpH,aAAa,IAAI,MAAM,GACzB,CAAC,CAAC,MAAM;GACR,OAAO,KAAK,QAAQ;GACpB,UAAU,IAAI,MAAM,QAAQ;GAC5B,QAAQ,QAAQ;IAAE,IAAI,MAAM,KAAK,GAAG;IAAG,OAAO,MAAM,QAAQ,QAAQ;GAAE;EACxE;EAEA,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,YAAY,OAAO,CAAC,CAAC,MAAM;EAC5E,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAC,MAAM;EAC1H,OAAO,KAAK,KAAK;EACjB,MAAM,WAAW,MAAM,KAAK,MAAM;EAElC,MAAM,YAAY,MAAM,IAAI,iBAAiB,IAAI,CAAC,CAC/C,YAAY,OAAO,CAAC,CACpB,YAAY;GAAC;GAAM;GAAM;EAA8B,CAAC,CAAC,CACzD,MAAM;EACT,OAAO,KAAK,SAAS;EAErB,MAAM,cAAc,MAAM,QAAQ,KAAK;EACvC,MAAM,UAAU,MAAoB;EACpC,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC7C,mBAAmB,CAAC,CACpB,gBAAgB,MAAM,CAAC,CACvB,YAAY,CAAC,uBAAuB,OAAO,WAAW,CAAC,CAAC,CAAC,CACzD,gBAAgB,QAAQ,OAAO,CAAC,CAChC,MAAM;EACT,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,QAAQ,MAAM,CAAC,SAAS,MAAM,GAAG,KAAQ,QAAQ;EACrE,IAAI,MAAM,OAAO,QAAQ,MAAM,IAAI,MAAM,sBAAsB,OAAO,MAAM,MAAM,GAAG;EAErF,MAAM,OAAO,SAAuC;GAClD,MAAM,QAAQ,MAAM,IAAI,IAAI;GAC5B,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,2BAA2B,MAAM;GAC1E,OAAO;EACT;EACA,MAAM,cAAc,SAAuC;GACzD,MAAM,QAAQ,UAAU,IAAI,IAAI;GAChC,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,2BAA2B,MAAM;GAC1E,OAAO;EACT;EACA,MAAM,YAAY,SAAyB,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,SAAS,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK;EAC3G,MAAM,UAAU,OAAO,OAA6B,SAAmC;GACrF,MAAM,QAAQ,KAAK,MAAM,SAAS,MAAM,OAAO,OAAO,IAAI,CAAC,CAAC;GAC5D,OAAO;IAAE,IAAI,MAAM;IAAI,IAAI,MAAM;GAAG;EACtC;EACA,MAAM,SAAS,OAAsC,OAAO,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;;EAE5G,MAAM,SAAS,OAAO,MAAc,YAAwC;GAC1E,MAAM,OAAO,MAAM,OAAO,IAAI,IAAI,GAAG;IAAC;IAAM;IAAM,eAAe,QAAQ;GAAiB,CAAC;GAC3F,MAAM,SAAS,KACZ,MAAM,IAAI,CAAC,CACX,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,QAAQ,SAAS,YAAY,KAAK,IAAI,CAAC,CAAC,CACxC,IAAI,MAAM;GACb,IAAI,OAAO,SAAS,GAAG,MAAM,IAAI,MAAM,GAAG,KAAK,qBAAqB,QAAQ,IAAI,KAAK,MAAM,GAAG,GAAG,GAAG;GACpG,OAAO;IAAE,OAAO,OAAO;IAAK,OAAO,OAAO,GAAG,EAAE;GAAG;EACpD;EACA,MAAM,SAAS,OAAO,SAAqC;GACzD,MAAM,OAAO,MAAM,OAAO,IAAI,IAAI,GAAG;IAAC;IAAmB;IAAM;IAAiB,QAAQ;IAAO;IAAe;GAAM,CAAC;GACrH,OAAO,cAAc,SAAS,WAAW,IAAI,CAAgB;EAC/D;EACA,IAAI,QAAgB,QAAQ,QAAQ;;EAEpC,MAAM,OAAO,YAAgC;GAC3C,IAAI,OAAkB;IAAE,SAAS;IAAM,SAAS;IAAO,KAAK;GAAmB;GAC/E,KAAK,MAAM,QAAQ,CAAC,OAAO,GAAG,QAAQ,QAAQ,QAAQ,SAAS,SAAS,KAAK,CAAC,GAAG;IAC/E,MAAM,OAAO,MAAM,OAAO,IAAI,CAAC,CAAC,OAAO,WAAoB;KAAE,SAAS;KAAM,SAAS;KAAO,KAAK,GAAG,KAAK,IAAK,MAAgB,QAAQ,MAAM,GAAG,GAAG;IAAI,EAAE;IACxJ,IAAI,KAAK,YAAY,MAAM,OAAO;IAClC,OAAO;GACT;GACA,OAAO;EACT;EACA,MAAM,WAAW,OAAO,SAAS,gBAAiC;GAChE,MAAM,UAAU,KAAK,IAAI;GACzB,IAAI,OAAO;GACX,IAAI,OAAkB;IAAE,SAAS;IAAM,SAAS;IAAO,KAAK;GAAc;GAC1E,OAAO,KAAK,IAAI,IAAI,UAAU,QAAQ;IACpC,OAAO,MAAM,KAAK;IAElB,OAAO,KAAK,UAAU,OAAO,IAAI;IACjC,IAAI,KAAK,YAAY,MAAM,QAAQ,KAAK;IACxC,IAAI,QAAQ,KAAK,KAAK,YAAY,MAAM,OAAO,KAAK;IACpD,MAAMA,QAAM,GAAK;GACnB;GACA,MAAM,IAAI,MAAM,iCAAiC,OAAO,OAAO,KAAK,KAAK;EAC3E;EAGA,MAAM,UAAU,KAAK,IAAI;EACzB,SAAS;GACP,MAAM,OAAO,MAAM,OAAO,IAAI,QAAQ,QAAQ,EAAG,GAAG;IAAC;IAAwB;IAAM;IAAkB;IAAe;GAAM,CAAC,CAAC,CAAC,YAAY,IAAI;GAC7I,MAAM,WAAY,KAAK,KAAK,MAAM,KAAK,CAAC,IAAI,WAAW,IAAI,EAAA,CAAoC,iBAAiB,CAAC;GACjH,IAAI,QAAQ,QAAQ,OAAO,SAAS,QAAQ,SAAS,WAAW,IAAI,CAAC,CAAC,GAAG;GACzE,IAAI,KAAK,IAAI,IAAI,UAAU,MAAS,MAAM,IAAI,MAAM,sCAAsC,QAAQ,KAAK,IAAI,EAAE,KAAK;GAClH,MAAMA,QAAM,GAAK;EACnB;EACA,MAAM,WAAW,SAAS,MAAM,OAAO,WAAW;GAAC;GAAQ;GAAuC,GAAG,QAAQ,QAAQ,QAAQ,GAAI,CAAE,GAAG,GAAG,QAAQ;GAAQ;GAAW,QAAQ;EAAK,CAAC,CAAC;EACnL,IAAI,CAAC,SAAS,SAAS,aAAW,GAAG,MAAM,IAAI,MAAM,oCAAoC,UAAU;EACnG,MAAM,SAAS;EAEf,OAAO;GACL;GACA;GACA;GACA,OAAO,EAAE,QAAQ,YAAY;GAC7B,QAAQ,QAAQ;GAChB;GACA;GACA,MAAM,OAAO,QAAQ;IACnB,MAAM,WAAW,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO;IAC/E,IAAI,SAAS,SAAS,GAAG,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;KAAM,GAAG;IAAQ,CAAC;IAChF,MAAM,OAA+B,CAAC;IACtC,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG,KAAK,OAAO,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;IAAG,CAAC;IAC5F,OAAO;GACT;GACA;GACA,MAAM,MAAM,QAAQ;IAClB,MAAM,OAAO,IAAI,MAAM,GAAG;KAAC;KAAe;KAAM;KAAe,QAAQ;IAAK,CAAC;GAC/E;GACA,MAAM,MAAM,QAAQ;IAClB,MAAM,QAAQ,SAAS,MAAM,OAAO,WAAW;KAAC;KAAQ;KAAuC,GAAG,QAAQ,OAAO,CAAE,GAAG,GAAG,QAAQ;KAAQ;KAAS,QAAQ;IAAK,CAAC,CAAC;IACjK,MAAM,OAAQ,KAAK,MAAM,KAAK,CAAC,CAA0B;IACzD,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,iCAAiC,OAAO;IAChF,OAAO,KAAK,IAAI,MAAM,CAAC,CAAC,QAAQ,MAAM,OAAO,UAAU,CAAC,KAAK,IAAI,CAAC;GACpE;GACA,OAAO,MAAM,QAAQ;IACnB,IAAI,SAAS,WAAW,OAAO;IAC/B,IAAI,SAAS,YAAY,MAAM,IAAI,MAAM,2BAA2B;IACpE,MAAM,WAAW,QAAQ,QAAQ,MAAM,SAAS,SAAS,MAAM;IAC/D,IAAI,aAAa,KAAA,GAAW,MAAM,IAAI,MAAM,6BAA6B;IACzE,OAAO;GACT;GACA,MAAM,OAAO,MAAM;IACjB,MAAM,SAAS,MAAkB;IACjC,MAAM,YAAY,MAAM,IAAI,iBAAiB,IAAI,CAAC,CAC/C,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,YAAY;KAAC;KAAQ;KAAwC,GAAG;IAAI,CAAC,CAAC,CACtE,gBAAgB,OAAO,OAAO,CAAC,CAC/B,MAAM;IACT,OAAO;KACL,QAAQ,OAAO;KACf,QAAQ,OAAO,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAQ;KAE9D,YACE,UACG,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CACpB,WAAW,KAAA,CAAS,CAAC,CACrB,YAAY,KAAA,CAAS;IAC5B;GACF;GACA,MAAM,MAAM,MAAM,MAAM,IAAI;IAC1B,MAAM,MAAM,aAAa,SAAS,SAAS,UAAU,MAAM,IAAI;IAC/D,MAAM,YAAY,IAAI,cAAc,KAAA,IAAY,CAAC,IAAI,CAAC,eAAe,IAAI,SAAS;IAClF,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB;KAAM,IAAI,MAAM,KAAK,GAAG;KAAG,GAAG;KAAW,GAAG,MAAM,EAAE;IAAC,CAAC;GACjH;GACA,KAAK,MAAM,MAAM,MAAM,IAAI;IACzB,MAAM,MAAM,aAAa,SAAS,SAAS,UAAU,MAAM,IAAI;IAC/D,MAAM,YAAY,IAAI,cAAc,KAAA,IAAY,CAAC,IAAI,CAAC,eAAe,IAAI,SAAS;IAClF,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB,SAAS,QAAQ,cAAc;KAAS,IAAI,MAAM,KAAK,GAAG;KAAG,GAAG;KAAW,GAAG,MAAM,EAAE;IAAC,CAAC;GACnJ;GACA,OAAO,MAAM,QAAQ,IAAI;IACvB,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB;KAAU,QAAQ,SAAS;KAAQ;KAAQ,GAAG,MAAM,EAAE;IAAC,CAAC;GACnH;GACA,MAAM,QAAQ,QAAQ;IAEpB,MAAM,OAAO,IAAI,MAAM,GAAG;KAAC;KAAM;KAAM,GAAG,QAAQ,SAAS,MAAM;IAAuB,CAAC;IACzF,MAAM,QAAQ,KAAK,IAAI;IACvB,OAAO,CAAE,MAAM,OAAO,IAAI,MAAM,GAAG;KAAC;KAAwB;KAAM;IAAe,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,YAAY,KAAK,GAAI;KACxH,IAAI,KAAK,IAAI,IAAI,QAAQ,MAAS,MAAM,IAAI,MAAM,GAAG,OAAO,qBAAqB;KACjF,MAAMA,QAAM,GAAK;IACnB;GACF;GACA,SAAS,QAAQ,IAAI;IACnB,OAAO,OAAO,QAAQ,0CAA0C,QAAQ,MAAM,GAAG,WAAW,EAAE,GAAG;GACnG;GACA,MAAM,QAAQ;IACZ,OAAO,OAAO,QAAQ,2BAA2B;GACnD;GACA,MAAM,OAAO,QAAQ;IACnB,MAAM,OAAO,IAAI,MAAM,GAAG;KAAC;KAAoB;KAAM;IAAQ,CAAC;GAChE;GACA,MAAM,SAAS;IACb,MAAM,OAAO,OAAO;KAAC;KAAM;KAAe;KAAS;IAAK,CAAC;GAC3D;GACA,MAAM,SAAS;IACb,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,QAAQ,MAAM,IAAI,SAA8B,YAAY;KAChE,MAAM,QAAQ,KAAK,IAAI;KACvB,MAAM,aAAa;MACjB,MAAM,OAAO,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,WAAW,OAAO,OAAO,OAAO;MAC5E,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI;WAC/B,IAAI,KAAK,IAAI,IAAI,QAAQ,KAAO,QAAQ,IAAI;WAC5C,WAAW,MAAM,EAAE;KAC1B;KACA,KAAK;IACP,CAAC;IACD,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM,WAAW,CAAC;GAC1D;GACA,MAAM,SAAS,SAAS;IACtB,MAAM,SAAS,MAAM,OAAO,OAAO,CAAC,QAAQ,iBAAiB,CAAC,CAAC,CAAC,YAAY,EAAE;IAC9E,MAAM,UAAU,OAAO,cAAoC,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC;IACjI,MAAM,OAAO,CAAC;IACd,KAAK,MAAM,QAAQ,QAAQ,SAAS;KAClC,MAAM,UAAU,SAAS,MAAM,OAAO,IAAI,IAAI,GAAG;MAAC;MAAe;MAAM;KAAS,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;KAClG,KAAK,KAAK;MAAE;MAAM,IAAI,QAAQ,KAAK,CAAE;MAAI,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,EAAA,CAAG;MAAO,UAAU;OAAE;OAAS,MAAM,QAAQ,KAAK,KAAK,IAAI;MAAE;KAAE,CAAC;IACvI;IACA,OAAO;KACL,QAAQ,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAC5C,cAAc,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAClD,IAAI,qBAAqB,KAAK,MAAM,CAAC,GAAG,MAAM;KAC9C,SAAS,MAAM,OAAO,QAAQ,CAAC,OAAO,iCAAiC,CAAC;KACxE,WAAW,cAAc,IAAI;KAC7B,QAAQ,GAAG,QAAQ,KAAK,iBAAiB,cAAc,MAAM,QAAQ,KAAK,iBAAiB;KAC3F,QAAQ;MAAE,OAAO,QAAQ;MAAO,IAAI,KAAK,EAAE,CAAE;MAAI,UAAU,KAAK,EAAE,CAAE;MAAU,SAAS,CAAC;KAAE;KAC1F,SAAS;MACP;MACA,KAAK,MAAM,QAAQ,MAAM,EAAA,CAAG;MAC5B,WAAW,MAAM,OAAO,QAAQ;OAAC;OAAO;OAAQ;MAAI,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,KAAK;MACzE,GAAG,cAAc;KACnB;KACA,QAAQ,oBAAoB,QAAQ,IAAI;KACxC,OAAO;MAAE,QAAQ;MAAa,QAAQ,QAAQ,QAAQ,QAAQ,GAAI,CAAE;KAAM;KAC1E;KACA,OAAO;MAAE,SAAS;MAAM,WAAW,CAAC;MAAG,UAAU,EAAE,OAAO,KAAK;KAAE;IACnE;GACF;GACA;EACF;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM;CACR;AACF;;AAOA,MAAME,WAAS;;AAEf,MAAMC,YAAU;;;;;;AAOhB,MAAa,kBAAkB,MAAY,SAA4C,WAA6B;CAClH,MAAM,UAAU,KAAK;CACrB,MAAM,QAAQ,KAAK,aAAa,WAAW,SAAS,QAAQ,QAAQ,QAAQ,SAAS,SAAS,MAAM,CAAC,CAAC,GAAG,EAAE;CAC3G,OAAO,CAAC,OAAO,GAAG,QAAQ,QAAQ,QAAQ,SAAS,SAAS,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,GAAG,QAAQ,KAAK,CAAE,GAAG,GAAG,QAAQ,MAAM;AAC1H;;AAGA,MAAa,aAAqB;;AAElC,MAAa,eAAuB;;AAGpC,MAAa,eAAe,MAAY,SAA4C,WAA6B;CAC/G,eAAe,MAAM,SAAS,MAAM,CAAC,CAAC,KAAK,GAAG;CAC9C;CACA,KAAK,QAAS;CACd;CACA,OAAO,KAAK,MAAM,aAAa,KAAA,IAAY,KAAK,QAAQ,KAAK,MAAM,UAAU,IAAI,CAAC;CAClF;CACA,OAAO,KAAK,KAAK,WAAW,IAAI,IAAI,OAAS,KAAK,SAAS,KAAA,IAAY,IAAI,QAAQ,KAAK,MAAM,GAAG,KAAK,GAAG,CAAC;CAC1G,GAAI,KAAK,kBAAkB,KAAA,IAAY,CAAC,IAAI,CAAC,aAAa,KAAK,UAAU,KAAK,aAAa,CAAC;AAC9F;;AAGA,MAAMC,aAAW,QAAqB,OAAuC,WAC3E,IAAI,SAAS,YAAY;CACvB,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,aAAa;EACjB,MAAM,QAAQ,OAAO,OAAO,KAAK,KAAK;EACtC,IAAI,UAAU,KAAA,KAAa,KAAK,IAAI,IAAI,UAAU,QAAQ,QAAQ,KAAK;OAClE,WAAW,MAAM,EAAE;CAC1B;CACA,KAAK;AACP,CAAC;;AAGH,MAAMC,kBAAgB,YAA6C;CACjE,KAAK,IAAI,KAAK,QAAQ,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,QAAQ,GAAG,CAAE,OAAO,SAAS,OAAO,OAAO,QAAQ,GAAG,CAAE,WAAW,CAAC;CAC5H,OAAO;AACT;;AAGA,MAAa,eAAe,OAAkB,WAAgD;CAC5F,MAAM,SAAS,cAAc,MAAM;CACnC,OAAO,WAAW,OAAO,OAAO;EAAE,IAAI,KAAK,MAAM,MAAM,QAAQ,MAAM;EAAG,IAAI,KAAK,MAAM,MAAM,QAAQ,MAAM;CAAE;AAC/G;;;;;;;;AASA,MAAM,UAAU,OACd,KACA,QACA,SACA,OACA,SAC8E;CAC9E,MAAM,UAAU,KAAK,IAAI;CACzB,OAAO,KAAK,IAAI,IAAI,UAAU,KAAO;EAEnC,MAAM,OADQ,iBAAiB,IAAI,IAAI,MAAM,OAAO,GAAG,cAAc,OAAO,MAAM,CACjE,CAAC,CAAC,KAAK,KAAK;EAC7B,IAAI,SAAS,KAAA,KAAa,KAAK,IAAI,GAAG,OAAO;GAAE,OAAO;IAAE,IAAI,KAAK;IAAG,IAAI,KAAK;GAAE;GAAG;EAAK;EACvF,MAAML,QAAM,GAAG;CACjB;CACA,OAAO;EAAE,OAAO,YAAY,MAAM,OAAO,MAAM;EAAG,MAAM;CAAK;AAC/D;;;;;;AAOA,MAAa,aAAa,MAAgB,WAAgD;CACxF,MAAM,CAAC,MAAM,iBAAiB,CAAC,IAAI,GAAG,cAAc,MAAM,CAAC;CAC3D,OAAO,OAAO,KAAA,KAAa,GAAG,KAAK,IAAI,OAAO;EAAE,IAAI,GAAG;EAAG,IAAI,GAAG;CAAE;AACrE;;;;;;;;;;;;;AAcA,MAAa,cAAc,OAAO,KAAiB,MAAY,aAAqB,UAAgC;CAClH,MAAM,SAAS,MAAM,IAAI,SAAS;CAClC,MAAM,IAAI,MAAM,MAAM;CACtB,MAAM,IAAI,OAAO;CACjB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,UAAU,IAAI,IAAI;CACxB,MAAM,aAAaK,eAAa,IAAI,MAAM;CAC1C,MAAM,SAAS,MAAM,IAAI,OAAO,YAAY,MAAM,IAAI,SAAS,MAAM,CAAC;CACtE,MAAM,QAAS,KAAK,WAAW,EAAE,MAAM,UAAU;CACjD,IAAI,QAAsB;CAC1B,IAAI,OAAoB;CACxB,IAAI,KAAoB;CACxB,IAAI,OAAyB;CAE7B,IAAI,YAA6B;CACjC,MAAM,OAAsC,CAAC;CAC7C,IAAI;EACF,MAAM,OAAO,MAAM,CAAC,OAAO,GAAG,GAAM;EAEpC,IAAI,MADiBD,UAAQ,SAAS,UAAU,MAAM,OAAO,SAAS,OAAO,MAAM,IAAI,KAAKF,UAAQ,GAAM,MAC3F,KAAA,GAAW,MAAM,IAAI,MAAM,8BAA8BA,SAAO,eAAe;EAC9F,IAAI,UAAuC;EAC3C,QAAQ,KAAK,OAAb;GACE,KAAK;GACL,KAAK;GACL,KAAK,OAAO;IACV,MAAM,OAAO,KAAK,UAAU,QAAQ,QAAQ;IAC5C,MAAM,OAAO,MAAM,SAAS,KAAK,UAAU,cAAc,UAAU;IACnE,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,MAAM;IAC1C,KAAK;IACL,QAAQ,MAAM,IAAI,MAAM,MAAM,MAAM,IAAI;IACxC,KAAK,WAAW,IAAI,KAAK,MAAM,MAAM,IAAI,CAAC;IAC1C,IAAI,KAAK,SAAS,KAAA,GAAW,UAAU,IAAI,KAAK,MAAM,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;IAC1G;GACF;GACA,KAAK,kBAAkB;IACrB,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,MAAM;IAC1C,KAAK;IACL,QAAQ,MAAM,IAAI,OAAO,MAAM,MAAM;IACrC,KAAK,WAAW,IAAI,OAAO,MAAM,MAAM,CAAC;IACxC,IAAI,KAAK,SAAS,KAAA,GAAW,UAAU,IAAI,OAAO,MAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;IACxG;GACF;GACA,KAAK,OAAO;IACV,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,MAAM;IAC1C,KAAK;IACL,QAAQ,MAAM,IAAI,OAAO,MAAM,MAAM;IACrC,KAAK,WAAW,IAAI,QAAQ,IAAI,CAAC;IACjC;GACF;GACA,KAAK;IACH,KAAK;IACL,OAAO,MAAM,IAAI,SAAS,QAAQ,IAAI,OAAO,WAAW,MAAM,CAAC;IAC/D,CAAC,CAAE,OAAO,OAAO,MAAM,aAAc,MAAM,QAAQ,KAAK,QAAQ,UAAU,SAAS,KAAK,WAAW,UAAU,WAAW,KAAK,KAAK,GAAG,GAAG,IAAI;IAC5I;GAEF,KAAK,SAAS;IACZ,MAAM,OAAO,IAAI,OAAO,MAAM,MAAM,MAAM;IAC1C,KAAK;IACL,OAAO,MAAM,IAAI,MAAM,IAAI;IAC3B,KAAK,WAAW,IAAI,OAAO,IAAI,CAAC;IAEhC,CAAC,CAAE,OAAO,OAAO,MAAM,aAAc,MAAM,QAAQ,KAAK,QAAQ,UAAU,SAAS,KAAK,WAAW,QAAQ,aAAa,KAAK,KAAK,GAAG,GAAG,IAAI;IAC5I;GACF;GACA,SACE,MAAM,IAAI,MAAM,+BAA+B,KAAK,OAAO;EAC/D;EACA,IAAI,UAAU,MAAM,MAAM,IAAI,MAAM,gGAAgG;EAEpI,MAAM,SACJ,YAAY,OACR,QAAQ,QAAQ,IAAI,IACpB,QAAQ,MAAM,UAAU;GACtB,OAAO;GAEP,KAAK,SAAS;GACd,OAAO;EACT,CAAC;EAEP,OAAO,YAAY,KAAA,CAAS;EAC5B,MAAM,KAAK,MAAM;EACjB,MAAM,UAAU,MAAsB,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,OAAO,MAAM,IAAI,MAAM,CAAC,CAAC,EAAE,KAAK;EAE3H,IAAI,MADkBE,UAAQ,SAAS,UAAU,MAAM,OAAO,SAAS,OAAO,OAAO,MAAM,IAAI,CAAC,IAAI,IAAI,WAAW,IAAI,CAAC,MACxG,KAAA,GAAW,MAAMJ,QAAMG,SAAO;EAE9C,IAAI,YAAY,MAAM;GACpB,MAAM,OAAO,YAAY,KAAA,CAAS;GAClC,MAAMH,QAAMG,SAAO;EACrB;CACF,UAAU;EAER,KAAK,MAAM,QAAQ,KAAK,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;EACrE,MAAM,OAAO,KAAK;CACpB;CACA,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,MAAM,OAAO,YAAY,OAAO,OAAO,UAAU;CACjD,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,CAAC,YAAY,IAAI;CACnD,MAAM,QAAQ,UAAU,OAAO,OAAO,MAAM,IAAI,MAAM,KAAK;CAC3D,OAAO;EACL;EACA;EACA,QAAQ,CAAC,GAAG,OAAO,MAAM;EACzB,OAAO,cAAc,OAAO,QAAS,UAAU,WAAW,OAAO,MAAM,KAAK;EAC5E,GAAI,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK;EAChC,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,QAAQ,MAAM,OAAO,CAAE;EACxC;EACA,OAAO;GACL,SAAS,IAAI;GACb,WAAW,CAAC;GACZ,SAAS;GACT;GACA,UAAU,iBAAiB,IAAI,IAAI,MAAM,OAAO,GAAG,cAAc,OAAO,MAAM,CAAC;GAC/E;GACA;EACF;CACF;AACF;;;;;;;;;;;;;;;AC9sBA,MAAM,aAAa;;AAGnB,MAAM,cAAc;;AAGpB,MAAa,YAAY,OAAc,SAAyB;CAC9D,MAAM,KAAK,MAAM,QAAQ,QAAQ,IAAI;CACrC,IAAI,OAAO,IAAI,OAAO,KAAK;CAC3B,IAAI,SAAS,MAAM,YAAY,OAAO,MAAM,QAAQ,SAAS;CAC7D,MAAM,IAAI,MAAM,+BAA+B,MAAM;AACvD;;;;;;AAOA,MAAa,SAAS,aACpB,SAAS,SAAS,QAAQ,MAAM,IAAI,CAAC,CAAC,QAAQ,MAAM,KAAK,CAAC,CAAC,QAAQ,OAAO,GAAG,CAAC,CAAC,YAAY;;AAG7F,MAAM,aAAa,WAA0C;CAC3D,YAAY,MAAM;CAClB,iBAAiB,MAAM;CACvB,gCAAgC,GAAG,SAAS,OAAO,MAAM,UAAU,EAAE,GAAG,MAAM,WAAW,GAAG,MAAM;CAClG,iCAAiC;CACjC,sCAAsC;CAEtC,gBAAgB;CAChB,GAAG,OAAO,YAAY,OAAO,QAAQ,MAAM,QAAQ,CAAC,CAAC,KAAK,CAAC,UAAU,WAAW,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC;AAC3G;;AAGA,MAAa,aAAa,OAAc,UAA0C;CAChF,GAAG,UAAU,KAAK;CAClB,qBAAqB;CACrB,eAAe,OAAO,SAAS,OAAO,IAAI,CAAC;CAC3C,iBAAiB,uBAAuB,MAAM;CAC9C,4BAA4B,eAAe,KAAK,GAAG,MAAM;CACzD,kCAAkC;AACpC;;AAGA,MAAa,iBAAiB,WAA0C;CACtE,GAAG,UAAU,KAAK;CAClB,qBAAqB;CACrB,eAAe,OAAO,SAAS,OAAO,MAAM,UAAU,CAAC;CACvD,iBAAiB,wBAAwB,MAAM;AACjD;;;;;AAcA,MAAa,eAAe,OAAc,SAAmC;CAC3E,MAAM,UAAU,KAAK,WAAW,KAAA,KAAa,KAAK,WAAW,OAAO,OAAQ,MAAM,QAAQ,KAAK,SAAS,MAAM;CAC9G,MAAM,MAAM,MAAM,QAAQ;CAC1B,IAAI,KAAK,QAAQ,WAAW,KAAK,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,GAAG,KAAK,QAAQ,OAAO;CAAyB;CACxH,IAAI,YAAY,MAAM,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK;CAA8B;CAC3F,IAAI,KAAK,UAAU,WAAW,KAAK,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,qBAAqB,KAAK,UAAU,UAAU,EAAE;CAAW;CACrI,IAAI,KAAK,KAAK,WAAW,KAAK,OAAO;EAAE;EAAS,SAAS;EAAO,KAAK,qBAAqB,KAAK,KAAK,UAAU,EAAE;CAAmB;CACnI,OAAO;EAAE;EAAS,SAAS;EAAM,KAAK;CAAU;AAClD;;;;;AAMA,MAAa,cACX,OACA,SACA,YACA,MACA,SACQ;CACR,IAAI,SAAS,SAAS,MAAM,IAAI,MAAM,2BAA2B,MAAM;CACvE,OAAO,EAAE,OAAO,CAAC,GAAG,MAAM,QAAQ,QAAQ,SAAS,SAAS,IAAI,CAAC,CAAC,KAAK,SAAS,QAAQ,KAAK,CAAE,EAAE,GAAG,WAAW,EAAE,EAAE;AACrH;;AAGA,MAAa,eAAe,UAAyB,MAAM,QAAQ,KAAK,SAAS,GAAG,KAAK,GAAG,MAAM,MAAM,CAAC,CAAC,KAAK,GAAG;;AAGlH,MAAa,WAAW,aAAqB,UAA0B,UAAU,YAAY,IAAI,QAAQ;AAiDzG,MAAMG,WAAS,OAA8B,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;;;;;;;;;;AAc7F,MAAa,eAAe,OAAO,UAAoC;CACrE,MAAM,QAAQ,MAAM,aAAa;CACjC,MAAM,cAAc,MAAM,iBAAiB;CAC3C,MAAM,EAAE,kBAAkB,SAAS,MAAM,8BAA8B,MAAM,WAAW;CACxF,MAAM,UAAU,MAAM,0BAA0B;CAChD,MAAM,SAAiC,CAAC;CACxC,IAAI;CACJ,MAAM,QAAQ,YAAY;EACxB,KAAK,MAAM,aAAa,OAAO,QAAQ,GAAG,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC,YAAY,KAAA,CAAS;EAC1F,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;CAC7C;CACA,MAAM,OAAO,OAAO,cAAqD;EAEvE,MAAM,MAAK,MADQ,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC,EAAA,CACzE,gBAAgB,SAAS,QAAS,QAAQ,EAAE,EAAE;EAC9D,IAAI,OAAO,KAAA,KAAa,OAAO,IAAI,MAAM,IAAI,MAAM,GAAG,UAAU,QAAQ,EAAE,qBAAqB,QAAS,QAAQ,GAAG;EACnH,OAAO;CACT;CACA,IAAI;EACF,UAAU,MAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;EACpC,MAAM,UAAU;EAChB,MAAM,wBAAQ,IAAI,IAAkC;EACpD,MAAM,4BAAY,IAAI,IAAkC;EACxD,MAAM,QAAiC,CAAC;EACxC,MAAM,MAAgC,CAAC;EACvC,MAAM,SAAmB,CAAC;EAC1B,MAAM,WAAW,OAAO,MAAc,gBAAuD;GAC3F,IAAI,UAAU;GACd,MAAM,MAAM,MAAM,IAAI,iBAAiB,MAAM,KAAK,CAAC,CAChD,YAAY,OAAO,CAAC,CACpB,mBAAmB,IAAI,CAAC,CACxB,aAAa,IAAI,CAAC,CAClB,gBAAgB,WAAW,CAAC,CAC5B,iBAAiB,KAAK,cAAc,MAAM,KAAK,CAAC,CAAC,CACjD,mBAAmB,IAAO,CAAC,CAC3B,iBAAiB,WAChB,OAAO,GAAG,SAAS,UAA2B;IAC5C,WAAW,MAAM,SAAS;IAC1B,MAAM,QAAQ,QAAQ,MAAM,IAAI;IAChC,UAAU,MAAM,IAAI,KAAK;IACzB,KAAK,MAAM,QAAQ,OAAO;KACxB,MAAM,OAAQ,IAAI,UAAU,CAAC;KAC7B,KAAK,KAAK,IAAI;KACd,IAAI,KAAK,SAAA,KAAmB,KAAK,MAAM;KACvC,IAAI,YAAY,IAAI,GAAG,OAAO,KAAK,IAAI;IACzC;GACF,CAAC,CACH,CAAC,CACA,MAAM;GACT,OAAO,KAAK,GAAG;GACf,MAAM,IAAI,MAAM,GAAG;GACnB,MAAM,WAAW,MAAM,QACrB,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC,sBAAsB,aAAa,SAAS,GACpH,aAAa,IAAI,MAAM,GACzB,CAAC,CAAC,MAAM;GACR,OAAO,KAAK,QAAQ;GACpB,UAAU,IAAI,MAAM,QAAQ;GAC5B,MAAM,QAAQ;IAAE,IAAI,MAAM,KAAK,GAAG;IAAG,OAAO,MAAM,QAAQ,QAAQ;GAAE;EACtE;EACA,MAAM,SAAS,MAAM,YAAY,cAAc,KAAK,CAAC;EACrD,KAAK,MAAM,QAAQ,MAAM,SAAS,MAAM,SAAS,MAAM,UAAU,OAAO,IAAI,CAAC;EAC7E,MAAM,UAAmC,OAAO,YAAY,MAAM,QAAQ,KAAK,SAAS,CAAC,MAAM,MAAM,KAAM,CAAC,CAAC;EAC7G,MAAM,aAAa,MAAM,MAAM;EAE/B,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,YAAY,OAAO,CAAC,CAAC,MAAM;EAC5E,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAC,MAAM;EAC1H,OAAO,KAAK,KAAK;EACjB,MAAM,WAAW,MAAM,KAAK,MAAM;EAClC,MAAM,YAAY,MAAM,IAAI,iBAAiB,WAAW,CAAC,CACtD,YAAY,OAAO,CAAC,CACpB,YAAY;GAAC;GAAM;GAAM;EAA8B,CAAC,CAAC,CACzD,MAAM;EACT,OAAO,KAAK,SAAS;EAErB,MAAM,cAAc,MAAM,QAAQ,KAAK;EACvC,MAAM,UAAU,MAAoB;EACpC,MAAM,SAAS,MAAM,IAAI,iBAAiB,KAAK,CAAC,CAC7C,mBAAmB,CAAC,CACpB,gBAAgB,MAAM,CAAC,CACvB,YAAY,CAAC,uBAAuB,OAAO,WAAW,CAAC,CAAC,CAAC,CACzD,gBAAgB,QAAQ,OAAO,CAAC,CAChC,MAAM;EACT,OAAO,KAAK,MAAM;EAClB,MAAM,QAAQ,MAAM,QAAQ,MAAM,CAAC,SAAS,MAAM,GAAG,KAAQ,QAAQ;EACrE,IAAI,MAAM,OAAO,QAAQ,MAAM,IAAI,MAAM,sBAAsB,OAAO,MAAM,MAAM,GAAG;EAErF,MAAM,OAAO,SAAuC;GAClD,MAAM,QAAQ,MAAM,IAAI,IAAI;GAC5B,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,yBAAyB,MAAM;GACxE,OAAO;EACT;EACA,MAAM,cAAc,SAAuC;GACzD,MAAM,QAAQ,UAAU,IAAI,IAAI;GAChC,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,yBAAyB,MAAM;GACxE,OAAO;EACT;EACA,MAAM,YAAY,SAAyB,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,SAAS,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK;EAC3G,MAAM,UAAU,OAAO,OAA6B,SAAmC;GACrF,MAAM,QAAQ,KAAK,MAAM,SAAS,MAAM,OAAO,OAAO,IAAI,CAAC,CAAC;GAC5D,OAAO;IAAE,IAAI,MAAM;IAAI,IAAI,MAAM;GAAG;EACtC;EACA,MAAM,SAAS,OAAsC,OAAO,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;EAC5G,MAAM,YAAY,YAAY,KAAK;EACnC,MAAM,OAAO,OAAO,GAAG,SACrB,SAAS,MAAM,OAAO,WAAW;GAAC;GAAQ;GAAa;GAAO;GAAY;GAAc;GAAW,GAAG;EAAI,CAAC,CAAC;EAC9G,MAAM,OAAO,OAAO,UAClB,KAAK,MAAM,MAAM,KAAK,QAAQ,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC;EAExE,OAAO;GACL;GACA;GACA;GACA;GACA,OAAO,EAAE,QAAQ,YAAY;GAC7B,QAAQ,QAAQ;GAChB;GACA;GACA,MAAM,OAAO,QAAQ;IACnB,MAAM,WAAW,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO;IAC/E,IAAI,SAAS,SAAS,GAAG,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;KAAM,GAAG;IAAQ,CAAC;IAChF,MAAM,OAA+B,CAAC;IACtC,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG,KAAK,OAAO,MAAM,OAAO,OAAO;KAAC;KAAU;KAAM;IAAG,CAAC;IAC5F,OAAO;GACT;GACA,MAAM,UAAU,SAAS,aAAa;IACpC,MAAM,QAAQ,KAAK,IAAI;IACvB,IAAI,OAAO;IACX,OAAO,KAAK,IAAI,IAAI,QAAQ,QAAQ;KAClC,MAAM,OAAO,MAAM,KAAK,CAAC,CAAC,OAAO,UAAoB,MAAgB,QAAQ,MAAM,GAAG,GAAG,CAAC;KAC1F,IAAI,OAAO,SAAS,YAAY,KAAK,QAAQ,WAAW,MAAM,QAAQ,QAAQ;KAC9E,OAAO,OAAO,SAAS,WAAW,OAAO,GAAG,KAAK,QAAQ,OAAO;KAChE,MAAMA,QAAM,GAAK;IACnB;IACA,MAAM,IAAI,MAAM,kCAAkC,OAAO,OAAO,MAAM;GACxE;GACA,MAAM,OAAO,OAAO,aAAa,GAAG;IAClC,MAAM,MAAM,MAAM,QAAQ,KAAK,SAAS,SAAS,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;IACvE,MAAM,QAAQ,MAAM,KAAK,UAAU,OAAO,OAAO,MAAM,SAAS,GAAG,KAAK,OAAO,UAAU,CAAC;IAC1F,IAAI,CAAC,MAAM,SAAS,aAAW,GAAG,MAAM,IAAI,MAAM,mCAAmC,OAAO;GAC9F;GACA,MAAM,KAAK,OAAO,YAAY,OAAO;IACnC,MAAM,QAAQ,MAAM,KAAK,QAAQ,OAAO,OAAO,UAAU,GAAG,OAAO,KAAK,CAAC;IACzE,IAAI,CAAC,MAAM,SAAS,aAAW,GAAG,MAAM,IAAI,MAAM,iCAAiC,OAAO;GAC5F;GACA,MAAM,SAAS,MAAM;IACnB,MAAM,SAAS,MAAkB;IAEjC,MAAM,YAAY,MAAM,IAAI,iBAAiB,WAAW,CAAC,CACtD,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,YAAY;KAAC;KAAM;KAAM;KAAgB;KAAY;KAAa;KAAO;KAAY;KAAiB;KAAW,GAAG;IAAI,CAAC,CAAC,CAC1H,gBAAgB,OAAO,OAAO,CAAC,CAC/B,MAAM;IACT,MAAM,YAAY,MAAM,QACtB,IAAI,iBAAiB,KAAK,CAAC,CAAC,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAAC,sBAAsB,aAAa,SAAS,GACvH,aAAa,UAAU,MAAM,GAC/B,CAAC,CAAC,MAAM;IACR,OAAO;KACL,QAAQ,OAAO;KACf,QAAQ,OAAO,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAQ;KAC9D,SAAS,QAAQ,OAAO,QAAQ,WAAW;MAAC;MAAuB;MAAU;MAAQ;MAAQ,GAAG,MAAM,EAAE;KAAC,CAAC;KAE1G,MAAM,YAAY;MAChB,MAAM,UAAU,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;MAC1D,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC,YAAY,KAAA,CAAS;KAClD;IACF;GACF;GACA,MAAM,SAAS,OAAO,SAAS,aAAa;IAC1C,MAAM,QAAQ,KAAK,IAAI;IACvB,IAAI,OAAO;IACX,IAAI,OAAkB;KAAE,SAAS;KAAM,SAAS;KAAO,KAAK;IAAc;IAC1E,OAAO,KAAK,IAAI,IAAI,QAAQ,QAAQ;KAClC,OAAO,MAAM,KAAK,KAAK,CAAC,CAAC,MACtB,SAAS,YAAY,OAAO,IAAI,IAChC,WAAoB;MAAE,SAAS;MAAM,SAAS;MAAO,KAAM,MAAgB,QAAQ,MAAM,GAAG,GAAG;KAAE,EACpG;KAGA,OAAO,KAAK,UAAU,OAAO,IAAI;KACjC,IAAI,QAAQ,KAAK,KAAK,YAAY,MAAM,OAAO,KAAK;KACpD,MAAMA,QAAM,GAAK;IACnB;IACA,MAAM,IAAI,MAAM,qCAAqC,OAAO,OAAO,KAAK,KAAK;GAC/E;GACA,MAAM,MAAM,OAAO;IACjB,MAAM,QAAQ,MAAM,KAAK,SAAS,KAAK;IACvC,MAAM,EAAE,SAAS,KAAK,MAAM,KAAK;IACjC,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,qCAAqC,OAAO;IACpF,OAAO,KAAK,IAAI,MAAM,CAAC,CAAC,QAAQ,MAAM,OAAO,UAAU,CAAC,KAAK,IAAI,CAAC;GACpE;GACA,MAAM,OAAO,MAAM;IACjB,MAAM,SAAS,MAAkB;IACjC,MAAM,YAAY,MAAM,IAAI,iBAAiB,WAAW,CAAC,CACtD,gBAAgB,aAAa,OAAO,MAAM,GAAG,CAAC,CAC9C,YAAY;KAAC;KAAQ;KAAa;KAAO;KAAY;KAAe;KAAW,GAAG;IAAI,CAAC,CAAC,CACxF,gBAAgB,OAAO,OAAO,CAAC,CAC/B,MAAM;IACT,OAAO;KACL,QAAQ,OAAO;KACf,QAAQ,OAAO,WAAW,OAAO,MAAM,OAAO,QAAQ,QAAQ;KAE9D,YACE,UACG,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CACpB,WAAW,KAAA,CAAS,CAAC,CACrB,YAAY,KAAA,CAAS;IAC5B;GACF;GACA,MAAM,MAAM,MAAM,MAAM,IAAI;IAC1B,MAAM,MAAM,WAAW,OAAO,SAAS,YAAY,MAAM,IAAI;IAC7D,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB;KAAM,IAAI,MAAM,KAAK,GAAG;KAAG,GAAG,MAAM,EAAE;IAAC,CAAC;GACnG;GACA,KAAK,MAAM,MAAM,MAAM,IAAI;IACzB,MAAM,MAAM,WAAW,OAAO,SAAS,YAAY,MAAM,IAAI;IAC7D,OAAO,QAAQ,WAAW,IAAI,GAAG;KAAC;KAAuB,SAAS,QAAQ,cAAc;KAAS,IAAI,MAAM,KAAK,GAAG;KAAG,GAAG,MAAM,EAAE;IAAC,CAAC;GACrI;GACA,MAAM,SAAS;IACb,MAAM,OAAO,OAAO;KAAC;KAAM;KAAe;KAAS;IAAK,CAAC;GAC3D;GACA,MAAM,SAAS;IACb,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,QAAQ,MAAM,IAAI,SAA8B,YAAY;KAChE,MAAM,QAAQ,KAAK,IAAI;KACvB,MAAM,aAAa;MACjB,MAAM,OAAO,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,WAAW,OAAO,OAAO,OAAO;MAC5E,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI;WAC/B,IAAI,KAAK,IAAI,IAAI,QAAQ,KAAO,QAAQ,IAAI;WAC5C,WAAW,MAAM,EAAE;KAC1B;KACA,KAAK;IACP,CAAC;IACD,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM,WAAW,CAAC;GAC1D;GACA,MAAM,SAAS,SAAS;IACtB,MAAM,SAAS,MAAM,OAAO,OAAO,CAAC,QAAQ,iBAAiB,CAAC,CAAC,CAAC,YAAY,EAAE;IAC9E,MAAM,UAAU,OAAO,cAAoC,QAAQ,UAAU,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC,CAAC;IACjI,MAAM,WAAW;KACf,UAAU,OAAO,QAAQ,MAAM,QAAQ,CAAC,CACrC,KAAK,CAAC,UAAU,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC,CAClD,KAAK,IAAI;KACZ,MAAM,MAAM;KACZ,uBAAuB,OAAO,MAAM,SAAS;IAC/C;IACA,MAAM,OAAO,OAAO,UAA6B;KAC/C,MAAM,MAAM,CAAC;KACb,KAAK,MAAM,QAAQ,OAAO;MACxB,MAAM,UAAU,SAAS,MAAM,OAAO,IAAI,IAAI,GAAG,CAAC,kCAAkC,WAAW,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;MACjH,IAAI,KAAK;OAAE;OAAM,IAAI,MAAM,KAAK,CAAE;OAAI,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,EAAA,CAAG;OAAO,UAAU;QAAE;QAAS,GAAG;OAAS;MAAE,CAAC;KAClH;KACA,OAAO;IACT;IACA,MAAM,UAAU,MAAM,KAAK,MAAM,OAAO;IACxC,OAAO;KACL,QAAQ,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAC5C,cAAc,MAAM,OAAO,QAAQ,CAAC,SAAS,IAAI,CAAC;KAClD,IAAI,qBAAqB,KAAK,MAAM,CAAC,GAAG,MAAM;KAC9C,SAAS,MAAM,OAAO,QAAQ,CAAC,OAAO,iCAAiC,CAAC;KACxE,QAAQ,GAAG,QAAQ,KAAK,iBAAiB,cAAc,MAAM,QAAQ,KAAK,iBAAiB;KAC3F,QAAQ;MAAE,OAAO,MAAM;MAAO,IAAI,QAAQ,EAAE,CAAE;MAAI,UAAU,QAAQ,EAAE,CAAE;MAAU,SAAS,CAAC;KAAE;KAC9F,SAAS;MACP;MACA,KAAK,MAAM,QAAQ,MAAM,EAAA,CAAG;MAC5B,WAAW,MAAM,OAAO,QAAQ;OAAC;OAAO;OAAQ;MAAI,CAAC,EAAA,CAAG,MAAM,IAAI,CAAC,CAAC,KAAK;KAC3E;KACA,QAAQ;MAAE,MAAM;MAAS,OAAO;KAAY;KAC5C,OAAO;MAAE,QAAQ;MAAa,QAAQ,QAAQ,MAAM,QAAQ,GAAI,CAAE;KAAM;KACxE;KACA,OAAO;MAAE,SAAS;MAAS,WAAW,MAAM,KAAK,CAAC,MAAM,UAAU,CAAC;MAAG,UAAU,EAAE,OAAO,YAAY;KAAE;IACzG;GACF;GACA;EACF;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM;CACR;AACF;;AAOA,MAAM,SAAS;;;;;;AAOf,MAAa,gBAAgB;;AAG7B,MAAa,aAAa,MAAY,UAA4B;CAChE;CACA;CACA;CACA,OAAO,KAAK,MAAO,OAAO;CAC1B;CACA,OAAO,KAAK,MAAM,aAAa,KAAA,IAAY,KAAK,QAAQ,KAAK,MAAM,UAAU,IAAI,CAAC;CAClF;CACA,OAAO,KAAK,KAAK,WAAW,IAAI,IAAI,OAAS,KAAK,SAAS,KAAA,IAAY,IAAI,QAAQ,KAAK,MAAM,GAAG,KAAK,GAAG,CAAC;CAC1G,GAAG,OAAO,QAAQ,KAAK,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,WAAW,CAAC,SAAS,GAAG,KAAK,GAAG,OAAO,KAAK,GAAG,CAAC;AAC9G;;AAGA,MAAM,WAAW,QAAqB,OAAuC,WAC3E,IAAI,SAAS,YAAY;CACvB,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,aAAa;EACjB,MAAM,QAAQ,OAAO,OAAO,KAAK,KAAK;EACtC,IAAI,UAAU,KAAA,KAAa,KAAK,IAAI,IAAI,UAAU,QAAQ,QAAQ,KAAK;OAClE,WAAW,MAAM,EAAE;CAC1B;CACA,KAAK;AACP,CAAC;;AAGH,MAAMC,kBAAgB,YAA6C;CACjE,KAAK,IAAI,KAAK,QAAQ,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,QAAQ,GAAG,CAAE,OAAO,SAAS,OAAO,OAAO,QAAQ,GAAG,CAAE,WAAW,CAAC;CAC5H,OAAO;AACT;;;;;;;;;;;AAYA,MAAa,YAAY,OAAO,KAAe,MAAY,aAAqB,UAAgC;CAC9G,IAAI,KAAK,UAAU,aAAa,MAAM,IAAI,MAAM,6BAA6B,KAAK,OAAO;CACzF,IAAI,KAAK,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,6CAA6C;CAC1F,MAAM,QAAS,KAAK,WAAW,EAAE,MAAM,UAAU;CACjD,IAAI,MAAM,SAAS,WAAW,MAAM,IAAI,MAAM,oCAAoC,MAAM,MAAM;CAC9F,MAAM,OAAO,MAAM,QAAQ;CAC3B,MAAM,QAAQ,QAAQ,aAAa,KAAK;CACxC,MAAM,IAAI,UAAU;CACpB,MAAM,IAAI,OAAO,KAAK;CACtB,MAAM,SAAS,MAAM,IAAI,SAAS,KAAK;CACvC,MAAM,IAAI,OAAO;CACjB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,aAAaA,eAAa,IAAI,MAAM;CAC1C,MAAM,SAAS,MAAM,IAAI,OAAO,UAAU,MAAM,KAAK,CAAC;CACtD,IAAI,QAAsB;CAC1B,IAAI,OAAoB;CACxB,MAAM,OAAsC,CAAC;CAC7C,IAAI;EACF,MAAM,OAAO,MAAM,CAAC,OAAO,GAAG,GAAM;EAEpC,IAAI,MADiB,QAAQ,SAAS,UAAU,MAAM,OAAO,SAAS,OAAO,MAAM,IAAI,KAAK,QAAQ,GAAM,MAC3F,KAAA,GAAW,MAAM,IAAI,MAAM,4BAA4B,OAAO,eAAe;EAC5F,QAAQ,MAAM,IAAI,MAAM,aAAa,QAAQ,IAAI;EACjD,KAAK,WAAW,IAAI,KAAK,aAAa,QAAQ,IAAI,CAAC;EAEnD,OAAO,MAAM,IAAI,KAAK,aAAa,QAAQ,MAAM,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;EAEzF,KAAK,SAAS;EACd,MAAMD,QAAM,aAAa;CAC3B,UAAU;EAER,KAAK,MAAM,QAAQ,KAAK,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;EACrE,MAAM,OAAO,KAAK;CACpB;CACA,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,MAAM,OAAO,YAAY,OAAO,OAAO,UAAU;CACjD,MAAM,QAAQ,MAAM,IAAI,SAAS,KAAK,CAAC,CAAC,YAAY,IAAI;CACxD,MAAM,QAAQ,UAAU,OAAO,OAAO,MAAM,IAAI,MAAM,KAAK;CAC3D,OAAO;EACL;EACA;EACA,QAAQ,CAAC,GAAG,OAAO,MAAM;EACzB;EACA,GAAI,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK;EAChC,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,QAAQ,OAAO,CAAE;EAClC;EACA,OAAO;GACL,SAAS,IAAI;GACb,WAAW,GAAG,IAAI,MAAM,aAAa,IAAI,WAAW;GACpD,SAAS;GACT,IAAI;GACJ,UAAU,CAAC;GACX;GACA;EACF;CACF;AACF;;AAGA,MAAM,mBAAmB;;AAGzB,MAAM,iBAAiB;;AAGvB,MAAM,iBAAiB;;;;;;;;;;;;AAavB,MAAa,iBAAiB,OAAO,KAAe,MAAY,aAAqB,UAAgC;CACnH,MAAM,QAAQ,KAAK,OAAO;CAC1B,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,gDAAgD;CACzF,IAAI,KAAK,UAAU,kBAAkB,MAAM,IAAI,MAAM,kCAAkC,KAAK,OAAO;CACnG,IAAI,KAAK,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,kDAAkD;CAC/F,MAAM,OAAO,QAAQ,KAAK,MAAM,GAAG;CACnC,MAAM,QAAQ,QAAQ,aAAa,KAAK;CACxC,MAAM,QAAQ,UAAU,YAAY,IAAI,QAAQ;CAChD,MAAM,IAAI,UAAU;CACpB,MAAM,IAAI,OAAO,OAAO,gBAAgB;CACxC,MAAM,SAAS,MAAM,IAAI,SAAS,KAAK;CACvC,MAAM,IAAI,KAAK,OAAO,kBAAkB,MAAM,IAAI;CAClD,MAAM,IAAI,OAAO;CACjB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,aAAaC,eAAa,IAAI,MAAM;CAC1C,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA,MAAM;EACN;EACA,OAAO,KAAK,KAAK,OAAO,GAAG,CAAC;EAC5B,GAAG,OAAO,QAAQ,KAAK,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,WAAW,CAAC,SAAS,GAAG,KAAK,GAAG,OAAO,KAAK,GAAG,CAAC;CAC9G;CACA,MAAM,UAAyB,CAAC;CAChC,IAAI,QAAsB;CAC1B,IAAI,OAAoB;CACxB,IAAI,cAAqC,CAAC;CAC1C,IAAI,cAAqC,CAAC;CAC1C,IAAI;EACF,MAAM,QAAQ,MAAM,IAAI,SAAS;GAAC,GAAG;GAAQ;GAAgB,OAAO,QAAQ,MAAM,SAAS,IAAI,CAAC;GAAG;GAAiB,MAAM;EAAU,CAAC;EACrI,QAAQ,KAAK,KAAK;EAClB,MAAM,QAAQ,MAAM,IAAI,SAAS;GAAC,GAAG;GAAQ;GAAgB;GAAK;GAAiB;EAAQ,CAAC;EAC5F,QAAQ,KAAK,KAAK;EAClB,cAAc,MAAM;EACpB,cAAc,MAAM;EACpB,MAAM,QAAQ,KAAK,IAAI;EACvB,OAAO,KAAK,IAAI,IAAI,QAAQ,kBAAkB,CAAC,WAAW,MAAM,QAAQ,MAAM,MAAM,GAAG,MAAMD,QAAM,GAAG;EACtG,IAAI,WAAW,MAAM,QAAQ,MAAM,MAAM,GAAG;GAC1C,MAAM,OAAO,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,KAAK;GACvC,MAAM,QAAQ,MAAM,QAAQ,QAAQ,UAAU,MAAM,OAAO,gBAAgB,MAAM,IAAI,MAAM,cAAc;GACzG,IAAI,UAAU,KAAA,GAAW;IACvB,QAAQ,MAAM,MAAM,OAAO,QAAQ,MAAM,IAAI,QAAQ,MAAM,WAAW,GAAG,IAAI,GAAG;IAEhF,OAAO,MAAM,MAAM,OAAO,QAAQ,MAAM,KAAK,OAAO,GAAG;IACvD,MAAMA,QAAM,aAAa;GAC3B;EACF;CACF,UAAU;EACR,KAAK,MAAM,UAAU,SAAS,MAAM,OAAO,KAAK;CAClD;CACA,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,OAAO;EACL;EACA;EACA,QAAQ,CAAC,GAAG,WAAW;EACvB;EACA,GAAI,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK;EAChC,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,QAAQ,OAAO,CAAE;EAClC,MAAM,YAAY,OAAO,OAAO,UAAU;EAC1C,OAAO;GAAE,OAAO,CAAC,GAAG,WAAW;GAAG,QAAQ,IAAI,OAAO,QAAQ,SAAS,WAAW,MAAM,KAAK,CAAC;GAAG;EAAM;CACxG;AACF;;;;;;;;AC1mBA,MAAa,SACX,MACA,SAC+C;CAE/C,MAAM,WAAW,KAAK,QAAQ,QAAQ,IAAI,WAAW,IAAI,CAAC,CAAC,KAAK,QAAQ,QAAQ,MAAM,GAAG,CAAC;CAC1F,OAAO;EAAE;EAAU,SAAS,UAAU,KAAK,YAAY,UAAU,QAAQ,IAAI,CAAC;CAAE;AAClF;;AAGA,MAAM,gBAAgB,YAA6C;CACjE,KAAK,IAAI,KAAK,QAAQ,SAAS,GAAG,MAAM,GAAG,MAAM,GAC/C,IAAI,QAAQ,GAAG,CAAE,OAAO,SAAS,OAAO,OAAO,QAAQ,GAAG,CAAE,WAAW,CAAC;CAC1E,OAAO;AACT;;AAGA,MAAM,aAAa,MAAY,QAAuB;CACpD,MAAM,EAAE,YAAY,UAAU;CAC9B,MAAM,WACH,WAAW,YAAY,QAAQ,WAAW,WAAW,KAAA,IAClD,UAAU,IAAI,IACd,WAAW,UACT,YAAY,UAAU,IACtB,QAAQ,WAAW,QAAQ,GAAG,MAAM,KAAK,eAAe,KAAA,IAAY,IAAI,QAAQ,KAAK,YAAY,GAAG;CAC5G,MAAM,OAAO;EAAC,IAAI;EAAU,OAAO,IAAI,UAAU;EAAG;EAAU,MAAM;CAAI;CACxE,IAAI,MAAM,OAAO,KAAA,GAAW;EAE1B,MAAM,EAAE,OAAO;EAEf,MAAM,SADa,WAAW,YAAY,QAAS,WAAW,YAAY,SAAS,CAAC,IAAK,CAAC,EAAA,CACjE,QAAQ,KAAK,SAAS,MAAM,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC;EAC/E,KAAK,KAAK,eAAe,GAAG,MAAM;EAClC,KAAK,KAAK,eAAe,GAAG,cAAc,OAAO,QAAQ,IAAI;EAC7D,IAAI,GAAG,cAAc,MACnB,KAAK,KACH,2BACA,OAAO,QAAQ,GAAG,UAAU,UAAU,IAAI,CAAC,GAC3C,0BACA,OAAO,QAAQ,GAAG,UAAU,SAAS,IAAI,CAAC,GAC1C,sBACA,OAAO,GAAG,UAAU,MAAM,CAC5B;EACF,KAAK,KAAK,eAAe,GAAG,cAAc,OAAO,QAAQ,IAAI;EAC7D,IAAI,GAAG,cAAc,MACnB,KAAK,KACH,0BACA,OAAO,QAAQ,GAAG,UAAU,cAAc,IAAI,CAAC,GAC/C,0BACA,OAAO,GAAG,UAAU,UAAU,GAC9B,sBACA,OAAO,QAAQ,GAAG,UAAU,UAAU,IAAI,CAAC,GAC3C,wBACA,OAAO,GAAG,UAAU,QAAQ,GAC5B,sBACA,OAAO,GAAG,UAAU,MAAM,CAC5B;EACF,KAAK,KAAK,wBAAwB,OAAO,QAAQ,GAAG,gBAAgB,IAAI,CAAC,CAAC;EAC1E,KAAK,KAAK,2BAA2B,OAAO,QAAQ,GAAG,mBAAmB,IAAI,CAAC,CAAC;EAChF,IAAI,GAAG,SAAS,KAAA,GAAW,KAAK,KAAK,aAAa,OAAO,QAAQ,GAAG,MAAM,IAAI,CAAC,CAAC;EAChF,KAAK,KAAK,WAAW,OAAO,KAAK,MAAM,UAAU,SAAS,IAAI,EAAE,CAAC,CAAC;EAClE,OAAO;CACT;CACA,IAAI,MAAM,SAAS,KAAA,GAAW;EAE5B,MAAM,EAAE,SAAS;EACjB,MAAM,MAAM,KAAK,QAAQ,KAAA,IAAY,IAAI,QAAQ,KAAK,KAAK,GAAG;EAC9D,KAAK,KAAK,YAAY,KAAK,MAAM;EACjC,IAAI,KAAK,QAAQ,KAAA,GAAW,KAAK,KAAK,YAAY,OAAO,QAAQ,KAAK,KAAK,IAAI,CAAC,CAAC;EACjF,IAAI,KAAK,SAAS,KAAA,GAAW,KAAK,KAAK,aAAa,OAAO,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC;EACpF,IAAI,KAAK,UAAU,KAAA,GAAW,KAAK,KAAK,WAAW,OAAO,KAAK,KAAK,CAAC;EACrE,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,GAAG,KAAK,KAAK,KAAK,QAAQ,OAAO,KAAK,CAAC;EAEpG,KAAK,KAAK,eAAe,OAAO,SAAS,CAAC;EAC1C,KAAK,KAAK,WAAW,OAAO,KAAK,KAAK,UAAU,IAAI,MAAM,EAAE,CAAC,CAAC;EAC9D,OAAO;CACT;CACA,IAAI,MAAM,YAAY,KAAA,GAAW,KAAK,KAAK,aAAa,MAAM,OAAO;CACrE,IAAI,MAAM,UAAU,KAAA,GAAW,KAAK,KAAK,WAAW,OAAO,MAAM,KAAK,CAAC;CACvE,IAAI,MAAM,aAAa,KAAA,GAAW,KAAK,KAAK,iBAAiB,OAAO,QAAQ,MAAM,UAAU,IAAI,CAAC,CAAC;CAClG,IAAI,MAAM,QAAQ,SAAS,WAAW;EAEpC,KAAK,KAAK,SAAS,MAAM,OAAO,GAAG;EACnC,IAAI,MAAM,OAAO,OAAO,KAAA,GAAW,KAAK,KAAK,QAAQ,MAAM,OAAO,EAAE;EACpE,IAAI,KAAK,iBAAiB,KAAA,GAAW,KAAK,KAAK,OAAO,OAAO,KAAK,YAAY,CAAC;EAC/E,IAAI,KAAK,WAAW,MAAM,KAAK,KAAK,UAAU;EAC9C,IAAI,KAAK,kBAAkB,KAAA,GAAW,KAAK,KAAK,aAAa,KAAK,UAAU,KAAK,aAAa,CAAC;EAC/F,KAAK,KAAK,WAAW,OAAO,KAAK,KAAK,UAAU,IAAI,EAAE,CAAC,CAAC;EACxD,OAAO;CACT;CACA,IAAI,MAAM,QAAQ,SAAS,QAAQ,MAAM,QAAQ,SAAS,YAAY,MAAM,QAAQ,SAAS,QAAQ;EAEnG,IAAI,MAAM,OAAO,SAAS,UAAU,MAAM,OAAO,UAAU,KAAA,GAAW,KAAK,KAAK,WAAW,MAAM,OAAO,KAAK;EAC7G,IAAI,MAAM,OAAO,SAAS,UAAU,MAAM,OAAO,aAAa,KAAA,GAAW,KAAK,KAAK,oBAAoB,MAAM,OAAO,QAAQ;EAC5H,IAAI,MAAM,OAAO,SAAS,YAAY,MAAM,OAAO,UAAU,KAAA,GAC3D,KAAK,KAAK,WAAW,OAAO,MAAM,OAAO,MAAM,KAAK,GAAG,kBAAkB,OAAO,KAAK,MAAM,QAAQ,MAAM,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;EACpI,IAAI,KAAK,WAAW,MAAM,KAAK,KAAK,UAAU;EAC9C,IAAI,KAAK,kBAAkB,KAAA,GAAW,KAAK,KAAK,aAAa,KAAK,UAAU,KAAK,aAAa,CAAC;EAC/F,KAAK,KAAK,WAAW,OAAO,KAAK,KAAK,UAAU,IAAI,EAAE,CAAC,CAAC;EACxD,OAAO;CACT;CACA,IAAI,MAAM,QAAQ,SAAS,QAAQ;EAEjC,IAAI,MAAM,OAAO,SAAS,KAAA,GAAW,KAAK,KAAK,aAAa,OAAO,QAAQ,MAAM,OAAO,MAAM,IAAI,CAAC,CAAC;EACpG,IAAI,MAAM,OAAO,OAAO,KAAA,GAAW,KAAK,KAAK,QAAQ,MAAM,OAAO,EAAE;EACpE,IAAI,KAAK,WAAW,MAAM,KAAK,KAAK,UAAU;EAC9C,IAAI,KAAK,kBAAkB,KAAA,GAAW,KAAK,KAAK,aAAa,KAAK,UAAU,KAAK,aAAa,CAAC;EAC/F,KAAK,KAAK,WAAW,OAAO,KAAK,KAAK,UAAU,IAAI,EAAE,CAAC,CAAC;EACxD,OAAO;CACT;CACA,IAAI,MAAM,WAAW,KAAA,GAAW;EAE9B,KAAK,KAAK,kBAAkB,OAAO,QAAQ,MAAM,OAAO,WAAW,IAAI,CAAC,CAAC;EACzE,KAAK,KAAK,WAAW,OAAO,KAAK,KAAK,UAAU,IAAI,EAAE,CAAC,CAAC;EACxD,OAAO;CACT;CACA,IAAI,MAAM,WAAW,KAAK,KAAK,aAAa;CAC5C,IAAI,MAAM,gBAAgB,KAAA,GACxB,KAAK,KAAK,qBAAqB,OAAO,QAAQ,MAAM,aAAa,IAAI,CAAC,CAAC;CACzE,IAAI,MAAM,SAAS,KAAA,GAAW,KAAK,KAAK,cAAc,aAAa;CACnE,IAAI,MAAM,YAAY,KAAA,GAAW,KAAK,KAAK,UAAU,SAAS;CAC9D,KAAK,KAAK,WAAW,OAAO,KAAK,KAAK,UAAU,IAAI,EAAE,CAAC,CAAC;CACxD,OAAO;AACT;;;;;;;AAQA,MAAM,iBACJ,MACA,SACA,QACA,gBAA+B,UAE/B,IAAI,SAAS,YAAY;CACvB,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,aAAa;EACjB,MAAM,MAAM,QAAQ;EACpB,MAAM,KAAK,SAAS,MAAM,GAAG;EAU7B,IARE,OAAO,KAAA,KACP,IAAI,OAAO,MACR,WACC,OAAO,UAAU,GAAG,SACpB,OAAO,WAAW,GAAG,WACnB,OAAO,OAAO,YAAY,OAAO,OAAO,OAAO,KAC9C,OAAO,OAAO,WAAY,OAAqC,QAAQ,EAC9E,KACU,QAAQ,KAAK,KAAK,IAAI,IAAI,UAAU,QAAQ,QAAQ;OAC3D,WAAW,MAAM,EAAE;CAC1B;CACA,KAAK;AACP,CAAC;AAEH,MAAM,SAAS,OAA8B,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;;;;;AAM7F,MAAa,WAAW;;;;;AAMxB,MAAa,YAAY;;AAGzB,MAAM,YAAY;CAAC;CAAQ;CAAY;AAAM;;;;;AAM7C,MAAM,eAAe,OAAc,WACjC,IAAI,SAAS,SAAS,WAAW;CAC/B,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,aAAa;EACjB,MAAM,OAAO,MAAM,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC;EACjE,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI;OAC/B,IAAI,KAAK,IAAI,IAAI,UAAU,QAC9B,uBAAO,IAAI,MAAM,qCAAqC,OAAO,qBAAqB,CAAC;OAChF,WAAW,MAAM,CAAC;CACzB;CACA,KAAK;AACP,CAAC;;AAGH,MAAM,UAAU;;AAEhB,MAAM,aAAa;;AAGnB,MAAM,gBAAgB,OAAO,MAAY,SAAoB,WAAkC;CAC7F,MAAM,UAAU,KAAK,IAAI;CACzB,OAAO,KAAK,IAAI,IAAI,UAAU,QAAQ;EACpC,IAAIE,QAAc,MAAM,QAAQ,CAAC,GAAG;EACpC,MAAM,MAAM,GAAG;CACjB;AACF;;AAGA,MAAM,gBAAgB,UAAwB,UAAU,IAAI,IAAI,MAAM,MAAM;;;;;;AAO5E,MAAM,aAAa,OAAO,KAAU,MAAY,aAAqB,UAAgC;CACnG,IAAI,KAAK,UAAU,SAAS,KAAK,UAAU,eAAe,KAAK,UAAU,eACvE,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,6DAA6D,KAAK,OAAO;CACxG,MAAM,IAAI,OAAO;CACjB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,gBAAgB,IAAI,UAAU;CACpC,MAAM,aAAa,aAAa,IAAI,MAAM;CAC1C,MAAM,UAAsB,KAAK,WAAW;CAC5C,MAAM,OAAO,KAAK,UAAU,gBAAgB,WAAW,KAAK;CAC5D,MAAM,UAAwB,KAAK,UAAU,gBAAgB,EAAE,MAAM,KAAK,QAAQ,OAAO,IAAI,CAAC;CAC9F,MAAM,QAAQ,MAAM,IAAI,MAAM,MAAM,SAAS,OAAO;CACpD,IAAI;CACJ,IAAI;EACF,QAAQ,MAAM,IAAI,MAAM,UAAU,MAAM,GAAG,CAAC;EAC5C,MAAM,UAAU;EAEhB,MAAM,iBAAsB;GAC1B;GACA;GACA,QAAQ,QAAQ;GAChB;GACA,QAAQ,IAAI,OAAO,MAAM,IAAI;GAC7B,OAAO,IAAI,MAAM;GACjB,aAAa,IAAI,MAAM;GACvB,MAAM;GACN,GAAI,IAAI,aAAa,OAAO,CAAC,IAAI,EAAE,UAAU,IAAI,SAAS;EAC5D;EACA,MAAM,cAAc,MAAM,SAAS,aAAa,IAAI,CAAC;EACrD,MAAM,MAAM,OAAO;CACrB,UAAU;EACR,MAAM,IAAI,KAAK,MAAM,SAAS,OAAO;EACrC,MAAM,OAAO,KAAK;CACpB;CACA,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,OAAO;EACL;EACA;EACA,QAAQ,CAAC,GAAI,OAAO,UAAU,CAAC,CAAE;EACjC;EACA,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,MAAM;EACvB,MAAM,YAAY,OAAO,OAAO,UAAU;EAC1C,GAAI,IAAI,aAAa,OAAO,CAAC,IAAI;GAAE,UAAU,IAAI;GAAU,WAAW,IAAI,UAAU,MAAM,aAAa;EAAE;CAC3G;AACF;;AAEA,MAAM,YAAY,OAAc,OAAe,WAC7C,IAAI,SAAS,SAAS,WAAW;CAC/B,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,aAAa;EACjB,MAAM,OAAO,MAAM,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,MAAM,KAAK,KAAK;EACjF,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI;OAC/B,IAAI,KAAK,IAAI,IAAI,UAAU,QAAQ,uBAAO,IAAI,MAAM,iDAAiD,OAAO,IAAI,CAAC;OACjH,WAAW,MAAM,CAAC;CACzB;CACA,KAAK;AACP,CAAC;;;;;AAMH,MAAM,SAAS,OAAc,OAAe,WAC1C,IAAI,SAAS,YAAY;CACvB,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,aAAa;EACjB,MAAM,QAAQ,MAAM,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC;EAClE,MAAM,QAAQ,MAAM,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU;EAClE,IAAI,SAAS,SAAS,SAAS,KAAK,IAAI,IAAI,UAAU,QAAQ,QAAQ;OACjE,WAAW,MAAM,EAAE;CAC1B;CACA,KAAK;AACP,CAAC;;AAGH,MAAM,WAAW;;;;;;AAOjB,MAAM,eAAe,OAAO,KAAU,MAAc,WAAgD;CAClG,MAAM,UAAU,KAAK,IAAI;CACzB,MAAM,cAAc,OAAO,MAAM,SAAS,QAAQ,IAAI,OAAO,MAAM,IAAI,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK;CAClG,OAAO,MAAM,KAAK,KAAK,IAAI,IAAI,UAAU,UAAU,MAAM,MAAM,EAAE;CACjE,MAAM,MAAA,GAAc;AACtB;;AAGA,MAAM,aAAa,MAAY,UAA6C;CAC1E,MAAM,QAAQ,CACZ,GAAI,KAAK,YAAY,KAAA,IAAY,CAAC,IAAI,CAAC,SAAS,QAAQ,KAAK,SAAS,IAAI,EAAE,GAAG,GAC/E,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,KAAK,CACvC;CACA,OAAO,MAAM,WAAW,IAAI,OAAO,MAAM,KAAK,GAAG;AACnD;;;;;;;;;;;;;;AAeA,MAAM,OAAO,OACX,KACA,MACA,aACA,OACA,MAAM,UACW;CACjB,IAAI,KAAK,WAAW,MAAM,OAAO,WAAW,KAAK,MAAM,aAAa,KAAK;CAEzE,MAAM,IAAI,QAAQ,MAAM;CACxB,MAAM,WAAW,MAAM,IAAI,QAAQ,SAAS;CAC5C,MAAM,aAAa,IAAI,QAAQ,OAAO,UAAU;CAEhD,MAAM,IAAI,OAAO;CACjB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,gBAAgB,IAAI,UAAU;CACpC,MAAM,aAAa,IAAI,OAAO;CAC9B,MAAM,aAAa,aAAa,IAAI,MAAM;CAC1C,MAAM,OAAO,KAAK,MAAM,SAAS,KAAA,IAAY,KAAA,IAAY,SAAS,KAAK,MAAM,KAAK,SAAS,KAAK,MAAM,KAAK,OAAO;CAElH,MAAM,OAAO,KAAK,MAAM,YAAY,KAAA,IAAY,KAAA,IAAY,WAAW,KAAK,MAAM,OAAO;CACzF,MAAM,QAAQ,CACZ,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC;EAAE,SAAS,KAAK,UAAU,IAAI;EAAG,QAAQ;CAAc,CAAC,GACvF,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC;EAAE,SAAS,KAAK;EAAS,QAAQ;CAAU,CAAC,CAC7E;CACA,MAAM,QAAQ,MAAM,IAAI,MAAM,UAAU,MAAM,GAAG,GAAG,MAAM,WAAW,IAAI,KAAA,IAAY,KAAK;CAC1F,MAAM,SAAS,KAAK,aAAa;CACjC,MAAM,OAAO,SACT;EAAE,cAAc,MAAM,OAAO;EAAG,YAAY,MAAM,KAAK;CAAE,IACzD;EAAE,cAAc,IAAI,OAAO;EAAG,YAAY,IAAI,KAAK;CAAE;CAEzD,MAAM,WACJ,MAAM,GAAG,CAAC,CAAC,OAAO,UAAmB;EACnC,MAAM,OAAO,MAAM,OAAO,MAAM,EAAE,CAAC,CAAC,KAAK,UAAU,KAAK,UAAU,KAAK,CAAC;EACxE,MAAM,IAAI,MAAM,GAAI,MAAgB,QAAQ,6BAA6B,KAAK,KAAK,GAAG,GAAG;CAC3F,CAAC;CACH,MAAM,SAAS;EACb,GAAI,IAAI,aAAa,OAAO,CAAC,IAAI,EAAE,UAAU,IAAI,SAAS;EAC1D,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,KAAK;EAC/C,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,KAAK,QAAQ;CACxD;CACA,MAAM,iBAAiB;EACrB,IAAI,IAAI,WAAW,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,2CAA2C;EACtG,OAAO,IAAI;CACb;;CAEA,MAAM,iBAAsB;EAC1B;EACA;EACA,QAAQ,MAAM;EACd,OAAO;EACP,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,MAAM;EACvB,MAAM;EACN,GAAG;CACL;CACA,IAAI,QAAsB;CAC1B,IAAI,OAA0C;CAE9C,MAAM,YAAY,CAAC,UAAU,KAAK,OAAO,YAAY,KAAA;CACrD,IAAI,UAAsD;CAC1D,IAAI;EACF,MAAM,MAAM,MAAM,CAAC,OAAO,GAAG,IAAM;EACnC,IAAI,KAAK;GACP,IAAI,KAAK,MAAM,SAAS,QAAQ,MAAM,GAAG;GACzC,MAAM,MAAM,GAAG;EACjB,OAAO;GAKL,MAAM,gBACJ,KAAK,MAAM,SAAS,eAClB,UAAU,KAAK,UAAU,mBAAoB,KAAK,UAAU,SAAS,aAAa,IAAI;GAC1F,IAAI,eAAe;IAGjB,MAAM,GAAG;IACT,MAAM,MAAM,GAAG;GACjB,OAIE,MAAM,MAAA,GAAc;GAEtB,MAAM,UAAsB,KAAK,YAAY,SAAS,WAAW;GAGjE,MAAM,sBACJ,YAAY,YAAa,WAAW,OAAO,KAAK,QAAQ,WAAW;GACrE,MAAM,YACJ,KAAK,UAAU,KAAA,IACX,KAAA,IACC,KAAK,UAAU,gBAAiB,sBAC/B,OACA;GACR,MAAM,UAAwB;IAC5B,GAAI,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU;IAC/C,GAAI,KAAK,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK;IACrD,GAAI,KAAK,QAAQ,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI;GACtD;GAEA,MAAM,aAAa,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU;GAC9D,IAAI,YAAY,MAAM,IAAI,MAAM,KAAK,KAAM;GAE3C,MAAM,UAAsB,KAAK,WAAW;GAC5C,MAAM,WAAW,UACf,YAAY,WAAW,IAAI,MAAM,UAAU,MAAM,KAAK,GAAG,QAAQ,IAAI,IAAI,MAAM,SAAS,MAAM,OAAO;GAEvG,MAAM,QAAQ,YAAmC;IAC/C,QAAQ,KAAK,OAAb;KACE,KAAK;MACH,IAAI,WAAW;OACb,MAAM,QAAQ,MAAM,IAAI,OAAO,MAAM;OACrC,IAAI,KAAK,SAAS,KAAA,GAAW;QAC3B,UAAU,IAAI,OAAO,QAAQ,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,WAAW;SACtF,OAAO;SACP,OAAO;QACT,CAAC;QACD,QAAQ,YAAY,KAAA,CAAS;OAC/B;OACA,OAAO;MACT;MACA,MAAM,KAAK,OAAO;MAClB,OAAO;KAET,KAAK;MACH,OAAO,SAAS,MAAM,KAAK,IAAI,IAAI,KAAK;MACxC,OAAO;KACT,KAAK,eACH,OAAO,IAAI,MAAM,UAAU,SAAS,EAAE,MAAM,KAAK,QAAQ,OAAO,CAAC;KACnE,KAAK,WACH,OAAO,IAAI,MAAM,aAAa,SAAS,OAAO;KAChD,KAAK,iBACH,OAAO,IAAI,MAAM,OAAO,KAAK,WAAW,UAAU,EAAE,OAAO,KAAK,OAAO,KAAK,CAAC;KAC/E,KAAK,SACH,OAAO,QAAQ,KAAK,KAAK;KAC3B,KAAK,OACH,OAAO,IAAI,MAAM,OAAO,OAAO;KAGjC,KAAK;KACL,KAAK;KACL,KAAK;KACL,KAAK,QACH,OAAO;KACT,KAAK;MACH,IAAI,KAAK,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,gBAAgB;MAC3E,OAAO,IAAI,MAAM,KAAK,KAAK;KAC7B,KAAK;MACH,MAAM,IAAI,YAAY;MACtB,OAAO;KACT,KAAK,WACH,OAAO,SAAS,CAAC,CAAC,QAAQ;KAC5B,KAAK,aAAa;MAChB,IAAI,KAAK,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,gBAAgB;MAC3E,MAAM,QAAQ,MAAM,IAAI,MAAM,KAAK,KAAK;MAExC,IAAI,YAAY,KAAK,SAAS,KAAK,MAAM,WAAW,UAAU,KAAK,SAAS,KAAA,KAAa,UAAU,MAAM;OACvG,MAAM,OAAO;QAAE,KAAK,KAAK,MAAM;QAAK,QAAQ;OAAO;OACnD,UAAU,IAAI,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,WAAW;QAC1F,IAAI,WAAW,MAAM,MAAM,IAAI,MAAM,WAAW,KAAK,IAAI,wBAAwB;QACjF,OAAO;QACP,OAAO;OACT,CAAC;OACD,QAAQ,YAAY,KAAA,CAAS;MAC/B;MACA,OAAO;KACT;KACA,SAEE,OAAO,IAAI,MAAM,aAAa,OAAO;IACzC;GACF;GACA,MAAM,OAAO,YAA2B;IACtC,QAAQ,KAAK,OAAb;KACE,KAAK;MACH,IAAI,WAAW;OACb,IAAI,YAAY,MAAM,MAAM,QAAQ,YAAY,IAAI,OAAO,MAAM,CAAC;YAC7D,MAAM,IAAI,OAAO,MAAM;OAC5B;MACF;MACA,OAAO,KAAK,KAAK;KACnB,KAAK;KACL,KAAK;KACL,KAAK;KACL,KAAK;KACL,KAAK;KACL,KAAK,QACH;KACF,KAAK;MAEH,IAAI,KAAK,UAAU,KAAA,KAAa,YAAY,KAAK,SAAS,KAAK,MAAM,WAAW,QAAQ;OACtF,MAAM,OAAO;QAAE,KAAK,KAAK,MAAM;QAAK,QAAQ;OAAO;OACnD,IAAI,YAAY,MAAM,MAAM,QAAQ,YAAY,IAAI,MAAM,IAAI,CAAC;YAC1D,MAAM,IAAI,MAAM,IAAI;OACzB;MACF;MAEA,IAAI,KAAK,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,KAAK,OAAO,IAAI;MAC9D;KACF,KAAK,eACH,OAAO,IAAI,KAAK,UAAU,SAAS,EAAE,MAAM,KAAK,QAAQ,OAAO,CAAC;KAClE,KAAK,WACH,OAAO,IAAI,KAAK,aAAa,SAAS,OAAO;KAC/C,KAAK,iBACH,OAAO,IAAI,KAAK,OAAO,KAAK,WAAW,UAAU,EAAE,OAAO,KAAK,OAAO,KAAK,CAAC;KAC9E,KAAK;MACH,MAAM,QAAQ,KAAA,CAAS;MACvB;KACF,KAAK,OACH,OAAO,IAAI,KAAK,OAAO,OAAO;KAChC,KAAK;MACH,MAAM,IAAI,MAAM,IAAI;MACpB;KACF,KAAK;MACH,MAAM,SAAS,CAAC,CAAC,MAAM;MACvB;KACF,SACE,OAAO,SAAS,OAAO,IAAI,KAAK,aAAa,OAAO,IAAI,KAAA;IAC5D;GACF;GACA,QAAQ,MAAM,MAAM;GACpB,IAAI;IAEF,IAAI,KAAK,eAAe,KAAA,KAAa,KAAK,MAAM,SAAS,QACvD,MAAM,MAAM,QAAQ,KAAK,YAAY,IAAI,CAAC;IAE5C,KAAK,KAAK,MAAM,SAAS,cAAc,KAAK,MAAM,SAAS,YAAY,KAAK,MAAM,SAAS,eAAe,CAAC,eAAe,MAAM,GAAG;IACnI,MAAM,EAAE,eAAe;IACvB,MAAM,OAAO,KAAK,MAAM,SAAS,KAAA;IACjC,IAAI,WAAW,YAAY,QAAQ,WAAW,WAAW,KAAA,GAAW;KAElE,IAAI,WAAW,SACb,MAAM,cAAc,aAAa;MAAE,GAAG,QAAQ;MAAG;KAAM,IAAI,aAAa,IAAI,CAAC;UAE7E,MAAM,MAAM,QAAQ,WAAW,QAAQ,GAAG,IAAI,GAAK;KAErD,MAAM,MAAM,OAAO;IACrB,OAAO,IAAI,KAAK,MAAM,SAAS,OAAO;KAEpC,MAAM,MAAM,KAAK,MAAM,MAAM,QAAQ,KAAA,IAAY,IAAI,QAAQ,KAAK,MAAM,KAAK,KAAK,GAAG;KACrF,MAAM,SAAS,QAAQ,WAAW,UAAU,WAAW,OAAO,WAAW,QAAQ,GAAG;KACpF,MAAM,MAAM,MAAM,YAAY,MAAM,UAAU,MAAQ,GAAM,CAAC,CAAC,YAAY,KAAA,CAAS;KACnF,IAAI,WAAW,YAAY,QAAQ,WAAW,WAAW,KAAA,GAAW,MAAM,aAAa,KAAK,YAAY,WAAW,MAAM;IAC3H,OAAO,IAAI,KAAK,UAAU,SAAS;KACjC,IAAI,KAAK,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,wBAAwB;KAGnF,MAAM,SAAS,QAAQ,WAAW,UAAU,WAAW,OAAO,WAAW,QAAQ,GAAG;KACpF,MAAM,OACJ,KAAK,MAAM,SAAS,SAChB,MAAM,SAAS,OAAO,OAAO,MAAM,GAAG,SAAS,GAAK,IACpD,MAAM,YAAY,OAAO,GAAK;KACpC,OAAO,MAAM,IAAI,KAAK,SAAS,KAAK,IAAI,QAAQ,KAAK,OAAO,GAAG,IAAI,GAAG;KACtE,MAAM,MAAM,MAAM;MAAC;MAAQ;MAAS;MAAO;KAAM,GAAG,SAAS,GAAK,CAAC,CAAC,YAAY,KAAA,CAAS;IAC3F,OAAO,IAAI,KAAK,UAAU,WAAW;KAGnC,MAAM,SAAS,QAAQ,WAAW,UAAU,WAAW,OAAO,WAAW,QAAQ,GAAG;KACpF,MAAM,YAAY,OAAO,GAAK;KAC9B,MAAM,MAAM,MAAM;MAAC;MAAQ;MAAS;MAAO;KAAM,GAAG,SAAS,GAAK,CAAC,CAAC,YAAY,KAAA,CAAS;KACzF,MAAM,MAAM,UAAU;KACtB,MAAM,QAAQ,UAAU,SAAS,CAAC,CAAC,OAAO,MAAM,UAAU,GAAG,OAAO,MAAM,CAAC;KAC3E,OAAO,UAAU,OAAO,OAAO;MAAE,IAAI;MAAO,IAAI;KAAM;IACxD,OAAO,IAAI,WAAW,YAAY,MAAM;KAEtC,MAAM,SAAS,QAAQ,WAAW,QAAQ,GAAG,IAAI;KACjD,MAAM,MAAM,MAAM;MAAC;MAAQ;MAAS;MAAO;KAAU,GAAG,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;IACvF,OAAO,IAAI,WAAW,SAAS;KAE7B,MAAM,SAAS,YAAY,UAAU,IAAI,MAAQ;KACjD,IAAI,KAAK,aAAa,KAAA,KAAa,KAAK,aAAa,UAEnD,MAAM,cAAc,MAAM,SAAS,cAAc,IAAI,OAAO,MAAM,UAAU,CAAC,CAAC,MAAM,SAAS,KAAK,OAAO,MAAM,CAAC;UAC3G,IAAI,QAAQ,KAAK,MAAM,SAAS,QAErC,MAAM,MAAM,MAAM,WAAW,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;UAI1D,MAAM,MAAM,MAAM;MAAC;MAAS;MAAO;MAAY;MAAQ,GAAI,OAAO,CAAC,QAAQ,IAAI,CAAC;KAAE,GAAG,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;IAEtH,OACE,MAAM,MAAM,QAAQ,WAAW,QAAQ,GAAG,IAAI,GAAK;GAEvD,UAAU;IACR,MAAM,KAAK;IACX,IAAI,YAAY,MAAM,IAAI,MAAM,IAAI;GACtC;GAGA,IAAI,KAAK,UAAU,oBAAoB,CAAC,UAAU,KAAK,MAAM,SAAS,UAAU,KAAK,MAAM,SAAS,YAClG,MAAM,MAAM,MAAM,CAAC,MAAM,GAAG,GAAK,CAAC,CAAC,YAAY,KAAA,CAAS;GAG1D,MAAM,WAAW,KAAK,WAAW,YAAY,QAAQ,KAAK,WAAW,aAAa,KAAA;GAClF,IAAI,aAAa,KAAA,GAAW;IAC1B,MAAM,QAAQ,SAAS,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC;IACnF,MAAM,MAAM,OAAO,IAAI,SAAS,MAAM,QAAQ,QAAQ,MAAQ,GAAK;GACrE;EACF;CACF,UAAU;EACR,MAAM,MAAM,KAAK;CACnB;CAEA,MAAM,UAAU,MAAM,IAAI,OAAO;CACjC,MAAM,OAAO,YAAY,OAAO,OAAO,UAAU;CACjD,OAAO;EACL;EACA;EACA,QAAQ,CAAC,GAAG,MAAM,MAAM;EACxB;EACA,GAAI,KAAK,UAAU,WAAW,KAAK,UAAU,aAAa,YAAY,OAAO,EAAE,KAAK,IAAI,CAAC;EACzF,QAAQ,IAAI,OAAO,MAAM,IAAI;EAC7B,OAAO,IAAI,MAAM;EACjB,aAAa,IAAI,MAAM;EACvB;EACA,GAAG;EACH,GAAI,IAAI,aAAa,OAAO,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU,MAAM,aAAa,EAAE;EACjF,GAAI,KAAK,OAAO,UAAU,OAAO,EAAE,QAAQ,IAAI,OAAO,MAAM,UAAU,EAAE,IAAI,CAAC;EAC7E,GAAI,IAAI,WAAW,KAAA,KAAa,aAAa,KAAA,IACzC,CAAC,IACD,EAAE,QAAQ;GAAE,QAAQ,IAAI,OAAO,OAAO,MAAM,UAAU;GAAG,aAAa;IAAE,QAAQ;IAAU,OAAO,MAAM,IAAI,OAAO,SAAS;GAAE;EAAE,EAAE;CACvI;AACF;;AAGA,MAAa,UAAU,MAAc,iBACnC,MAAM,KACJ,EAAE,QAAQ,aAAa,IACtB,GAAG,OAAO,KAAK,MAAM,OAAO,YAAY,KAAK,KAAK,OAAO,eAAe,IAAI,EAC/E,CAAC,CAAC,QAAQ,UAAU,QAAQ,CAAC;;;;;AAM/B,MAAM,mBAAmB,SACvB,KAAK,UAAU,QAAS,KAAK,UAAU,UAAU,KAAK,aAAa,KAAA,KAAa,KAAK,aAAa;;AAGpG,MAAM,QAAQ,MAAY,KAAU,SAClC,GAAG,KAAK,KAAK,QAAQ,IAAI,YAAY,GAAG,IAAI,WAAW,OAAO,YAAY,OAAO,IAAI,QAAQ,GAAG,KAAK,QAAQ,OAC1G,KAAK,YAAY,OAAO,KAAK,IAAI,KAAK,QAAQ,MAAM,MACpD,KAAK,SAAS,OAAO,KAAK,WAAW,KAAK,KAAK;;AAGpD,MAAM,YAAY,OAAO,SAA2C;CAClE,MAAM,SAAS,QAAQ;CACvB,MAAM,MAAM,MAAM,KAAK;CACvB,MAAM,QAAQ,QAAQ;CACtB,MAAM,QAAQ,WAAW,QAAQ,UAAU,OAAO,OAAO,WAAW,QAAQ,KAAK;CACjF,OAAO,UAAU,OAAO,MAAM;EAAE,GAAG;EAAK;CAAM;AAChD;;;;;;;AAQA,MAAM,gBAAgB,OACpB,MACA,aACA,OACA,QAC8D;CAC9D,IAAI,KAAK,UAAU,KAAA,GAAW,OAAO,mBAAmB,MAAM,aAAa,OAAO,GAAG;CACrF,IAAI,KAAK,eAAe,KAAA,GAAW,OAAO,wBAAwB,MAAM,aAAa,OAAO,GAAG;CAC/F,IAAI,KAAK,YAAY,KAAA,GAAW,OAAO,qBAAqB,MAAM,aAAa,OAAO,GAAG;CACzF,IAAI,KAAK,UAAU,KAAA,GAAW,OAAO,mBAAmB,MAAM,aAAa,OAAO,GAAG;CACrF,IAAI,KAAK,SAAS,KAAA,GAAW,OAAO,kBAAkB,MAAM,aAAa,OAAO,GAAG;CACnF,MAAM,MAAM,MAAM,QAAQ,KAAK,QAAQ,KAAK,UAAU,KAAK,MAAM,QAAQ,QAAQ,OAAO,KAAK,QAAQ;CACrG,IAAI;EAEF,MAAM,WAAW,MAAM,IAAI,UAAU,KAAK,kBAAkB,CAAC,CAAC;EAC9D,MAAM,gBAAgB,MAAM,IAAI,aAAa,KAAK,iBAAiB,CAAC,CAAC;EACrE,IAAI,KAAK,gBAAgB,KAAA,GAAW,MAAM,IAAI,MAAM,KAAK,WAAW;EAGpE,IAAI,KAAK,UAAU,mBAAmB,KAAK,UAAU,SAAS;GAC5D,MAAM,IAAI,QAAQ,OAAO,QAAQ;GACjC,MAAM,IAAI,QAAQ,OAAO,QAAQ;GACjC,IAAI,WAAW,KAAK,OAAO,GAAG,MAAM,IAAI,QAAQ,OAAO,KAAK,OAAO;EACrE;EAEA,MAAM,UAAU,UAAU,MAAM,KAAA,CAAS;EACzC,IAAI,YAAY,MAAM,MAAM,IAAI,MAAM,SAAS,QAAQ;EAEvD,MAAM,IAAI,KAAK;EACf,MAAM,WAAW,MAAM,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK,OAAO,GAAG,UAAU,aAAa;EAE3F,MAAM,UAAU,MAAM,IACnB,eAAe,KAAK,kBAAkB,CAAC,CAAC,CAAC,CACzC,WAAW,IAAI,WAAW,KAAK,eAAe,CAAC,CAAC,CAAC,CAAC,CAClD,WACO,KAAA,IACL,UAAoB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAC5E;EAEF,MAAM,SAAS,SAAmB;GAAE,GAAG;GAAK,QAAQ,SAAS,MAAM,GAAG;GAAG,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ;EAAG;EAEvH,MAAM,SAAc;GAAE,GADP,MAAM,MAAM,gBAAgB,KAAK,KAAK,MAAM,aAAa,IAAI,gBAAgB,IAAI,CAAC,CAAC,CACpE;GAAG,QAAQ;EAAK;EAC9C,IAAI,KAAK,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,CAAC;EAC7C,MAAM,OAAc,CAAC;EACrB,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;GAC7C,MAAM,MAAM,MAAM,MAAM,gBAAgB,KAAK,KAAK,MAAM,aAAa,KAAK,CAAC,CAAC;GAC5E,KAAK,KAAK,GAAG;GACb,IAAI,KAAK,MAAM,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC;EACzC;EACA,MAAM,OAAO,MAAM,IAAI,YAAY;EACnC,OAAO;GAAE,UAAU,KAAK,WAAW,IAAI,WAAW;IAAE,GAAG;IAAU;GAAK;GAAG;GAAM;EAAO;CACxF,UAAU;EACR,MAAM,IAAI,MAAM;CAClB;AACF;;;;;;AAOA,MAAM,qBAAqB,OACzB,MACA,aACA,OACA,QAC8D;CAC9D,MAAM,MAAM,MAAM,aAAa,KAAK,OAAQ,EAAE,gBAAgB,KAAK,eAAe,YAAY,CAAC;CAC/F,IAAI;EACF,MAAM,WAAW,MAAM,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK,OAAO,CAAC;EAElE,MAAM,SAAc;GAAE,GAAG,MADJ,UAAU,KAAK,MAAM,aAAa,EAAE;GACxB,QAAQ;EAAK;EAC9C,IAAI,KAAK,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,CAAC;EAC7C,MAAM,OAAc,CAAC;EACrB,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;GAC7C,MAAM,MAAM,MAAM,UAAU,KAAK,MAAM,aAAa,KAAK;GACzD,KAAK,KAAK,GAAG;GACb,IAAI,KAAK,MAAM,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC;EACzC;EACA,OAAO;GAAE;GAAU;GAAM;EAAO;CAClC,UAAU;EACR,MAAM,IAAI,MAAM;CAClB;AACF;;;;;AAMA,MAAM,0BAA0B,OAC9B,MACA,aACA,OACA,QAC8D;CAC9D,MAAM,MAAM,MAAM,kBAAkB,KAAK,YAAa,KAAK,UAAU,KAAA,CAAS;CAC9E,MAAM,OAAO,KAAK,UAAU,KAAA,IAAY,iBAAiB;CACzD,IAAI;EACF,MAAM,WAAW,MAAM,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK,OAAO,CAAC;EAElE,MAAM,SAAc;GAAE,GAAG,MADJ,KAAK,KAAK,MAAM,aAAa,EAAE;GACnB,QAAQ;EAAK;EAC9C,IAAI,KAAK,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,CAAC;EAC7C,MAAM,OAAc,CAAC;EACrB,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;GAC7C,MAAM,MAAM,MAAM,KAAK,KAAK,MAAM,aAAa,KAAK;GACpD,KAAK,KAAK,GAAG;GACb,IAAI,KAAK,MAAM,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC;EACzC;EACA,OAAO;GAAE;GAAU;GAAM;EAAO;CAClC,UAAU;EACR,MAAM,IAAI,MAAM;CAClB;AACF;;;;;AAMA,MAAM,oBAAoB,OACxB,MACA,aACA,OACA,QAC8D;CAC9D,MAAM,MAAM,MAAM,QAAQ,KAAK,QAAQ,KAAK,UAAU,KAAK,MAAM,QAAQ,QAAQ,OAAO,KAAK,QAAQ;CACrG,IAAI;EACF,MAAM,IAAI,KAAK;EACf,MAAM,WAAW,MAAM,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK,OAAO,CAAC;EAClE,MAAM,UAAU,MAAM,YAAY,KAAK,IAAI;EAE3C,MAAM,SAAc;GAAE,GAAG,MADJ,SAAS,KAAK,SAAS,MAAM,aAAa,IAAI,IAAI;GACtC,QAAQ;EAAK;EAC9C,IAAI,KAAK,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,CAAC;EAC7C,MAAM,OAAc,CAAC;EACrB,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;GAC7C,MAAM,MAAM,MAAM,SAAS,KAAK,SAAS,MAAM,aAAa,KAAK;GACjE,KAAK,KAAK,GAAG;GACb,IAAI,KAAK,MAAM,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC;EACzC;EACA,OAAO;GAAE;GAAU;GAAM;EAAO;CAClC,UAAU;EACR,MAAM,IAAI,MAAM;CAClB;AACF;;;;;AAMA,MAAM,uBAAuB,OAC3B,MACA,aACA,OACA,QAC8D;CAC9D,MAAM,MAAM,MAAM,eAAe,KAAK,OAAQ;CAC9C,IAAI;EACF,MAAM,WAAW,MAAM,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK,OAAO,CAAC;EAElE,MAAM,SAAc;GAAE,GAAG,MADJ,YAAY,KAAK,MAAM,aAAa,EAAE;GAC1B,QAAQ;EAAK;EAC9C,IAAI,KAAK,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,CAAC;EAC7C,MAAM,OAAc,CAAC;EACrB,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;GAC7C,MAAM,MAAM,MAAM,YAAY,KAAK,MAAM,aAAa,KAAK;GAC3D,KAAK,KAAK,GAAG;GACb,IAAI,KAAK,MAAM,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC;EACzC;EACA,OAAO;GAAE;GAAU;GAAM;EAAO;CAClC,UAAU;EACR,MAAM,IAAI,MAAM;CAClB;AACF;;;;;AAMA,MAAM,qBAAqB,OACzB,MACA,aACA,OACA,QAC8D;CAC9D,MAAM,MAAM,MAAM,aAAa,KAAK,KAAM;CAC1C,MAAM,OAAO,KAAK,MAAO,UAAU,KAAA,IAAY,YAAY;CAC3D,IAAI;EACF,MAAM,WAAW,MAAM,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK,OAAO,CAAC;EAElE,MAAM,SAAc;GAAE,GAAG,MADJ,KAAK,KAAK,MAAM,aAAa,EAAE;GACnB,QAAQ;EAAK;EAC9C,IAAI,KAAK,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,CAAC;EAC7C,MAAM,OAAc,CAAC;EACrB,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;GAC7C,MAAM,MAAM,MAAM,KAAK,KAAK,MAAM,aAAa,KAAK;GACpD,KAAK,KAAK,GAAG;GACb,IAAI,KAAK,MAAM,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC;EACzC;EACA,OAAO;GAAE;GAAU;GAAM;EAAO;CAClC,UAAU;EACR,MAAM,IAAI,MAAM;CAClB;AACF;;;;;;;;;;AAWA,MAAa,UAAU,OACrB,MACA,YAAoC,CAAC,MACb;CACxB,MAAM,2BAAU,IAAI,KAAK,EAAA,CAAE,YAAY;CACvC,MAAM,YAAwB,CAAC;CAC/B,MAAM,OAAc,CAAC;CACrB,MAAM,UAAiB,CAAC;CACxB,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,eAAe,CAAC;CACrD,IAAI,SAAiB,KAAK;CAC1B,IAAI,OAAO;CACX,SAAS;EACP,MAAM,SAAS,OAAO,SAAS,KAAK,QAAQ,KAAK,IAAI,KAAK,cAAc,WAAW,CAAC;EACpF,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM,aAAa;GACtD,MAAM,QAAQ,OAAO,MAAM,IAAI,KAAK,WAAW,CAAC,CAAC,KAAK,WAAW;IAAE;IAAO,KAAK;GAAO,EAAE;GACxF,MAAM,OAAO,MAAM,QAAQ,IACzB,MAAM,KAAK,EAAE,OAAO,UAAU,cAAc,MAAM,KAAK,OAAO,GAAG,CAAC,CACpE;GACA,KAAK,MAAM,QAAQ,MAAM;IACvB,UAAU,KAAK,KAAK,QAAQ;IAE5B,MAAM,KAAK,KAAK,SAAS,OAAO,OAAO,KAAA,IAAY,OAAO,KAAK,SAAS,EAAE;IAC1E,MAAM,UAAU,QAAmB,OAAO,KAAA,IAAY,MAAM;KAAE,GAAG;KAAK;IAAG;IACzE,KAAK,KAAK,GAAG,KAAK,KAAK,IAAI,MAAM,CAAC;IAClC,QAAQ,KAAK,OAAO,KAAK,MAAM,CAAC;GAClC;EACF;EACA,MAAM,EAAE,UAAU,YAAY,MAAM,MAAM,IAAI;EAC9C,MAAM,SAAS,MAAM,MAAM,SAAS,OAAO,KAAK,MAAM;EACtD,IAAI,QAAQ,aAAa,YAAY,WAAW,KAAA,GAE9C,OAAO;GAAE;GAAM;GAAW;GAAM;GAAS;GAAU;GAAS,IAAA;IAD/C;IAAS,wBAAO,IAAI,KAAK,EAAA,CAAE,YAAY;GACS;EAAE;EAEjE,SAAS;CACX;AACF"}
1
+ {"version":3,"file":"index.js","names":["spreadOf","middle","intervalOfMedian","median","between","newState","oldState","ERRNO","between","newState","oldState","ipOf","nameOf","between","numberOf","between","findingsOf","between","between","sleep","STEADY","sleep","peersOf","droppedSoFar","sleep","STEADY","TAIL_MS","waitFor","droppedSoFar","sleep","STEADY","TAIL_MS","waitFor","droppedSoFar","sleep","droppedSoFar","waitFor","TAIL_MS","sleep","RAW_TAIL","STEADY","TAIL_MS","waitFor","droppedSoFar","sleep","droppedSoFar","driverSettled"],"sources":["../src/load.ts","../src/verdict.ts","../src/application.ts","../src/driver.ts","../src/queue.ts","../src/conntrack.ts","../src/pause.ts","../src/ports.ts","../src/recovery.ts","../src/timeline.ts","../src/observe.ts","../src/fabric.ts","../src/substrate.ts","../src/lab.ts","../src/standby.ts","../src/pins.ts","../src/group.ts","../src/replset.ts","../src/drill.ts","../src/cluster.ts","../src/kafka.ts","../src/run.ts"],"sourcesContent":["import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { Rung, RungRecord } from \"@mark1russell7/rigor-bench\";\nimport { rungVerdict } from \"@mark1russell7/rigor-bench\";\nimport type { Completion, LoadMeasure, Schedule } from \"@mark1russell7/rigor-chaos\";\nimport { closedLoopPlan, measureLoad, schedule, scheduleHeld } from \"@mark1russell7/rigor-chaos\";\nimport { quantile } from \"@mark1russell7/rigor-statistics\";\nimport type { LoadPrediction, LoadStream, ProbeEvent, RunStream } from \"./cell.ts\";\n\n/**\n * The measure and the verdict of an open-loop cell (SYS-68). A client on a schedule sends each\n * arrival at its time, thus a stall counts in each arrival that it delayed. The package rigor-chaos\n * counts each latency from the planned time. The package rigor-bench judges a quantile by a\n * distribution-free interval.\n */\n\n/** This path is where the client of an open-loop cell finds its schedule. */\nexport const SCHEDULE_PATH = \"/tmp/schedule.json\";\n\n/** This function gives the time of a line of the client, in ms from the start of the schedule. */\nconst fromStart = (start: number, t: number): number => (t - start) / 1e6;\n\n/**\n * This function gives the measure of one run of a schedule from the lines of its client. It gives\n * null when the client did not start the schedule. The first `sent` line of a client is its request\n * before `ready`, and it names no arrival. The end of the run is its last line.\n */\nexport const loadOf = (events: readonly ProbeEvent[], plan: Schedule): RunLoad | null => {\n const start = events.find((event) => event.ev === \"scheduled\")?.t;\n if (start === undefined) return null;\n return measureOf(events, start, plan, undefined);\n};\n\n/**\n * A run load is the measure of one run of a schedule. `failed` counts the replies with a status\n * outside 200 to 299. Such a reply is a completion, thus its time is in `latency`. The client\n * `schedule` gives no status, and a record from before this field has none: both read as 0.\n */\nexport type RunLoad = LoadMeasure & { readonly failed?: number };\n\n/** This function tells if a status of a reply is a failure: a number outside 200 to 299. */\nconst failedStatus = (status: unknown): boolean => typeof status === \"number\" && (status < 200 || status > 299);\n\n/** This function gives the measure of the arrivals of one stream: the lines with the key `key`, or each line for no key. */\nconst measureOf = (events: readonly ProbeEvent[], start: number, plan: Schedule, key: string | undefined): RunLoad => {\n const sent = new Map<number, number>();\n const done = new Map<number, number>();\n let failed = 0;\n for (const event of events) {\n const index = event[\"i\"];\n if (typeof index !== \"number\" || (key !== undefined && event[\"k\"] !== key)) continue;\n if (event.ev === \"sent\") sent.set(index, fromStart(start, event.t));\n if (event.ev === \"replied\") {\n done.set(index, fromStart(start, event.t));\n if (failedStatus(event[\"status\"])) failed += 1;\n }\n }\n const completions: Completion[] = [...sent].map(([index, at]) => ({ index, sent: at, done: done.get(index) ?? null }));\n const end = events.reduce((latest, event) => Math.max(latest, fromStart(start, event.t)), 0);\n return { ...measureLoad(plan, completions, end), failed };\n};\n\n/** This path is where the client `load` finds its plan. */\nexport const LOAD_PATH = \"/tmp/load.json\";\n\n/** This text is the format of the plan of the client `load`. */\nexport const LOAD_FORMAT = \"systems-load/1\";\n\n/**\n * This function gives the schedule of each stream of a cell, and the text of the plan of the client\n * `load`. It throws for no stream, for two streams with one key and for a stream with no request.\n */\nexport const loadPlanOf = (streams: readonly LoadStream[]): { readonly streams: readonly RunStream[]; readonly content: string } => {\n if (streams.length === 0) throw new RangeError(\"a plan of the client load has no stream\");\n const keys = new Set<string>();\n for (const stream of streams) {\n if (keys.has(stream.key)) throw new RangeError(`two streams have the key ${stream.key}`);\n if (stream.requests.length === 0) throw new RangeError(`the stream ${stream.key} has no request`);\n keys.add(stream.key);\n }\n const scheduled = streams.map((stream) => ({ key: stream.key, schedule: schedule(stream.plan.profile, stream.plan.options), requests: stream.requests }));\n return {\n streams: scheduled.map(({ key, schedule: each }) => ({ key, schedule: each })),\n content: JSON.stringify({ format: LOAD_FORMAT, streams: scheduled }),\n };\n};\n\n/**\n * This function gives the measure of each stream of a run of the client `load`, and their pool. Each\n * stream counts its arrivals from 0, thus the lines of a stream are the lines with its key. The pool\n * sums the counts and joins the times, in the order of the streams. It gives null when the client did\n * not start its schedule.\n */\nexport const streamsLoadOf = (\n events: readonly ProbeEvent[],\n streams: readonly RunStream[],\n): { readonly pool: RunLoad; readonly streams: Readonly<Record<string, RunLoad>> } | null => {\n const start = events.find((event) => event.ev === \"scheduled\")?.t;\n if (start === undefined) return null;\n const each = streams.map((stream) => [stream.key, measureOf(events, start, stream.schedule, stream.key)] as const);\n return { pool: poolOf(each.map(([, measure]) => measure)), streams: Object.fromEntries(each) };\n};\n\n/** This function gives the pool of some measures: it sums the counts and joins the times, in the order of the measures. */\nexport const poolOf = (measures: readonly RunLoad[]): RunLoad & { readonly failed: number } => {\n const sum = (count: (measure: RunLoad) => number) => measures.reduce((total, measure) => total + count(measure), 0);\n const join = (times: (measure: RunLoad) => readonly number[]) => measures.flatMap(times);\n return {\n planned: sum((measure) => measure.planned),\n unsent: sum((measure) => measure.unsent),\n unfinished: sum((measure) => measure.unfinished),\n failed: sum((measure) => measure.failed ?? 0),\n latency: join((measure) => measure.latency),\n service: join((measure) => measure.service),\n lag: join((measure) => measure.lag),\n censored: join((measure) => measure.censored),\n };\n};\n\n/**\n * This time is the tolerance of a closed-loop estimate, in ms. A send later than its expected time\n * by more than this tolerance is a pause of the client: a driver gap.\n */\nexport const CLOSED_TOLERANCE = 5;\n\n/**\n * A run estimate is the latency of the open loop that a closed-loop stream hid (SYS-91). The package\n * rigor-chaos puts back each send that a stall or a pause of the client hid (`closedLoopPlan`).\n * `hidden` counts those sends, and `driverGaps` counts the pauses of the client. Its times are in ms.\n */\nexport type RunEstimate = LoadMeasure & { readonly hidden: number; readonly driverGaps: number; readonly driverGapTotal: number };\n\n/**\n * This function gives the estimate of one closed-loop stream from its requests, in the order of their\n * sends. Each time is a time of a line of the client. The client waits `interval` ms after each reply,\n * thus the interval is also the pause of the driver. The function gives undefined for no request, and\n * for a request with no reply before the last request.\n */\nexport const estimateOf = (\n requests: ReadonlyArray<{ readonly sent: number; readonly done: number | null }>,\n end: number,\n interval: number,\n): RunEstimate | undefined => {\n const start = requests[0]?.sent;\n if (start === undefined || requests.slice(0, -1).some((request) => request.done === null)) return undefined;\n const loop = requests.map((request) => ({ sent: fromStart(start, request.sent), done: request.done === null ? null : fromStart(start, request.done) }));\n const stop = Math.max(fromStart(start, end), ...loop.map((request) => request.done ?? request.sent), interval);\n const run = closedLoopPlan(loop, { interval, end: stop, tolerance: CLOSED_TOLERANCE, pause: interval });\n return { ...measureLoad(run.plan, run.completions, stop), hidden: run.hidden, driverGaps: run.driverGaps, driverGapTotal: run.driverGapTotal };\n};\n\n/** A load spread is a part of the distribution of one measure of an open-loop cell, over its counted runs. */\nexport interface LoadSpread {\n readonly p50: Quantity;\n readonly p99: Quantity;\n readonly max: Quantity;\n}\n\n/**\n * A load verdict sums the schedule of an open-loop cell over its counted runs. `latency` counts from\n * the planned time, and `service` counts from the send: the measure of a closed-loop driver. Each\n * arrival with no reply counts in `latency` at its age at the end of its run, a lower bound.\n */\nexport interface LoadVerdict {\n readonly planned: number;\n readonly unsent: number;\n readonly unfinished: number;\n /** This count is the replies with a status of a failure, over the counted runs. */\n readonly failed: number;\n readonly latency: LoadSpread | null;\n readonly service: LoadSpread | null;\n readonly lag: LoadSpread | null;\n /** This text is the verdict of each band, in the order of the prediction. */\n readonly bands: readonly string[];\n /** This text is the verdict of the share of failed arrivals, when the prediction has a limit on it. */\n readonly failures?: string;\n}\n\n/** This function gives the spread of a list of times in ms, or null for no time. */\nconst spreadOf = (values: readonly number[]): LoadSpread | null =>\n values.length === 0\n ? null\n : {\n p50: quantity(quantile(values, 0.5, \"nearest-rank\"), \"ms\"),\n p99: quantity(quantile(values, 0.99, \"nearest-rank\"), \"ms\"),\n max: quantity(values.reduce((most, value) => Math.max(most, value), 0), \"ms\"),\n };\n\n/** This time is the date of the record of a band and the date of its verdict. The record has no age, because it comes from this run. */\nconst NOW = \"2026-01-01T00:00:00.000Z\";\n\n/**\n * This function judges one band of the latency over the pooled arrivals of the counted runs. The\n * top of the band reads the interval of rigor-bench: the band holds only if the interval is under its top.\n * The latencies of one run can follow each other, thus the width of the interval is an estimate.\n * The bottom of the band reads the quantile itself. It gives the text of the verdict, and if it holds.\n */\nconst bandVerdict = (\n band: LoadPrediction[\"bands\"][number],\n values: readonly number[],\n censored: readonly number[],\n): { readonly holds: boolean; readonly words: string } => {\n const high = valueIn(band.high, \"ms\");\n const rung: Rung = {\n name: \"band\",\n at: {},\n budgets: [{ kind: \"quantile\", measure: \"latency\", unit: \"ms\", quantile: band.quantile, limit: high }],\n test: \"the cell\",\n };\n const record: RungRecord = {\n rung: \"band\",\n commit: \"the cell\",\n at: NOW,\n real: [\"the counted runs\"],\n synthetic: [],\n evidence: [{ kind: \"quantile\", measure: \"latency\", values, censored }],\n };\n const top = rungVerdict(rung, record, { now: NOW });\n const read = values.length + censored.length === 0 ? null : quantile([...values, ...censored], band.quantile, \"nearest-rank\");\n const low = band.low === undefined ? null : valueIn(band.low, \"ms\");\n const above = low === null || (read !== null && read >= low);\n const place = low === null ? `under ${high} ms` : `in [${low}, ${high}] ms`;\n // the rung judges only the top of the band: a read under its bottom is not within the band\n const outcome = top.outcome === \"within\" && !above ? \"under the bottom of the band\" : top.outcome;\n return {\n holds: top.outcome === \"within\" && above,\n words: `p${band.quantile * 100} of the latency ${read === null ? \"has no value\" : `is ${read} ms`}, wanted ${place}: ${outcome}. ${top.reason}`,\n };\n};\n\n/**\n * This function judges the share of failed arrivals over the counted runs against a limit. Each\n * planned arrival is a trial. An arrival fails if the client did not send it. It also fails with no\n * reply at the end of its run, or with the status of a failure. The rate budget of rigor-bench\n * reads the upper end of the Wilson interval at 0.95. Thus 381 arrivals with no failure hold a limit\n * of 1 %, and fewer arrivals cannot decide.\n */\nconst failuresVerdict = (limit: number, failures: number, trials: number): { readonly holds: boolean; readonly words: string } => {\n const rung: Rung = { name: \"failures\", at: {}, budgets: [{ kind: \"rate\", measure: \"failures\", limit }], test: \"the cell\" };\n const record: RungRecord = {\n rung: \"failures\",\n commit: \"the cell\",\n at: NOW,\n real: [\"the counted runs\"],\n synthetic: [],\n evidence: [{ kind: \"rate\", measure: \"failures\", failures, trials }],\n };\n const verdict = rungVerdict(rung, record, { now: NOW });\n return {\n holds: verdict.outcome === \"within\",\n words: `${failures} of ${trials} arrivals failed, wanted a share under ${limit * 100} %: ${verdict.outcome}. ${verdict.reason}`,\n };\n};\n\n/** This record is what the verdict of a cell takes from its load: the runs that broke the schedule, and the sum. */\nexport interface LoadJudgement {\n readonly holds: boolean;\n readonly outside: ReadonlyArray<{ readonly run: string; readonly why: string }>;\n readonly load: LoadVerdict;\n}\n\n/**\n * This function judges the load of an open-loop cell over its counted runs. A run that did not keep\n * its schedule measures its driver, not the target, thus it is a finding of that run. Each\n * band reads all the arrivals of the counted runs.\n */\nexport const loadVerdict = (\n prediction: LoadPrediction,\n runs: ReadonlyArray<{ readonly name: string; readonly load: RunLoad | undefined }>,\n): LoadJudgement => {\n const limit = valueIn(prediction.lag, \"ms\");\n const outside = runs.flatMap((run) => {\n if (run.load === undefined) return [{ run: run.name, why: \"the client never started its schedule\" }];\n const check = scheduleHeld(run.load, limit);\n return check.held ? [] : [{ run: run.name, why: check.reason }];\n });\n const measures = runs.flatMap((run) => (run.load === undefined ? [] : [run.load]));\n const latency = measures.flatMap((measure) => measure.latency);\n const censored = measures.flatMap((measure) => measure.censored);\n const bands = prediction.bands.map((band) => bandVerdict(band, latency, censored));\n const total = (count: (measure: RunLoad) => number) => measures.reduce((sum, measure) => sum + count(measure), 0);\n const planned = total((measure) => measure.planned);\n const unsent = total((measure) => measure.unsent);\n const unfinished = total((measure) => measure.unfinished);\n const failed = total((measure) => measure.failed ?? 0);\n const failures = prediction.failures === undefined ? undefined : failuresVerdict(prediction.failures, unsent + unfinished + failed, planned);\n return {\n holds: runs.length > 0 && outside.length === 0 && bands.every((band) => band.holds) && (failures?.holds ?? true),\n outside,\n load: {\n planned,\n unsent,\n unfinished,\n failed,\n latency: spreadOf([...latency, ...censored]),\n service: spreadOf(measures.flatMap((measure) => measure.service)),\n lag: spreadOf(measures.flatMap((measure) => measure.lag.map((lag) => Math.abs(lag)))),\n bands: bands.map((band) => band.words),\n ...(failures === undefined ? {} : { failures: failures.words }),\n },\n };\n};\n\n/**\n * An estimate verdict sums the closed-loop estimates of a cell over its counted runs. Its latency\n * is an estimate of the open loop, not a measure of it: a record of an open-loop client stays the\n * better measure. Each hidden send after a request with no reply counts at its age at the end.\n */\nexport interface EstimateVerdict {\n readonly planned: number;\n readonly hidden: number;\n readonly driverGaps: number;\n readonly driverGapTotal: Quantity;\n readonly latency: LoadSpread | null;\n /** This text gives the estimate in words, for the verdict of the cell. */\n readonly words: string;\n}\n\n/** This function gives the estimate verdict of the counted runs, or undefined when no run has an estimate. */\nexport const estimateVerdict = (estimates: ReadonlyArray<RunEstimate | undefined>): EstimateVerdict | undefined => {\n const runs = estimates.filter((estimate): estimate is RunEstimate => estimate !== undefined);\n if (runs.length === 0) return undefined;\n const pool = poolOf(runs);\n const total = (count: (estimate: RunEstimate) => number) => runs.reduce((sum, estimate) => sum + count(estimate), 0);\n const hidden = total((estimate) => estimate.hidden);\n const driverGaps = total((estimate) => estimate.driverGaps);\n const driverGapTotal = total((estimate) => estimate.driverGapTotal);\n const latency = spreadOf([...pool.latency, ...pool.censored]);\n const seconds = (time: Quantity) => (valueIn(time, \"ms\") / 1000).toFixed(3);\n const spread = latency === null ? \"no latency\" : `median ${seconds(latency.p50)} s, p99 ${seconds(latency.p99)} s, slowest ${seconds(latency.max)} s`;\n const gaps = driverGaps === 0 ? \"no pause of the client\" : `${driverGaps} pauses of the client, ${Math.round(driverGapTotal)} ms in all`;\n return {\n planned: pool.planned,\n hidden,\n driverGaps,\n driverGapTotal: quantity(driverGapTotal, \"ms\"),\n latency,\n words: `The estimate of the open loop puts back ${hidden} hidden sends, with ${gaps}: ${spread}.`,\n };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport { medianInterval as intervalOfMedian, median as middle, quantileSorted } from \"@mark1russell7/rigor-statistics\";\nimport type { Prediction, Run, Stage } from \"./cell.ts\";\nimport type { EstimateVerdict, LoadVerdict } from \"./load.ts\";\nimport { estimateVerdict, loadVerdict } from \"./load.ts\";\nimport type { Measured, Reordering } from \"./observe.ts\";\n\n/** This function gives the words of the outcome of a second request: its connection, a retry, and its end. */\nexport const requestWords = (outcome: {\n readonly connection: \"reused\" | \"new\";\n readonly retried: boolean;\n readonly error: string | null;\n readonly pending?: boolean | undefined;\n}): string =>\n `${outcome.connection}${outcome.retried ? \", a retry\" : \"\"}, ${outcome.pending === true ? \"pending\" : (outcome.error ?? \"a reply\")}`;\n\n/**\n * This amount is the noise of the pipeline itself, δ_abs, as the calibration measured it. It is\n * the 99.9th percentile of the whole latency of a reset, at the concurrency cap or less. Its\n * minimum is one jiffy. On 2026-10-12 the worst of 60 resets at 1 and 4 environments took\n * 1.141 ms, thus the minimum sets it to 4 ms. The calibration occurs again after each change to\n * the harness, the kernel or Docker.\n */\nexport const NOISE: Quantity = quantity(4, \"ms\");\n\n/**\n * This time is how late the injector can commit or lift a fault before the run is void. Stage 0\n * measures the commit apart from δ_abs, and the commit is longer. On a hosted runner it took up to\n * 2.75 ms at 4 environments, where δ_abs is 1 ms. Thus a cell's δ_abs does not change it.\n */\nexport const INJECT: Quantity = NOISE;\n\n/** This function gives the δ_abs of a cell: its own, or `NOISE` for a cell that gives none. */\nexport const noiseOf = (cell: { readonly noise?: Quantity | undefined }): Quantity => cell.noise ?? NOISE;\n\n/**\n * A pairing is the window of a run in which a line of its program pairs with the kernel's record\n * of its act. `bound` is the jitter of the program that the run measured, or null. `delta` is the\n * window: δ_abs of the cell, or the bound when the bound is longer.\n */\nexport interface Pairing {\n readonly bound: Quantity | null;\n readonly delta: Quantity;\n}\n\n/**\n * This function gives the pairing window of a run (SYS-25). On a runner of GitHub, the jitter of\n * a program can be longer than the δ_abs of 1 ms. Thus each run measures it before its fault\n * (`Run.jitter`), and its own measurement widens its window. A run without a jitter record is\n * from before SYS-25. It reads as a bound of null, thus its window is δ_abs. The decision of\n * 2026-10-19 keeps the rule of one miss: a pair that a window misses is still a finding.\n */\nexport const pairingOf = (cell: { readonly noise?: Quantity | undefined }, run: Pick<Run, \"jitter\">): Pairing => {\n const noise = noiseOf(cell);\n const bound = run.jitter?.bound ?? null;\n return { bound, delta: bound !== null && valueIn(bound, \"s\") > valueIn(noise, \"s\") ? bound : noise };\n};\n\n/**\n * This function sums the pairings of the measurements of a cell. It gives the longest bound and\n * the longest window. It also counts the pairings whose window is longer than δ_abs (`noise`). It\n * is null when no measurement has a pairing.\n */\nexport const pairingsOf = (\n runs: readonly Measured[],\n noise: Quantity = NOISE,\n): { readonly bound: Quantity | null; readonly delta: Quantity; readonly widened: number } | null => {\n const pairings = runs.flatMap((run) => (run.pairing === undefined ? [] : [run.pairing]));\n if (pairings.length === 0) return null;\n const longest = (values: readonly Quantity[]): Quantity => values.reduce((most, each) => (valueIn(each, \"s\") > valueIn(most, \"s\") ? each : most));\n const bounds = pairings.flatMap((pairing) => (pairing.bound === null ? [] : [pairing.bound]));\n return {\n bound: bounds.length === 0 ? null : longest(bounds),\n delta: longest(pairings.map((pairing) => pairing.delta)),\n widened: pairings.filter((pairing) => valueIn(pairing.delta, \"s\") > valueIn(noise, \"s\")).length,\n };\n};\n\n/**\n * This function tells if a timer firing came late enough to void a run. A firing two jiffies or\n * more behind its wheel slot came late because the host stopped a vCPU. With the HZ of the run,\n * the rule is in time: the delay must also reach δ_abs, because each band already includes that\n * noise. At HZ 250 two jiffies are 8 ms, more than a δ_abs of 4 ms. At HZ 1000 they are 2 ms.\n */\nexport const delayVoids = (behind: number, hz: number | undefined, noise: Quantity): boolean => {\n if (behind < 2) return false;\n if (hz === undefined || !(hz > 0)) return true;\n return behind / hz >= Math.max(2 / hz, valueIn(noise, \"s\"));\n};\n/** This fraction, δ_rel, is how far the median of a cell can be outside the prediction and stay equivalent. */\nexport const RELATIVE = 0.05;\n/** These are the run counts of a cell: 11, then 22 and 44 while its median crosses the edge of the band. */\nexport const STEPS = [11, 22, 44] as const;\n\n/**\n * A decision is the result of a verdict. A cell whose outcome is a distribution has no band, and\n * its decision is `measured`: a record, not a test.\n */\nexport type Decision = \"holds\" | \"fails\" | \"extend\" | \"inconclusive\" | \"measured\";\n\n/** An interval is a range of times. */\nexport interface Interval {\n readonly low: Quantity;\n readonly high: Quantity;\n}\n\n/** A spread is the distribution of a set of times: its count, its median and its upper quantiles by nearest rank. */\nexport interface Spread {\n readonly count: number;\n readonly median: Quantity;\n readonly p99: Quantity;\n readonly p999: Quantity;\n readonly max: Quantity;\n}\n\n/** A verdict is the judgement of a cell on its runs. */\nexport interface Verdict {\n readonly decision: Decision;\n readonly counted: number;\n readonly voided: number;\n /** This band is where each run must land: [T_lo − δ_abs, T_hi + δ_abs]. It is null for a silent prediction. */\n readonly band: Interval | null;\n /** These are the runs outside the band, and the reason for each. Each is a finding. */\n readonly outside: ReadonlyArray<{ readonly run: string; readonly why: string }>;\n readonly median: Quantity | null;\n /** This interval is the order-statistic interval of the median at 95 %, or the whole range for fewer than six runs. */\n readonly medianInterval: Interval | null;\n /** This time is the slowest reply of a cell that measures a distribution. A closed loop hides the sends in a stall, thus a quantile is a lower bound, and this maximum is not. */\n readonly slowest?: Quantity;\n /** This record is the sum of what reordering did in each counted run of a measurement-only cell. */\n readonly reordering?: Reordering;\n /** This record is the load of an open-loop cell over its counted runs. */\n readonly load?: LoadVerdict;\n /** This record is the estimate of the open loop of a closed-loop stream over its counted runs (SYS-91). */\n readonly estimate?: EstimateVerdict;\n /** This record is the time of the proxy of a calibration cell, in each direction. */\n readonly proxy?: { readonly hop: string; readonly up: Spread | null; readonly down: Spread | null };\n /** This record is what the group of a group cell did over the counted runs: its stages, and its writes. */\n readonly group?: GroupVerdict;\n /**\n * These are the outcomes of the second request of an HTTP client over the counted runs, each\n * with its count: for example \"reused, a retry, a reply\". An outcome other than the predicted\n * one is a finding of its run.\n */\n readonly requests?: Readonly<Record<string, number>>;\n /** This record is what the client did after the detection over the counted runs, for a prediction that says when it reconnects. */\n readonly reconnect?: ReconnectVerdict;\n /** These are the outcomes of the call in flight of a WebSocket client over the counted runs, each with its count. */\n readonly calls?: Readonly<Record<string, number>>;\n /**\n * This record is the time from a drop of the program to the close of its socket by its own side,\n * over the counted runs. It also counts the runs where the socket did not close itself.\n * `exited` is the spread of the end of the client process, for the runs where the socket stayed\n * open until that end (`Measured.exited`).\n */\n readonly left?: { readonly spread: Spread | null; readonly stayed: number; readonly exited?: Spread | null };\n readonly why: string;\n}\n\n/**\n * A reconnect verdict sums the reconnect of the client over the counted runs. Each wait before a\n * try gets its spread. A wait outside its band is a finding of its run, thus it is in `outside`.\n * - `syn` is the time from the detection to the first SYN of a new socket.\n * - `established` is the time from the detection to the first new socket that became ESTABLISHED.\n * - `connect` is the time from a `dial` line to the SYN of its socket: the work of the program.\n */\nexport interface ReconnectVerdict {\n readonly waits: ReadonlyArray<Spread | null>;\n readonly syn: Spread | null;\n readonly established: Spread | null;\n readonly connect: Spread | null;\n}\n\n/**\n * A stage verdict is the test of one stage of the timeline of a group against its band. The band\n * is [T_lo − δ_abs, T_hi + the error of the stamps + δ_abs]. A run that did not announce the stage\n * is outside too.\n */\nexport interface StageVerdict {\n readonly stage: Stage;\n readonly band: Interval;\n readonly median: Quantity | null;\n readonly outside: ReadonlyArray<{ readonly run: string; readonly why: string }>;\n readonly decision: \"holds\" | \"fails\";\n}\n\n/**\n * A group verdict sums what the group of a group cell did in its counted runs:\n * - `stages` tests each stage that the prediction gives a band.\n * - `medians` is the median of each stage that a run announced, from the fault.\n * - `lost` counts the writes that a primary accepted and the group did not keep, in each run.\n * - `old` counts the writes that the old primary accepted after the fault, in each run.\n * - `unknown` counts the writes whose outcome the client did not see, and how many the group kept.\n * - `errors` are the errors on the way: the runs that met each, and the median of its first time.\n * - `lags` is the spread of the delays of the stamps, for a calibration.\n * - `duplicates` counts the extra copies that the group holds, in each run. A cell with no band of\n * copies has no such count.\n */\nexport interface GroupVerdict {\n readonly stages: readonly StageVerdict[];\n readonly medians: Partial<Record<Stage, Quantity>>;\n readonly lost: { readonly runs: number; readonly total: number; readonly median: number | null; readonly max: number | null };\n readonly old: { readonly median: number | null; readonly max: number | null };\n readonly unknown: { readonly total: number; readonly held: number };\n readonly errors: ReadonlyArray<{ readonly name: string; readonly runs: number; readonly first: Quantity }>;\n readonly lags?: Spread | null;\n readonly duplicates?: { readonly runs: number; readonly total: number; readonly median: number | null; readonly max: number | null };\n}\n\nconst s = (value: number): Quantity => quantity(Math.round(value * 1e6) / 1e6, \"s\");\nconst name = (run: Measured): string => `env ${run.environment} run ${run.index}`;\n\n/**\n * This function gives the value at quantile p of sorted values, by nearest rank: x_(⌈p·n⌉). It is\n * `quantileSorted` of @mark1russell7/rigor-statistics with the method `\"nearest-rank\"`.\n */\nexport const quantileOf = (sorted: readonly number[], p: number): number => quantileSorted(sorted, p, \"nearest-rank\");\n\n/** This function gives the spread of a set of times, or null for none. */\nexport const spreadOf = (times: readonly Quantity[]): Spread | null => {\n if (times.length === 0) return null;\n const sorted = times.map((time) => valueIn(time, \"s\")).sort((a, b) => a - b);\n return {\n count: sorted.length,\n median: s(middle(sorted)),\n p99: s(quantileOf(sorted, 0.99)),\n p999: s(quantileOf(sorted, 0.999)),\n max: s(sorted.at(-1)!),\n };\n};\n\n/** This function adds the reordering records of runs: the counts add, and each largest value is the largest of all. */\nconst reorderingTotal = (runs: readonly Measured[]): Reordering | undefined => {\n const each = runs.flatMap((run) => (run.reordering === undefined ? [] : [run.reordering]));\n if (each.length === 0) return undefined;\n const sum = (key: \"outOfOrder\" | \"duplicates\" | \"fast\") => each.reduce((total, one) => total + one[key], 0);\n const add = (key: \"ooo\" | \"dsacks\" | \"seen\") =>\n each.some((one) => one[key] !== null) ? each.reduce((total, one) => total + (one[key] ?? 0), 0) : null;\n const top = (key: \"sacked\" | \"lost\" | \"degree\") =>\n each.some((one) => one[key] !== null) ? Math.max(...each.map((one) => one[key] ?? 0)) : null;\n return {\n outOfOrder: sum(\"outOfOrder\"),\n duplicates: sum(\"duplicates\"),\n ooo: add(\"ooo\"),\n sacked: top(\"sacked\"),\n lost: top(\"lost\"),\n dsacks: add(\"dsacks\"),\n fast: sum(\"fast\"),\n degree: top(\"degree\"),\n seen: add(\"seen\"),\n };\n};\n\n/** This function says a reordering record in words. */\nconst reorderingWords = (total: Reordering): string =>\n [\n `${total.outOfOrder} arrivals out of order and ${total.duplicates} duplicate arrivals at the client`,\n ...(total.ooo === null ? [] : [`its kernel counted ${total.ooo} segments out of order`]),\n ...(total.sacked === null ? [] : [`the server held up to ${total.sacked} segments SACKed`]),\n ...(total.dsacks === null ? [] : [`got ${total.dsacks} DSACKs`]),\n `sent ${total.fast} fast retransmissions`,\n ...(total.seen === null ? [] : [`saw ${total.seen} reorderings`]),\n ...(total.degree === null ? [] : [`and its reordering degree went to ${total.degree}`]),\n ].join(\", \");\n\n/** This function says a spread in words, in milliseconds. */\nconst spreadWords = (spread: Spread | null): string => {\n if (spread === null) return \"no time\";\n const ms = (time: Quantity) => Math.round(valueIn(time, \"s\") * 1e6) / 1e3;\n return `median ${ms(spread.median)} ms, p99 ${ms(spread.p99)} ms, p99.9 ${ms(spread.p999)} ms, max ${ms(spread.max)} ms of ${spread.count}`;\n};\n\n/**\n * This function gives the distribution-free interval of a median: [x_(k), x_(n+1−k)], for the\n * largest k whose two tails each hold 2.5 % or less. For eleven runs, it gives [x_(2), x_(10)],\n * at 98.8 %. It is `medianInterval` of @mark1russell7/rigor-statistics at the level 0.95. An\n * empty list throws a RangeError.\n */\nexport const medianInterval = (sorted: readonly number[]): [number, number] => {\n const interval = intervalOfMedian(sorted, 0.95);\n return [interval.low, interval.high];\n};\n\n/**\n * This function gives the verdict of a cell, from two tests:\n * - Containment: each run lands in [T_lo − δ_abs, T_hi + δ_abs]. A run outside is a finding.\n * - Median equivalence: the interval of the median is in the band, made wider by δ_rel. An\n * interval outside the band fails. An interval across its edge extends the cell to 22 runs, then\n * 44, and then the verdict is inconclusive.\n *\n * A silent prediction holds only if no run detected the fault in its window. After a stall, the\n * return of the reply gets the same test as a detection, by its interval, and a detection is a\n * finding. The distribution test (a DKW band) needs a predicted distribution from a simulator,\n * which does not exist at this time.\n */\nexport const verdictOf = (prediction: Prediction, runs: readonly Measured[], noise: Quantity = NOISE): Verdict => {\n const band = verdictOfBand(prediction, runs, noise);\n const counted = runs.filter((run) => run.void === null);\n const asked = counted.some((run) => run.request !== undefined) ? withRequests(band, counted) : band;\n const verdict = withProgram(asked, counted);\n if (prediction.group === undefined && !counted.some((run) => run.group !== undefined)) return verdict;\n return { ...verdict, group: groupVerdictOf(prediction, counted, noise) };\n};\n\n/**\n * This function adds the reconnect of the client and the outcomes of its call in flight to a\n * verdict. Its reason gets a sentence for each. A verdict whose runs have neither stays as it is.\n */\nconst withProgram = (verdict: Verdict, counted: readonly Measured[]): Verdict => {\n const reconnects = counted.flatMap((run) => (run.reconnect === undefined ? [] : [run.reconnect]));\n const calls = counted.flatMap((run) => (run.call === undefined ? [] : [run.call]));\n const lefts = counted.flatMap((run) => (run.left === undefined ? [] : [run.left]));\n if (reconnects.length === 0 && calls.length === 0 && lefts.length === 0) return verdict;\n const ms = (spread: Spread | null) => (spread === null ? \"none\" : `${Math.round(valueIn(spread.median, \"s\") * 1e6) / 1e3} ms`);\n const tries = Math.max(0, ...reconnects.map((each) => each.waits.length));\n const reconnect: ReconnectVerdict | undefined =\n reconnects.length === 0\n ? undefined\n : {\n waits: Array.from({ length: tries }, (_, at) =>\n spreadOf(reconnects.flatMap((each) => (each.waits[at] === undefined ? [] : [each.waits[at]!]))),\n ),\n syn: spreadOf(reconnects.flatMap((each) => (each.syn === null ? [] : [each.syn]))),\n established: spreadOf(reconnects.flatMap((each) => (each.established === null ? [] : [each.established]))),\n connect: spreadOf(reconnects.flatMap((each) => each.connects)),\n };\n const outcomes: Record<string, number> = {};\n for (const call of calls) outcomes[call.outcome] = (outcomes[call.outcome] ?? 0) + 1;\n const gone = lefts.flatMap((each) => (each === null ? [] : [each]));\n // a socket that stayed open until the end of the client process: its kernel closed it, not the program\n const ends = counted.flatMap((run) => (run.exited === undefined ? [] : [run.exited]));\n const left =\n lefts.length === 0\n ? undefined\n : { spread: spreadOf(gone), stayed: lefts.length - gone.length, ...(ends.length === 0 ? {} : { exited: spreadOf(ends) }) };\n const ended = ends.length === 0 ? \"\" : `: in ${ends.length} the socket stayed open until the client process ended, median ${ms(spreadOf(ends))} after the drop line`;\n const said = [\n ...(left === undefined\n ? []\n : [\n `After the drop, the program closed its socket in ${gone.length} runs, median ${ms(left.spread)} after its drop line${left.stayed === 0 ? \"\" : `, and it did not close it in ${left.stayed}${ended}`}.`,\n ]),\n ...(reconnect === undefined\n ? []\n : [\n `Reconnect: the waits before each try, median ${reconnect.waits.map(ms).join(\", \")}; the first SYN median ${ms(reconnect.syn)} and ESTABLISHED median ${ms(reconnect.established)} after the detection.`,\n ]),\n ...(calls.length === 0\n ? []\n : [`Calls in flight: ${Object.entries(outcomes).map(([outcome, n]) => `${n} ${outcome}`).join(\"; \")}.`]),\n ];\n return {\n ...verdict,\n ...(reconnect === undefined ? {} : { reconnect }),\n ...(calls.length === 0 ? {} : { calls: outcomes }),\n ...(left === undefined ? {} : { left }),\n why: `${verdict.why.endsWith(\".\") ? verdict.why : `${verdict.why}.`} ${said.join(\" \")}`,\n };\n};\n\n/**\n * This function adds the outcomes of the second request of an HTTP client to a verdict. A cell\n * whose outcome is a distribution gets them in its reason too.\n */\nconst withRequests = (verdict: Verdict, counted: readonly Measured[]): Verdict => {\n const requests: Record<string, number> = {};\n for (const run of counted) {\n const words = run.request === null || run.request === undefined ? \"no second request\" : requestWords(run.request);\n requests[words] = (requests[words] ?? 0) + 1;\n }\n const listed = Object.entries(requests)\n .map(([words, n]) => `${n} ${words}`)\n .join(\"; \");\n return {\n ...verdict,\n requests,\n why: verdict.decision === \"measured\" ? `${verdict.why} Second requests: ${listed}.` : verdict.why,\n };\n};\n\n/** This function gives the median of some counts, or null for none. */\nconst medianCount = (values: readonly number[]): number | null =>\n values.length === 0 ? null : middle([...values].sort((a, b) => a - b));\n\n/** This function sums what the group of a group cell did in its counted runs, and tests each stage that has a band. */\nexport const groupVerdictOf = (prediction: Prediction, counted: readonly Measured[], delta: Quantity = NOISE): GroupVerdict => {\n const noise = valueIn(delta, \"s\");\n const stamps = prediction.group?.stamps === undefined ? 0 : valueIn(prediction.group.stamps, \"s\");\n const stages = (prediction.group?.stages ?? []).map((band): StageVerdict => {\n const interval = { low: s(valueIn(band.low, \"s\") - noise), high: s(valueIn(band.high, \"s\") + stamps + noise) };\n const outside: Array<{ run: string; why: string }> = [];\n const values: number[] = [];\n for (const run of counted) {\n const at = run.group?.stages[band.stage];\n if (at === undefined) {\n // a stage of a Sentinel starts with +: a Sentinel announces it. The members and the client of a replica set mark the others\n const who = band.stage.startsWith(\"+\") ? \"no Sentinel announced\" : \"no member or client marked\";\n outside.push({ run: name(run), why: `${who} ${band.stage}` });\n continue;\n }\n const value = valueIn(at, \"s\");\n values.push(value);\n if (value < valueIn(interval.low, \"s\") || value > valueIn(interval.high, \"s\"))\n outside.push({ run: name(run), why: `${band.stage} at ${value} s is outside [${interval.low.value}, ${interval.high.value}] s` });\n }\n values.sort((a, b) => a - b);\n return {\n stage: band.stage,\n band: interval,\n median: values.length === 0 ? null : s(middle(values)),\n outside,\n decision: outside.length === 0 && values.length > 0 ? \"holds\" : \"fails\",\n };\n });\n const medians: Partial<Record<Stage, Quantity>> = {};\n const seen = new Set(counted.flatMap((run) => Object.keys(run.group?.stages ?? {}) as Stage[]));\n for (const stage of seen) {\n const values = counted.flatMap((run) => {\n const at = run.group?.stages[stage];\n return at === undefined ? [] : [valueIn(at, \"s\")];\n });\n medians[stage] = s(middle(values.sort((a, b) => a - b)));\n }\n const lostCounts = counted.flatMap((run) => (run.group?.writes.lost === null || run.group === undefined ? [] : [run.group.writes.lost.length]));\n const oldCounts = counted.flatMap((run) => (run.group === undefined ? [] : [run.group.writes.old]));\n const unknown = counted.flatMap((run) => run.group?.writes.unknown ?? []);\n const errors = new Map<string, number[]>();\n for (const run of counted)\n for (const error of run.group?.errors ?? []) errors.set(error.name, [...(errors.get(error.name) ?? []), valueIn(error.first, \"s\")]);\n const lags = counted.flatMap((run) => run.group?.lags ?? []);\n const copyCounts = counted.flatMap((run) => {\n const copies = run.group?.writes.duplicates;\n return copies === null || copies === undefined ? [] : [copies.length];\n });\n return {\n stages,\n medians,\n lost: {\n runs: lostCounts.length,\n total: lostCounts.reduce((sum, n) => sum + n, 0),\n median: medianCount(lostCounts),\n max: lostCounts.length === 0 ? null : Math.max(...lostCounts),\n },\n old: { median: medianCount(oldCounts), max: oldCounts.length === 0 ? null : Math.max(...oldCounts) },\n unknown: { total: unknown.length, held: unknown.filter((each) => each.held === true).length },\n errors: [...errors].map(([error, firsts]) => ({ name: error, runs: firsts.length, first: s(middle(firsts.sort((a, b) => a - b))) })),\n ...(lags.length === 0 ? {} : { lags: spreadOf(lags) }),\n ...(prediction.group?.duplicates === undefined\n ? {}\n : {\n duplicates: {\n runs: copyCounts.length,\n total: copyCounts.reduce((sum, n) => sum + n, 0),\n median: medianCount(copyCounts),\n max: copyCounts.length === 0 ? null : Math.max(...copyCounts),\n },\n }),\n };\n};\n\n/** This function gives the verdict of the band of a cell: its containment and the equivalence of its median. */\nconst verdictOfBand = (prediction: Prediction, runs: readonly Measured[], delta: Quantity = NOISE): Verdict => {\n const counted = runs.filter((run) => run.void === null);\n const voided = runs.length - counted.length;\n const outside = counted\n .filter((run) => run.finding !== null)\n .map((run) => ({ run: name(run), why: run.finding! }));\n const empty = { counted: counted.length, voided, median: null, medianInterval: null };\n if (counted.length === 0)\n return { ...empty, decision: \"inconclusive\", band: null, outside, why: \"no run counted\" };\n\n if (prediction.detects === null) {\n // the law of an accept queue, a port range, a paused consumer or a conntrack table: each run holds each term of it, or the run is outside\n const law =\n prediction.queue !== undefined\n ? \"queue\"\n : prediction.ports !== undefined\n ? \"port range\"\n : prediction.pause !== undefined\n ? \"paused consumer\"\n : prediction.conntrack !== undefined\n ? \"conntrack table\"\n : undefined;\n if (law !== undefined) {\n const off = new Set(outside.map((each) => each.run)).size;\n return {\n ...empty,\n decision: off === 0 ? \"holds\" : \"fails\",\n band: null,\n outside,\n why: `${counted.length - off} of ${counted.length} runs hold the law of the ${law}; ${prediction.why}`,\n };\n }\n // a calibration of a proxy: its time in each direction, over all the requests of the runs\n const crossed = counted.flatMap((run) => (run.crossings === undefined ? [] : [run.crossings]));\n if (crossed.length > 0) {\n const hop = crossed[0]!.hop;\n const up = spreadOf(crossed.flatMap((each) => each.up));\n const down = spreadOf(crossed.flatMap((each) => each.down));\n return {\n ...empty,\n decision: \"measured\",\n band: null,\n outside: [],\n median: up?.median ?? null,\n proxy: { hop, up, down },\n why: `${counted.length} runs measured ${hop}: toward the target ${spreadWords(up)}; toward the client ${spreadWords(down)}. ${prediction.why}`,\n };\n }\n // a measurement-only cell with a reference: the outcomes, and the times from the reference\n if (prediction.from !== undefined) {\n const times = counted\n .flatMap((run) => (run.elapsed === null ? [] : [valueIn(run.elapsed, \"s\")]))\n .sort((a, b) => a - b);\n const kinds = new Map<string, number>();\n for (const run of counted) {\n const kind = run.outcome.kind === \"error\" ? run.outcome.errno : run.outcome.kind;\n kinds.set(kind, (kinds.get(kind) ?? 0) + 1);\n }\n const outcomes = [...kinds].map(([kind, n]) => `${n} ${kind}`).join(\", \");\n const timed =\n times.length === 0\n ? \"no time\"\n : `median ${s(middle(times)).value} s from ${prediction.from}, range [${s(times[0]!).value}, ${s(times.at(-1)!).value}] s`;\n // exact counts judge the cell: the times have no band\n const { counts } = prediction;\n if (counts !== undefined) {\n const exact = counts.map((each) => `${each.what} ${each.count}`).join(\", \");\n return {\n ...empty,\n decision: outside.length === 0 ? \"holds\" : \"fails\",\n band: null,\n outside,\n median: times.length === 0 ? null : s(middle(times)),\n why: `${counted.length - outside.length} of ${counted.length} runs gave the exact counts (${exact}); ${outcomes}; ${timed}. ${prediction.why}`,\n };\n }\n // a band of lost writes or of extra copies judges the cell: the time stays a measurement, and each finding of a run counts\n const lost = prediction.group?.lost;\n const copies = prediction.group?.duplicates;\n if (lost !== undefined || copies !== undefined) {\n const off = new Set(outside.map((each) => each.run)).size;\n const bands = [\n ...(lost === undefined ? [] : [`lost writes [${lost.low}, ${lost.high}]`]),\n ...(copies === undefined ? [] : [`extra copies [${copies.low}, ${copies.high}]`]),\n ];\n return {\n ...empty,\n decision: off === 0 ? \"holds\" : \"fails\",\n band: null,\n outside,\n median: times.length === 0 ? null : s(middle(times)),\n why: `${counted.length - off} of ${counted.length} runs inside the band of ${bands.join(\" and the band of \")}; ${outcomes}; ${timed}. ${prediction.why}`,\n };\n }\n // the end has no band, but each wait of the reconnect has one: a wait outside it is a finding of its run\n const missed = outside.filter((each) => counted.some((run) => name(run) === each.run && run.reconnect !== undefined));\n const late = missed.length === 0 ? \"\" : ` ${missed.length} runs had a wait of the reconnect outside its band.`;\n return {\n ...empty,\n decision: \"measured\",\n band: null,\n outside: missed,\n median: times.length === 0 ? null : s(middle(times)),\n why: `${counted.length} runs measured: ${outcomes}; ${timed}.${late} ${prediction.why}`,\n };\n }\n // an open-loop cell: each run keeps its schedule, and each band of the latency holds\n if (counted.some((run) => run.load !== undefined)) {\n const judged = loadVerdict(\n prediction.load ?? { lag: quantity(Number.MAX_SAFE_INTEGER, \"ms\"), bands: [] },\n counted.map((run) => ({ name: name(run), load: run.load })),\n );\n const middleOfLoad = judged.load.latency?.p50;\n const failed = judged.load.failed === 0 ? \"\" : `, ${judged.load.failed} with the status of a failure`;\n const read = [`${counted.length} runs on a schedule, ${judged.load.planned} arrivals, ${judged.load.unsent} not sent, ${judged.load.unfinished} with no reply${failed}.`, ...judged.load.bands, ...(judged.load.failures === undefined ? [] : [judged.load.failures]), prediction.why].join(\" \");\n return {\n ...empty,\n decision: prediction.load === undefined ? \"measured\" : judged.holds ? \"holds\" : \"fails\",\n band: null,\n outside: judged.outside,\n median: middleOfLoad === undefined ? null : s(valueIn(middleOfLoad, \"s\")),\n ...(judged.load.latency === null ? {} : { slowest: s(valueIn(judged.load.latency.max, \"s\")) }),\n load: judged.load,\n why: read,\n };\n }\n const samples = counted\n .flatMap((run) => (run.samples ?? []).map((sample) => valueIn(sample, \"s\")))\n .sort((a, b) => a - b);\n const retransmissions = counted.reduce((sum, run) => sum + run.retransmissions, 0);\n const ended = counted.filter((run) => run.outcome.kind === \"error\" || run.outcome.kind === \"eof\");\n const reordering = reorderingTotal(counted);\n // a run in which nothing came out of order, twice or SACKed says nothing about reordering\n const anything =\n reordering !== undefined &&\n [reordering.outOfOrder, reordering.duplicates, reordering.ooo, reordering.sacked, reordering.dsacks, reordering.fast, reordering.seen].some(\n (count) => (count ?? 0) > 0,\n );\n const reordered = anything ? ` Reordering: ${reorderingWords(reordering)}.` : \"\";\n // the reply times of a closed loop hide the sends of each stall: the estimate puts them back\n const estimate = estimateVerdict(counted.map((run) => run.estimate));\n const estimated = estimate === undefined ? \"\" : ` ${estimate.words}`;\n const why =\n samples.length === 0\n ? `${counted.length} runs measured, with no reply: ${prediction.why}`\n : `${counted.length} runs, ${samples.length} replies: median ${s(middle(samples)).value} s, p99 ${s(quantileOf(samples, 0.99)).value} s, slowest ${s(samples.at(-1)!).value} s, ${retransmissions} retransmissions, ${ended.length} connections ended.${reordered}${estimated} ${prediction.why}`;\n return {\n ...empty,\n decision: \"measured\",\n band: null,\n outside: [],\n median: samples.length === 0 ? null : s(middle(samples)),\n ...(samples.length === 0 ? {} : { slowest: s(samples.at(-1)!) }),\n ...(reordering === undefined ? {} : { reordering }),\n ...(estimate === undefined ? {} : { estimate }),\n why,\n };\n }\n\n if (!prediction.detects && prediction.recovers === undefined && prediction.replies === undefined) {\n const decision = outside.length === 0 ? \"holds\" : \"fails\";\n const why =\n decision === \"holds\"\n ? `nothing detected it in ${counted.length} runs of ${valueIn(prediction.window, \"s\")} s`\n : `${outside.length} of ${counted.length} runs detected it`;\n return { ...empty, decision, band: null, outside, why };\n }\n\n // the interval of a detection, of the return of the reply after a stall, or of a reply in its band\n const timed = prediction.detects ? prediction : (prediction.recovers ?? prediction.replies)!;\n const noise = valueIn(delta, \"s\");\n const low = valueIn(timed.low, \"s\");\n const high = valueIn(timed.high, \"s\");\n const band = { low: s(low - noise), high: s(high + noise) };\n const values: number[] = [];\n for (const run of counted) {\n if (run.elapsed === null) continue;\n const value = valueIn(run.elapsed, \"s\");\n values.push(value);\n if (value < low - noise || value > high + noise)\n outside.push({\n run: name(run),\n why: `${value} s is outside [${band.low.value}, ${band.high.value}] s`,\n });\n }\n values.sort((a, b) => a - b);\n if (values.length === 0)\n return { ...empty, decision: \"fails\", band, outside, why: \"no run measured its time\" };\n const [from, to] = medianInterval(values);\n const median = s(middle(values));\n const interval = { low: s(from), high: s(to) };\n const wide = { low: low * (1 - RELATIVE), high: high * (1 + RELATIVE) };\n const inside = from >= wide.low && to <= wide.high;\n const disjoint = to < wide.low || from > wide.high;\n // a run can be outside for its time and for a finding: it counts once\n const off = new Set(outside.map((each) => each.run)).size;\n const counts = `${counted.length - off} of ${counted.length} runs inside [${band.low.value}, ${band.high.value}] s`;\n const centre = `median ${median.value} s, its interval [${interval.low.value}, ${interval.high.value}] s`;\n const result = {\n counted: counted.length,\n voided,\n band,\n outside,\n median,\n medianInterval: interval,\n };\n if (outside.length > 0 || disjoint)\n return { ...result, decision: \"fails\", why: `${counts}; ${centre}` };\n if (inside) return { ...result, decision: \"holds\", why: `${counts}; ${centre}` };\n const decision = counted.length < STEPS[2] ? \"extend\" : \"inconclusive\";\n return { ...result, decision, why: `${counts}; ${centre} straddles the band` };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, Jitter, KernelRecord, ProbeEvent, Reconnects, Run } from \"./cell.ts\";\nimport { NOISE } from \"./verdict.ts\";\n\n/**\n * This module reads the acts of the program of the observer: its heartbeat, its drop of the\n * connection, its reconnect and its call in flight. The kernel has no report of a detection by\n * a program. Thus the program writes a line before each of its own acts, on CLOCK_MONOTONIC:\n * - `ping` before each ping of its heartbeat, and `drop` before it closes the connection by itself.\n * - `reconnecting` when it starts its reconnect timer, and `dial` before each new connection.\n *\n * The kernel then stamps each write of the program on the socket (`tx`) and each change of the\n * state of the socket. A line of the client names its socket by its local address (`local`), and\n * a line of a server names it by its peer (`peer`).\n */\n\n/**\n * This time bounds the handling of a drop by the program of the observer. It starts when the timer\n * of the program fires. It ends at the kernel's stamp of the act: the write of a close frame, or\n * the close of the socket. The `drop` line comes in that time, before the act.\n *\n * This bound is not δ_abs. δ_abs is the noise of the pipeline, and stage 0 calibrates it from a\n * reset. The handling is the time of the code of the program, and it is longer:\n * - No source and no machine document bounds it (`http/timers.ts` of `@mark1russell7/machines`).\n * - The handling time of the HTTP cells (`HANDLING` in `packages/cells/src/http/race.ts`) is\n * another act. It is the first reply of a new process, up to 11.182 ms.\n * - A drop comes from a timer, long after the start of the process.\n *\n * The bound comes from the CI records of the WS and WST cells, from the `drop` line to the act:\n * - 585 drops with a close frame had a median of 0.652 ms, a 99th percentile of 0.87 ms and a\n * maximum of 1.017 ms.\n * - 559 drops with a close of the socket had a maximum of 0.914 ms.\n * - Two drops took more than the δ_abs of 1 ms. Each failed its cell, and its time was in the band.\n * These are the runs 39390222333 and 39903020657 of the client repository.\n *\n * The bound is 1.5 ms: the maximum and a margin of 0.48 ms. The pairing of a drop with its act\n * uses it, or the pairing window of the run when that window is longer. The band of a drop adds\n * it to its high bound (the WS catalog of the cells). Read the records again after a change to the subject, to Node or to\n * the runners.\n */\nexport const DROP_HANDLING: Quantity = quantity(1.5, \"ms\");\n\n/** This function gives the window of the act of a drop, in seconds: `DROP_HANDLING`, or the pairing window (`delta`) when it is longer. */\nconst dropWindow = (delta: Quantity): number => Math.max(valueIn(DROP_HANDLING, \"s\"), valueIn(delta, \"s\"));\n\n/** This function gives the interval between two instants on the one clock, in seconds to the microsecond. */\nconst between = (from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\n/** This function gives the state of a state record after the change, and before it. TCP_ESTABLISHED is 1, TCP_SYN_SENT 2. */\nconst newState = (record: KernelRecord): number | undefined => (record as { readonly new?: number }).new;\nconst oldState = (record: KernelRecord): number | undefined => (record as { readonly old?: number }).old;\n\n/**\n * A program event is a line of the program of the observer, with the kernel's stamp of its act.\n * The act is a write, or a change of state of the socket. Without a record of the kernel in its\n * window after the line, the instant is the stamp of the line. The window is the pairing window of\n * the run (`pairingOf`), and for a drop it is `DROP_HANDLING` when that is longer.\n */\nexport interface ProgramEvent {\n readonly line: ProbeEvent;\n readonly at: number;\n /** This flag tells that the kernel stamped the event. */\n readonly kernel: boolean;\n /** This name is the kind of the record of the kernel: a write, or a change of state. It is null without a record. */\n readonly record: \"write\" | \"state\" | null;\n}\n\n/** This function gives the lines of the program of the observer: the client, or the target for the server. A proxy has no lines. */\nexport const programLines = (cell: Cell, run: Run): readonly ProbeEvent[] => {\n const observer = cell.observer ?? \"client\";\n if (observer === \"client\") return run.events;\n if (observer === \"server\") return run.server ?? [];\n return [];\n};\n\n/**\n * This function tells if a line of the program is about the connection of the run. The client\n * names it by its local address, and a server by its peer. A line with neither is about the one\n * connection of its program. A line whose address is null is about a socket that did not open:\n * a try that failed.\n */\nconst onConnection = (line: ProbeEvent, local: unknown): boolean => {\n if (!(\"local\" in line) && !(\"peer\" in line)) return true;\n return (line[\"local\"] ?? line[\"peer\"]) === local;\n};\n\n/** This function gives the first record of a socket that matches, at the stamp of a line or in a window (`delta`) after it. */\nconst kernelAt = (\n socket: readonly KernelRecord[],\n line: ProbeEvent,\n matches: (record: KernelRecord) => boolean,\n delta: Quantity,\n): KernelRecord | undefined => {\n const noise = valueIn(delta, \"s\") * 1e9;\n return socket.find((record) => record.mono >= line.t && record.mono <= line.t + noise && matches(record));\n};\n\nconst eventOf = (\n socket: readonly KernelRecord[],\n line: ProbeEvent,\n matches: (record: KernelRecord) => boolean,\n delta: Quantity = NOISE,\n): ProgramEvent => {\n const record = kernelAt(socket, line, matches, delta);\n return {\n line,\n at: record?.mono ?? line.t,\n kernel: record !== undefined,\n record: record === undefined ? null : record.ev === \"tx\" ? \"write\" : \"state\",\n };\n};\n\n/**\n * This function gives the time from a line of the program to the close of the socket by its own\n * side. That close is its change from ESTABLISHED to FIN_WAIT1, or to CLOSE (an abort). A FIN of\n * the peer (CLOSE_WAIT) is not such a close. It is null when the socket did not close itself.\n */\nexport const leftAfter = (socket: readonly KernelRecord[], line: ProbeEvent): Quantity | null => {\n const left = socket.find(\n (record) => record.ev === \"state\" && oldState(record) === 1 && (newState(record) === 4 || newState(record) === 7) && record.mono >= line.t,\n );\n return left === undefined ? null : between(line.t, left.mono);\n};\n\n/**\n * This function gives the end of the client process in a run, as the kernel stamps it. The process\n * ends after its last try, and its kernel then closes each socket that is still open, at one\n * instant. Thus the end is the first change out of ESTABLISHED of another socket of the client\n * after its last `dial` line. The program dropped none of these sockets. It is undefined when the\n * record has no such change, for example when the last try did not open.\n */\nexport const exitOf = (run: Run, cookie: number | undefined): number | undefined => {\n const last = run.events.filter((line) => line.ev === \"dial\").at(-1);\n if (last === undefined) return undefined;\n const dropped = new Set(run.events.filter((line) => line.ev === \"drop\").map((line) => line[\"local\"]));\n return run.kernel.find(\n (record) =>\n record.netns === run.netns &&\n record.cookie !== cookie &&\n record.ev === \"state\" &&\n oldState(record) === 1 &&\n (newState(record) === 4 || newState(record) === 7) &&\n record.mono >= last.t &&\n !dropped.has(record.src),\n )?.mono;\n};\n\n/**\n * This function separates a close of the socket by the program from the end of the client process.\n * `left` is the time from the drop line to the close, and `exit` is the end of the process. A close\n * in δ_abs of that end is the end, not the program: `left` becomes null, and `exited` keeps the time.\n */\nexport const closeOrExit = (\n line: ProbeEvent,\n left: Quantity | null,\n exit: number | undefined,\n delta: Quantity = NOISE,\n): { readonly left: Quantity | null; readonly exited?: Quantity } => {\n if (left === null || exit === undefined) return { left };\n const at = line.t + valueIn(left, \"s\") * 1e9;\n return Math.abs(at - exit) <= valueIn(delta, \"s\") * 1e9 ? { left: null, exited: left } : { left };\n};\n\n/**\n * This function tells how a drop differs from the way that its prediction gives, or gives null.\n * A close closes the socket at once, in the handling time of the program (`DROP_HANDLING`). If\n * the pairing window of the run (`delta`) is longer, that window is the limit. A close frame is a\n * write, and the program does not close the socket at the drop. A peer that answers the close frame can close it, and that is no finding.\n */\nexport const dropFinding = (\n expected: \"frame\" | \"close\",\n drop: ProgramEvent,\n left: Quantity | null,\n delta: Quantity = NOISE,\n exited?: Quantity,\n): string | null => {\n const noise = dropWindow(delta);\n const soon = left !== null && valueIn(left, \"s\") <= noise;\n if (expected === \"close\") {\n if (left === null)\n return `the program did not close its socket after the drop, where a close is at once${exited === undefined ? \"\" : \": it stayed open until the client process ended\"}`;\n return soon ? null : `the program closed its socket ${left.value} s after the drop, not at once`;\n }\n if (drop.record !== \"write\") return \"the drop wrote no close frame on its socket\";\n return soon ? \"the program closed its socket at the drop, where a close frame leaves it open\" : null;\n};\n\nconst isWrite = (record: KernelRecord): boolean => record.ev === \"tx\";\n\n/**\n * This function measures the jitter of a program from its acts before `until`, the start of the\n * fault. An act is a `write` line or a `ping` line on the connection. Its delay goes from the line\n * to the first write of data on the socket after it, before the next act and before `until`. An\n * act with no such write does not count. The bound is the longest delay, to the microsecond.\n */\nexport const jitterOfLines = (\n lines: readonly ProbeEvent[],\n socket: readonly KernelRecord[],\n local: unknown,\n until: number,\n): Jitter => {\n const acts = lines.filter((line) => (line.ev === \"write\" || line.ev === \"ping\") && line.t < until && onConnection(line, local));\n const delays = acts.flatMap((line, at) => {\n const next = Math.min(acts[at + 1]?.t ?? until, until);\n const write = socket.find((record) => isWrite(record) && (record.seg?.len.value ?? 0) > 0 && record.mono >= line.t && record.mono < next);\n return write === undefined ? [] : [write.mono - line.t];\n });\n return {\n acts: delays.length,\n bound: delays.length === 0 ? null : quantity(Math.round(Math.max(...delays) / 1e3) / 1e3, \"ms\"),\n };\n};\n\n/** This function gives each ping of the program on the connection, with the kernel's stamp of its write in the pairing window (`delta`). */\nexport const pingsOf = (\n lines: readonly ProbeEvent[],\n socket: readonly KernelRecord[],\n local: unknown,\n delta: Quantity = NOISE,\n): ProgramEvent[] =>\n lines.filter((line) => line.ev === \"ping\" && onConnection(line, local)).map((line) => eventOf(socket, line, isWrite, delta));\n\n/**\n * This function gives the first ping that got no answer: no segment with data reached the socket\n * after its write, up to `until`. Its write starts the wait of the heartbeat that the fault met.\n */\nexport const firstUnanswered = (\n pings: readonly ProgramEvent[],\n socket: readonly KernelRecord[],\n until: number = Number.POSITIVE_INFINITY,\n): ProgramEvent | undefined =>\n pings\n .filter((ping) => ping.at <= until)\n .find(\n (ping) =>\n !socket.some((record) => record.ev === \"rx\" && (record.seg?.len.value ?? 0) > 0 && record.mono > ping.at && record.mono <= until),\n );\n\n/**\n * This function gives the first drop of the connection by its program. The kernel stamps it as the\n * write of a close frame. Or it stamps the change of the socket out of ESTABLISHED: a close or an\n * abort. That stamp comes in the handling time of the program after the drop line\n * (`DROP_HANDLING`). If the pairing window of the run (`delta`) is longer, that window is the limit.\n */\nexport const dropOf = (\n lines: readonly ProbeEvent[],\n socket: readonly KernelRecord[],\n local: unknown,\n delta: Quantity = NOISE,\n): ProgramEvent | undefined => {\n const line = lines.find((each) => each.ev === \"drop\" && onConnection(each, local));\n return line === undefined\n ? undefined\n : eventOf(socket, line, (record) => isWrite(record) || (record.ev === \"state\" && oldState(record) === 1), quantity(dropWindow(delta), \"s\"));\n};\n\n/** A reconnect reading is what the client did after the detection, from its lines and from the records of the kernel. */\nexport interface ReconnectReading {\n /** These are the waits of the program before each try: from a `reconnecting` line to the next `dial` line. */\n readonly waits: readonly Quantity[];\n /** This time is from the detection to the first SYN of a new socket. The kernel stamps the change to SYN_SENT at connect(2). */\n readonly syn: Quantity | null;\n /** This time is from the detection to the first new socket of the client that became ESTABLISHED. */\n readonly established: Quantity | null;\n /** These are the times from each `dial` line after the detection to the SYN of its socket: the work of the program before connect(2). */\n readonly connects: readonly Quantity[];\n}\n\n/**\n * This function reads the reconnect of the client after the detection at `detected`. The socket of\n * the run has the cookie `cookie`. The lines of the program count from `from`: the drop line of a\n * drop, which comes before the kernel's stamp of it.\n */\nexport const reconnectOf = (run: Run, detected: number, cookie: number | undefined, from: number = detected): ReconnectReading => {\n const after = run.events.filter((line) => line.t > from);\n const starts = after.filter((line) => line.ev === \"reconnecting\");\n const dials = after.filter((line) => line.ev === \"dial\");\n const waits = starts.flatMap((start, at) => {\n const next = starts[at + 1]?.t ?? Number.POSITIVE_INFINITY;\n const dial = dials.find((each) => each.t >= start.t && each.t < next);\n return dial === undefined ? [] : [between(start.t, dial.t)];\n });\n const fresh = run.kernel.filter((record) => record.netns === run.netns && record.cookie !== cookie && record.ev === \"state\" && record.mono > detected);\n const syns = fresh.filter((record) => newState(record) === 2);\n const established = fresh.find((record) => newState(record) === 1);\n const connects = dials.flatMap((dial) => {\n const syn = syns.find((record) => record.mono >= dial.t);\n return syn === undefined ? [] : [between(dial.t, syn.mono)];\n });\n return {\n waits,\n syn: syns[0] === undefined ? null : between(detected, syns[0].mono),\n established: established === undefined ? null : between(detected, established.mono),\n connects,\n };\n};\n\n/** This function tells how the waits of a reconnect differ from their bands, each widened by δ_abs, or gives null. */\nexport const reconnectFinding = (expected: Reconnects, read: ReconnectReading, delta: Quantity = NOISE): string | null => {\n const noise = valueIn(delta, \"s\");\n const round = (value: number) => Math.round(value * 1e6) / 1e6;\n const found = expected.waits.flatMap((band, at) => {\n const wait = read.waits[at];\n if (wait === undefined) return [`the client made no try ${at + 1} after the detection`];\n const value = valueIn(wait, \"s\");\n const low = round(valueIn(band.low, \"s\") - noise);\n const high = round(valueIn(band.high, \"s\") + noise);\n return value < low || value > high ? [`its wait before try ${at + 1} was ${value} s, outside [${low}, ${high}] s`] : [];\n });\n return found.length === 0 ? null : found.join(\". \");\n};\n\n/**\n * A call reading is what the call in flight of a WebSocket client met: its error, a reply, or\n * nothing in the run. The time counts from the detection to its end.\n */\nexport interface CallReading {\n readonly outcome: string;\n readonly after: Quantity | null;\n}\n\n/** This function reads the call that the client sent into the fault: its `call-error` or `data` line after the request. */\nexport const callOf = (events: readonly ProbeEvent[], request: ProbeEvent, detected: number | undefined): CallReading => {\n const end = events.find((line) => (line.ev === \"call-error\" || line.ev === \"data\") && line.t > request.t);\n if (end === undefined) return { outcome: \"pending\", after: null };\n const outcome = end.ev === \"data\" ? \"a reply\" : String(end[\"message\"] ?? end[\"code\"] ?? \"an error\");\n return { outcome, after: detected === undefined ? null : between(detected, end.t) };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, DriverBand, KernelRecord, LineCount, LineMatch, ProbeEvent, Reference, Run } from \"./cell.ts\";\nimport { requestFirst } from \"./cell.ts\";\nimport type { Measured, Outcome } from \"./observe.ts\";\nimport { INJECT, delayVoids, noiseOf } from \"./verdict.ts\";\n\n/**\n * This module measures a run of a cell whose client is a driver with more than one socket, for\n * example the MongoDB driver. Its monitor, its pool and its round-trip pinger each have their own\n * socket, and the client names each socket by its role. A band counts from an event of one socket,\n * as the kernel records it. It ends at a line of the client, or at the report of the kernel on\n * that socket.\n */\n\n/** A driver socket is one socket of the driver in a run: its role, its local address, its server, and when it opened and ended. */\nexport interface DriverSocket {\n readonly role: string;\n readonly local: string;\n readonly server: string;\n readonly opened: number;\n readonly ended: number | null;\n}\n\n/** A driver step time is the time of one later band of a run. It is null when its line did not come. */\nexport interface DriverStepTime {\n readonly what: string;\n readonly name: string | null;\n readonly elapsed: Quantity | null;\n}\n\n/** These are the errno numbers that the kernel reports to a socket, by the names that predictions use. */\nconst ERRNO: Readonly<Record<number, string>> = {\n 32: \"EPIPE\",\n 101: \"ENETUNREACH\",\n 103: \"ECONNABORTED\",\n 104: \"ECONNRESET\",\n 110: \"ETIMEDOUT\",\n 111: \"ECONNREFUSED\",\n 113: \"EHOSTUNREACH\",\n};\n\nconst between = (from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\nconst round = (seconds: number): number => Math.round(seconds * 1e6) / 1e6;\n\n/** This function gives the value of a field of a line by its name. A dotted name is a field in a field. */\nexport const fieldOf = (line: unknown, path: string): unknown =>\n path.split(\".\").reduce<unknown>((value, key) => (value !== null && typeof value === \"object\" ? (value as Record<string, unknown>)[key] : undefined), line);\n\n/** This function tells if a line of the client matches a line match: its `ev`, and each field that the match names. */\nexport const matches = (line: ProbeEvent, match: LineMatch): boolean =>\n line.ev === match.ev && Object.entries(match.where ?? {}).every(([path, value]) => fieldOf(line, path) === value);\n\n/** This function gives the count of the lines that match. */\nexport const countOf = (lines: readonly ProbeEvent[], match: LineMatch): number => lines.filter((line) => matches(line, match)).length;\n\n/** This function gives the finding of the line counts of a run, or null when each count is the exact one. */\nexport const countFinding = (counts: readonly LineCount[], lines: readonly ProbeEvent[]): string | null => {\n const off = counts.flatMap((each) => {\n const seen = countOf(lines, each.match);\n return seen === each.count ? [] : [`${each.what}: ${seen} lines, and the law gives ${each.count}`];\n });\n return off.length === 0 ? null : off.join(\"; \");\n};\n\n/** This function says a line match in words, for a finding. */\nexport const wordsOf = (match: LineMatch): string => {\n const where = Object.entries(match.where ?? {}).map(([path, value]) => `${path} ${String(value)}`);\n return where.length === 0 ? `a ${match.ev} line` : `a ${match.ev} line with ${where.join(\", \")}`;\n};\n\n/** This function gives the sockets of the driver in a run, from the `socket` and `socket-end` lines of the client. */\nexport const socketsOf = (events: readonly ProbeEvent[]): DriverSocket[] =>\n events\n .filter((event) => event.ev === \"socket\")\n .map((event) => {\n const local = String(event[\"local\"]);\n const end = events.find((each) => each.ev === \"socket-end\" && each[\"local\"] === local && each.t >= event.t);\n return { role: String(event[\"role\"]), local, server: String(event[\"server\"]), opened: event.t, ended: end?.t ?? null };\n });\n\n/**\n * This function finds the socket of a role at an instant. The pool's socket is the first one, which\n * the client names in its `connected` line. Each other role has the latest socket that opened at\n * the instant or before it.\n */\nexport const socketAt = (events: readonly ProbeEvent[], role: string, at: number): DriverSocket | undefined => {\n const sockets = socketsOf(events);\n if (role === \"pool\") {\n const local = events.find((event) => event.ev === \"connected\")?.[\"local\"];\n return sockets.find((socket) => socket.local === local);\n }\n return sockets.filter((socket) => socket.role === role && socket.opened <= at).at(-1);\n};\n\n/** A kernel place is the namespace and the cookie of a socket, and its records in the run. */\ninterface KernelPlace {\n readonly netns: number;\n readonly cookie: number;\n readonly records: readonly KernelRecord[];\n}\n\nconst placeOf = (run: Run, netns: number, find: (record: KernelRecord) => boolean): KernelPlace | undefined => {\n const cookie = run.kernel.find((record) => record.netns === netns && find(record))?.cookie;\n if (cookie === undefined) return undefined;\n return { netns, cookie, records: run.kernel.filter((record) => record.netns === netns && record.cookie === cookie) };\n};\n\nconst portOf = (address: string): string => address.split(\":\").at(-1) ?? \"\";\n\n/**\n * This function gives the socket of the target for a socket of the client. In a direct pair, its\n * peer is the address of the client socket. Behind a router, its peer is the address of the router\n * with the port of the client socket. The router keeps the port when it is free.\n */\nconst peerPlace = (run: Run, local: string): KernelPlace | undefined => {\n const peer = run.topology === undefined ? local : `${run.topology.targetPeer}:${portOf(local)}`;\n return placeOf(run, run.targetNetns, (record) => record.dst === peer);\n};\n\n/**\n * This function gives the socket that a hop of the topology opens toward its target in the run. It is\n * the first one that moves to SYN_SENT after the outset. A pooler connects to the server by itself,\n * thus no line of the client names that socket. The last hop goes first, because it faces the target.\n */\nconst upstreamOf = (run: Run): KernelPlace | undefined => {\n if (run.topology === undefined) return undefined;\n const outset = outsetOf(run);\n for (const hop of Object.values(run.topology.hops).reverse()) {\n const place = placeOf(run, hop.netns, (record) => record.ev === \"state\" && newState(record) === 2 && record.mono >= outset && record.dst === hop.target);\n if (place !== undefined) return place;\n }\n return undefined;\n};\n\n/**\n * This function gives the kernel place of a socket of a role at an instant. The role `server` is a\n * socket of the target, and the role `upstream` is the socket that a hop opens toward the target.\n */\nconst kernelOf = (run: Run, role: string, at: number): { socket: DriverSocket | undefined; place: KernelPlace | undefined } => {\n if (role === \"upstream\") return { socket: undefined, place: upstreamOf(run) };\n if (role === \"server\") {\n const pool = socketAt(run.events, \"pool\", at);\n return { socket: pool, place: pool === undefined ? undefined : peerPlace(run, pool.local) };\n }\n const socket = socketAt(run.events, role, at);\n return { socket, place: socket === undefined ? undefined : placeOf(run, run.netns, (record) => record.src === socket.local) };\n};\n\nconst newState = (record: KernelRecord): number | undefined => (record as { readonly new?: number }).new;\nconst oldState = (record: KernelRecord): number | undefined => (record as { readonly old?: number }).old;\n\n/** This function gives the instant that a run starts to look for its outcome. It is the fault, the reply before it, or the start of the client. */\nconst outsetOf = (run: Run): number => {\n const ready = run.events.find((event) => event.ev === \"ready\");\n return run.fault?.t0 ?? ready?.t ?? run.events[0]?.t ?? 0;\n};\n\n/**\n * This function gives the instant of a reference in a run, on a socket of the driver:\n * - `last-received`: the last segment that the socket received before the fault held. A band of\n * the kernel counts from the last segment of any kind. A band that a line ends is a timer of\n * the driver. It counts from the last segment with data that the socket received or sent.\n * - `request-sent`: the send of the operation into the fault, the second `sent` line.\n * - `first-retransmission`: the first retransmission of the RTO timer on the socket.\n * - `last-data`: the last segment with data that the socket received or sent before the fault\n * held, for a band of the kernel too. An idle timer of a peer counts from the end of a stream.\n * - `peer-closed`: the change of state of the socket of the target, when its process dies.\n * - `fault`: the start of the commit of the fault. `client-start`: the `connecting` line.\n * - `first-sent`: the first segment with data that the socket sends after the fault.\n * - `last-reply`: the refusal that a retry follows. It is the last segment with data that a socket\n * of the client received before the end of the band (`end`). The retry can go on another socket.\n * A reference that this judge does not know (`ping-sent`) does not come: its band is a finding.\n */\nexport const referenceOf = (run: Run, from: Reference, role: string, data: boolean, end: number = Infinity): number | undefined => {\n const ready = run.events.find((event) => event.ev === \"ready\");\n const before = run.fault?.t1 ?? ready?.t ?? Infinity;\n if (from === \"fault\") return run.fault?.t0;\n if (from === \"client-start\") return (run.events.find((event) => event.ev === \"connecting\") ?? run.events[0])?.t;\n if (from === \"request-sent\") return run.events.filter((event) => event.ev === \"sent\")[1]?.t;\n // a retry can go on a new connection: its refusal is the last data that a socket of the client got\n if (from === \"last-reply\")\n return run.kernel.filter((record) => record.netns === run.netns && record.mono < end && record.ev === \"rx\" && (record.seg?.len.value ?? 0) > 0).at(-1)?.mono;\n const { socket, place } = kernelOf(run, role, before);\n if (place === undefined) return undefined;\n if (from === \"last-received\" || from === \"last-data\") {\n // the idle timer of a Node socket starts again at each read and at each write of data\n const withData = data || from === \"last-data\";\n const counts = (record: KernelRecord) =>\n withData ? (record.ev === \"rx\" || record.ev === \"tx\") && (record.seg?.len.value ?? 0) > 0 : record.ev === \"rx\";\n return place.records.filter((record) => record.mono <= before && counts(record)).at(-1)?.mono;\n }\n if (from === \"first-sent\")\n return place.records.find((record) => record.ev === \"tx\" && record.mono > before && (record.seg?.len.value ?? 0) > 0)?.mono;\n // the connect of the socket: its change to SYN_SENT, which the kernel stamps when it sends the SYN\n if (from === \"syn-sent\") return place.records.find((record) => record.ev === \"state\" && newState(record) === 2)?.mono;\n if (from === \"first-retransmission\") {\n const request = run.events.filter((event) => event.ev === \"sent\")[1]?.t ?? before;\n return place.records.find((record) => record.ev === \"retrans\" && record.why === \"rto\" && record.mono > request)?.mono;\n }\n // before 0.11.22 an unknown reference fell to the close of the peer: through a proxy, that was the\n // first close of a socket of the target, for example the idle close of an upstream connection\n if (from !== \"peer-closed\") return undefined;\n // the close of the peer: the socket of the target leaves ESTABLISHED\n const peer = socket === undefined ? undefined : peerPlace(run, socket.local);\n const closed = peer?.records.find((record) => record.ev === \"state\" && oldState(record) === 1)?.mono;\n if (closed !== undefined || run.topology === undefined) return closed;\n return proxiedClose(run);\n};\n\n/**\n * This function gives the close of the target behind a proxy. It is the first socket of the target\n * toward the last hop that leaves ESTABLISHED after the outset. A proxy opens its own connection to the\n * target, with a port of its own, and a pooler keeps it across its clients. Thus no socket of the\n * target has the port of the client, and the one of the run can be older than the run. The death of\n * the process of the target closes each of them at once.\n */\nexport const proxiedClose = (run: Run): number | undefined => {\n if (run.topology === undefined) return undefined;\n const hop = run.topology.targetPeer;\n const outset = outsetOf(run);\n return run.kernel.find(\n (record) =>\n record.netns === run.targetNetns && record.ev === \"state\" && oldState(record) === 1 && record.mono >= outset && record.dst !== undefined && ipOf(record.dst) === hop,\n )?.mono;\n};\n\n/** This function gives the address of an address with its port. */\nconst ipOf = (address: string): string => address.slice(0, address.lastIndexOf(\":\"));\n\n/** This function gives the first line of the client that matches, after an instant. */\nconst lineAfter = (events: readonly ProbeEvent[], match: LineMatch, after: number): ProbeEvent | undefined =>\n events.find((event) => event.t > after && matches(event, match));\n\n/** This function gives the name of the error of a line: the field that the match names, or `name`. */\nconst nameOf = (line: ProbeEvent, match: LineMatch): string => String(fieldOf(line, match.name ?? \"name\") ?? line.ev);\n\n/**\n * This function gives the report of the kernel on a socket after an instant: an error, or the end of\n * the file (CLOSE_WAIT). With neither, a close of the socket in SYN_SENT is the end. The program gave\n * up on its connect, and the kernel reports no error and sends no FIN. A refused connect also leaves\n * SYN_SENT, but it has its error.\n */\nconst reportOf = (place: KernelPlace, after: number): { at: number; outcome: Outcome } | undefined => {\n const report = place.records.find(\n (record) => record.mono > after && ((record.ev === \"error\" && (record.err ?? 0) !== 0) || (record.ev === \"state\" && newState(record) === 8)),\n );\n if (report === undefined) {\n const given = place.records.find((record) => record.mono > after && record.ev === \"state\" && oldState(record) === 2 && newState(record) === 7);\n return given === undefined ? undefined : { at: given.mono, outcome: { kind: \"closed\" } };\n }\n return report.ev === \"error\"\n ? { at: report.mono, outcome: { kind: \"error\", errno: ERRNO[report.err!] ?? `E${report.err}` } }\n : { at: report.mono, outcome: { kind: \"eof\" } };\n};\n\n/**\n * This function gives the latest instant of the bands of a driver prediction, in seconds from their\n * references. A band from the refusal before it (`last-reply`) follows the band before it. Thus the\n * times of those bands add: five retries of 30 s end 150 s after the first refusal.\n */\nexport const longestOf = (cell: Cell): number => {\n const { prediction } = cell;\n if (prediction.detects === null) return valueIn(prediction.window, \"s\");\n const then = prediction.driver?.then ?? [];\n const steps = then.map((step) => valueIn(step.high, \"s\"));\n const own = prediction.detects ? valueIn(prediction.high, \"s\") : valueIn(prediction.window, \"s\");\n const chained = [...(prediction.detects && prediction.from === \"last-reply\" ? [own] : []), ...then.filter((step) => step.from === \"last-reply\").map((step) => valueIn(step.high, \"s\"))];\n return Math.max(own, ...steps, chained.reduce((total, high) => total + high, 0));\n};\n\n/**\n * This function tells if a run of a driver cell has its outcome, so that its wait can stop. For a\n * detection, the outcome is the end of its band and of each later band. A silent prediction waits\n * for its window.\n */\nexport const settled = (cell: Cell, run: Run): boolean => {\n const { prediction } = cell;\n if (prediction.detects !== true || prediction.driver === undefined) return false;\n const driver: DriverBand = prediction.driver;\n const after = outsetOf(run);\n const ended =\n driver.ends === undefined\n ? (() => {\n const { place } = kernelOf(run, driver.socket, run.fault?.t1 ?? after);\n return place !== undefined && reportOf(place, after) !== undefined;\n })()\n : lineAfter(run.events, driver.ends, after) !== undefined;\n return ended && (driver.then ?? []).every((step) => lineAfter(run.events, step.ends, after) !== undefined);\n};\n\n/**\n * This function examines the keepalive timer of a socket between two instants. A firing two\n * jiffies or more behind its wheel slot was delayed by the host, which stopped a vCPU. A firing\n * that found the socket held by its owner put itself off by HZ/20. Either way, the run measured\n * something other than the timer.\n */\nconst delayed = (place: KernelPlace, from: number, to: number, hz: number | undefined, noise: Quantity): string | null => {\n const firings = place.records.filter((record) => record.ev === \"timer\" && record.what === \"keepalive\" && record.mono >= from && record.mono <= to);\n const late = firings.find((record) => delayVoids(record.behind?.value ?? 0, hz, noise));\n if (late !== undefined) return `its keepalive timer ran ${late.behind!.value} jiffies behind its wheel slot: the VM delayed it, not the kernel`;\n const held = firings.find((record) => record.owned === true);\n return held === undefined ? null : \"its keepalive timer found the socket held by its owner and put itself off by HZ/20: the run measured the owner, not the timer\";\n};\n\n/**\n * This function reads one run of a driver cell.\n * - The band of the cell counts from its reference on its socket. It ends at its line, or at the\n * report of the kernel on that socket.\n * - Each later band (`then`) gets the same test. A later band outside its band, or absent, is a finding.\n * - A line that the prediction names as quiet, after the fault and in its window, is a finding.\n * So is a flow of an open socket of the driver that a router forgot, for a silent prediction.\n * A prediction with `middlebox.forgets` gives a band for the flow of the socket of the driver. The\n * band counts from the last segment that the socket got before the fault.\n * - A silent prediction can time a reply (`reply`), and the verdict tests it against `replies`.\n *\n * A run is void when the prober lost records, or when the client did not get its first reply. It\n * is also void when the operation went out before the fault held. A late lift of a hold and a\n * keepalive probe before the fault also make it void. So do a delayed timer and a round trip\n * above the assumption.\n */\nexport const measureDriver = (cell: Cell, run: Run): Measured => {\n const { prediction } = cell;\n if (prediction.detects === null || prediction.driver === undefined) throw new Error(`${cell.name} has no driver band`);\n const driver = prediction.driver;\n const { events } = run;\n const ready = events.find((event) => event.ev === \"ready\");\n const request = events.filter((event) => event.ev === \"sent\")[1];\n const after = outsetOf(run);\n const before = run.fault?.t1 ?? ready?.t ?? after;\n const { place } = kernelOf(run, driver.socket, before);\n const records = place?.records ?? [];\n const pool = kernelOf(run, \"pool\", before).place;\n const srtt = pool?.records.find((record) => record.tcp?.srtt !== undefined)?.tcp?.srtt;\n const rtt = srtt === undefined ? null : quantity(valueIn(srtt, \"us\") / 1000, \"ms\");\n const base = {\n environment: run.environment,\n index: run.index,\n probes: records.filter((record) => record.ev === \"probe\" && record.what === \"keepalive\").length,\n retransmissions: records.filter((record) => record.ev === \"retrans\").length,\n acks: request === undefined ? 0 : records.filter((record) => record.ev === \"rx\" && record.mono > request.t).length,\n rtt,\n };\n const nothing = { outcome: { kind: \"silent\" } as const, elapsed: null, socket: null, noticed: null, steps: [], finding: null };\n\n if (cell.before !== true && ready === undefined) return { ...base, ...nothing, void: \"the client never had its reply\" };\n if (run.lost === null) return { ...base, ...nothing, void: \"the prober wrote no clock line after the run, so nothing says what it dropped\" };\n if (run.lost > 0) return { ...base, ...nothing, void: `the prober dropped ${run.lost} records` };\n\n let voided: string | null = null;\n if (cell.probe.mode !== \"idle\" && cell.before !== true) {\n if (request === undefined) voided = \"the operation was never sent into the fault\";\n else if (requestFirst(cell)) {\n // an event at a hop that comes while the operation is in flight: the operation goes first\n if (run.fault !== null && run.fault.t0 < request.t) voided = \"the event came before the operation\";\n } else if (run.fault !== null && run.fault.t1 > request.t) voided = \"the operation went out before the fault held\";\n }\n const keepalive = records.find((record) => record.ev === \"probe\" && record.what === \"keepalive\");\n if (voided === null && run.fault !== null && keepalive !== undefined && keepalive.mono < run.fault.t1)\n voided = \"a keepalive probe went out before the fault held\";\n if (voided === null && cell.hold !== undefined && run.fault !== null) {\n const heal = run.heal ?? null;\n if (heal === null) voided = \"the fault never lifted\";\n else {\n const late = (heal.t0 - run.fault.t0) / 1e9 - valueIn(cell.hold, \"s\");\n if (late > valueIn(INJECT, \"s\")) voided = `the lift came ${Math.round(late * 1e4) / 10} ms after its hold: the injector was late, not the client`;\n }\n }\n const assumed = prediction.rtt;\n if (voided === null && assumed !== undefined && rtt !== null && valueIn(rtt, \"ms\") > valueIn(assumed.high, \"ms\"))\n voided = `rtt-over-assumption: its first round trip was ${rtt.value} ms, above the ${valueIn(assumed.high, \"ms\")} ms that the prediction assumes`;\n\n const findings: string[] = [];\n const noise = valueIn(noiseOf(cell), \"s\");\n // the end of the window: the window of a silent prediction, or the end of the run\n const until = prediction.detects ? Infinity : after + valueIn(prediction.window, \"s\") * 1e9;\n for (const match of driver.quiet ?? []) {\n const line = events.find((event) => event.t > after && event.t <= until && matches(event, match));\n if (line !== undefined) findings.push(`${wordsOf(match)} came ${between(after, line.t).value} s after the fault, where none should`);\n }\n const expected = prediction.detects ? undefined : prediction.middlebox?.forgets;\n if (!prediction.detects && (run.middlebox !== undefined || expected !== undefined)) {\n // a router forgets a flow of a socket that is still open: the flow of a live connection is gone,\n // unless the prediction says when the router forgets the flow of the socket of the driver\n const own = socketAt(events, driver.socket, before)?.local;\n if (expected !== undefined && own === undefined) findings.push(`the client opened no ${driver.socket} socket before the fault`);\n const middlebox: NonNullable<Run[\"middlebox\"]> = run.middlebox ?? [];\n for (const socket of socketsOf(events)) {\n const forgot = middlebox.find(\n (line) =>\n line.ev === \"ct\" &&\n line[\"type\"] === \"DESTROY\" &&\n String(line[\"orig\"] ?? \"\").startsWith(`${socket.local}>`) &&\n line.t > socket.opened &&\n (socket.ended === null || line.t < socket.ended) &&\n line.t <= until,\n );\n if (expected === undefined || socket.local !== own) {\n if (forgot !== undefined) findings.push(`a router forgot the flow of the ${socket.role} socket ${between(after, forgot.t).value} s after the fault, where it should keep it`);\n continue;\n }\n // the band counts from the last segment that the socket got before the fault, as for the client of TCP\n const last = referenceOf(run, \"last-received\", driver.socket, false);\n if (forgot === undefined) findings.push(`no router forgot the flow of the ${socket.role} socket in the window, where it should forget it`);\n else if (last === undefined) findings.push(`the ${socket.role} socket got no segment before the fault`);\n else {\n const at = between(last, forgot.t).value;\n const [low, high] = [round(valueIn(expected.low, \"s\") - noise), round(valueIn(expected.high, \"s\") + noise)];\n if (at < low || at > high) findings.push(`a router forgot the flow of the ${socket.role} socket ${at} s after its last segment, outside [${low}, ${high}] s`);\n }\n }\n }\n const stepTimes: DriverStepTime[] = (driver.then ?? []).map((step) => {\n const line = lineAfter(events, step.ends, after);\n const from = referenceOf(run, step.from, step.socket ?? driver.socket, true, line?.t);\n if (line === undefined || from === undefined) {\n findings.push(line === undefined ? `${step.what}: ${wordsOf(step.ends)} never came` : `${step.what}: its reference (${step.from}) never came`);\n return { what: step.what, name: line === undefined ? null : nameOf(line, step.ends), elapsed: null };\n }\n const elapsed = between(from, line.t);\n const name = nameOf(line, step.ends);\n if (step.name !== \"OK\" && name !== step.name) findings.push(`${step.what}: it ended with ${name}, not ${step.name}`);\n const [low, high] = [round(valueIn(step.low, \"s\") - noise), round(valueIn(step.high, \"s\") + noise)];\n if (elapsed.value < low || elapsed.value > high) findings.push(`${step.what}: ${elapsed.value} s is outside [${low}, ${high}] s`);\n return { what: step.what, name, elapsed };\n });\n const stepped = stepTimes.length === 0 ? {} : { driver: { steps: stepTimes } };\n\n if (!prediction.detects) {\n if (driver.reply === undefined || prediction.replies === undefined)\n return { ...base, ...nothing, ...stepped, void: voided, finding: findings[0] ?? null };\n const line = lineAfter(events, driver.reply.ends, after);\n const from = referenceOf(run, driver.reply.from, driver.socket, true, line?.t);\n if (line === undefined || from === undefined)\n return { ...base, ...nothing, ...stepped, void: voided, finding: findings[0] ?? `the reply never came: ${wordsOf(driver.reply.ends)}` };\n return {\n ...base,\n ...nothing,\n ...stepped,\n outcome: { kind: \"answered\" },\n elapsed: between(from, line.t),\n void: voided,\n finding: findings[0] ?? null,\n };\n }\n\n // the band of the cell: its line, or the report of the kernel on its socket\n const line = driver.ends === undefined ? undefined : lineAfter(events, driver.ends, after);\n const report = driver.ends === undefined && place !== undefined ? reportOf(place, after) : undefined;\n if (driver.ends === undefined && place === undefined)\n return { ...base, ...nothing, ...stepped, void: voided ?? `the prober saw nothing of the ${driver.socket} socket`, finding: findings[0] ?? null };\n const ended = line?.t ?? report?.at;\n const outcome: Outcome =\n line !== undefined && driver.ends !== undefined ? { kind: \"error\", errno: nameOf(line, driver.ends) } : (report?.outcome ?? { kind: \"silent\" });\n if (ended === undefined)\n return { ...base, ...nothing, ...stepped, void: voided, finding: findings[0] ?? `nothing detected it: ${prediction.timer} never fired` };\n const reference = referenceOf(run, prediction.from, driver.socket, driver.ends !== undefined, ended);\n if (reference === undefined)\n return { ...base, ...nothing, ...stepped, outcome, void: voided, finding: `it ended without its reference event (${prediction.from} on the ${driver.socket} socket)` };\n if (driver.ends === undefined && prediction.from === \"last-received\" && place !== undefined) voided ??= delayed(place, reference, ended, run.hz, noiseOf(cell));\n const name = outcome.kind === \"error\" ? outcome.errno : outcome.kind === \"eof\" ? \"EOF\" : outcome.kind === \"closed\" ? \"CLOSED\" : \"silent\";\n if (prediction.errno !== \"OK\" && name !== prediction.errno) findings.unshift(`it ended with ${name}, not ${prediction.errno}`);\n // the client's own view: its first error line after the report of the kernel\n const seen = report === undefined ? undefined : events.find((event) => event.t >= report.at && (event.ev === \"error\" || event.ev === \"socket-error\"));\n return {\n ...base,\n ...stepped,\n outcome,\n elapsed: between(reference, ended),\n socket: seen === undefined ? null : between(reference, seen.t),\n noticed: report === undefined || seen === undefined ? null : between(report.at, seen.t),\n steps: (prediction.from === \"last-received\" ? records.filter((record) => record.ev === \"probe\" && record.what === \"keepalive\" && record.mono > reference) : []).map(\n (record) => between(reference, record.mono),\n ),\n void: voided,\n finding: findings[0] ?? null,\n };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { KernelRecord, ProbeEvent, QueueBand, QueueConnection, QueuePrediction, Run } from \"./cell.ts\";\nimport type { Measured } from \"./observe.ts\";\n\n/** This bit is the SYN of the flags of an `rx` record of the prober. */\nconst SYN = 2;\n\n/** This record is what one connection of a queue cell did, from its lines and the records of its socket. */\nexport interface QueueConnectionReading {\n readonly name: string;\n readonly connected: boolean;\n /** These times are the waits of the SYN. The first one counts from the dial. */\n readonly syns: readonly Quantity[];\n /** These times are the waits of each SYN-ACK sent again. The first one counts from the dial. */\n readonly synAcks: readonly Quantity[];\n /** This count is the segments that the socket sent again. */\n readonly retransmissions: number;\n readonly errno: string | null;\n /** This time is from the line of the prediction to the end of the connection. It is null for a live connection, or with no prediction. */\n readonly ended: Quantity | null;\n /** This time is from the last retransmission to the end of the connection. */\n readonly afterLast: Quantity | null;\n /** This count is the segments of the socket with no acknowledgment at the end of the run. */\n readonly unacked: number | null;\n}\n\n/** This record is what a run of a queue cell measured. The counts are the changes in the run. */\nexport interface QueueReading {\n readonly max: number;\n readonly held: number;\n readonly connected: number;\n readonly overflows: number;\n readonly drops: number;\n readonly cookies: number;\n readonly timeouts: number;\n readonly resets: number;\n readonly drained: number;\n /** This time is from the first dial of the burst to the last `TCPTimeouts` of the prediction. */\n readonly expiry: Quantity | null;\n /** This time is from the first dial of the burst to the rise of the count of the queue. */\n readonly rise: Quantity | null;\n readonly connections: readonly QueueConnectionReading[];\n}\n\n/** This function gives the time between two stamps of CLOCK_MONOTONIC. */\nexport const between = (from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\nconst numberOf = (line: ProbeEvent, field: string): number => {\n const value = line[field];\n return typeof value === \"number\" ? value : 0;\n};\n\n/** This function says if a time is inside a band. */\nexport const inside = (time: Quantity, band: QueueBand): boolean => {\n const seconds = valueIn(time, \"s\");\n return seconds >= valueIn(band.low, \"s\") && seconds <= valueIn(band.high, \"s\");\n};\n\n/** This function gives the words of a band. */\nexport const bandWords = (band: QueueBand): string => `[${valueIn(band.low, \"s\")}, ${valueIn(band.high, \"s\")}] s`;\n\nconst waitsOf = (from: number, stamps: readonly number[]): Quantity[] =>\n stamps.map((stamp, at) => between(at === 0 ? from : stamps[at - 1]!, stamp));\n\n/** This function finds the records of the sockets of the client that had this local address. */\nconst socketsAt = (run: Run, local: unknown): KernelRecord[] => {\n const cookies = new Set(\n run.kernel.filter((record) => record.netns === run.netns && record.src === local).map((record) => record.cookie),\n );\n return run.kernel.filter((record) => record.netns === run.netns && cookies.has(record.cookie));\n};\n\nconst readConnection = (name: string, run: Run, expected: QueueConnection | undefined): QueueConnectionReading => {\n const lineOf = (ev: string): ProbeEvent | undefined =>\n run.events.find((event) => event.ev === ev && event[\"name\"] === name);\n const dial = lineOf(\"dial\");\n const connected = lineOf(\"connected\");\n const failed = lineOf(\"failed\");\n const state = lineOf(\"state\");\n const socket = dial === undefined ? [] : socketsAt(run, dial[\"local\"]);\n const sent = socket.filter((record) => record.ev === \"retrans\").map((record) => record.mono);\n const rx = socket.filter((record) => record.ev === \"rx\" && ((record.seg?.flags ?? 0) & SYN) !== 0);\n const from = dial?.t ?? 0;\n const start = expected?.ends === null || expected?.ends === undefined ? undefined : lineOf(expected.ends.from);\n const last = sent.at(-1);\n return {\n name,\n connected: connected !== undefined,\n // a socket that connected sends its data again, not its SYN\n syns: waitsOf(from, connected === undefined ? sent : sent.filter((stamp) => stamp < connected.t)),\n synAcks: waitsOf(\n from,\n rx.map((record) => record.mono),\n ),\n retransmissions: sent.length,\n errno: failed === undefined ? null : String(failed[\"errno\"]),\n ended: failed === undefined || start === undefined ? null : between(start.t, failed.t),\n afterLast: failed === undefined || last === undefined ? null : between(last, failed.t),\n unacked: state === undefined ? null : numberOf(state, \"unacked\"),\n };\n};\n\n/** This function reads one run against the band of each wait in a list, and gives the words of each miss. */\nconst waitFindings = (what: string, seen: readonly Quantity[], bands: readonly QueueBand[]): string[] => {\n if (seen.length !== bands.length) return [`${what}: ${seen.length} waits, not ${bands.length}`];\n return seen.flatMap((wait, at) =>\n inside(wait, bands[at]!) ? [] : [`${what}: wait ${at} of ${valueIn(wait, \"s\")} s, outside ${bandWords(bands[at]!)}`],\n );\n};\n\nconst connectionFindings = (\n expected: QueueConnection,\n read: QueueConnectionReading,\n expiredAt: number | null,\n stamps: readonly number[],\n): string[] => {\n const { name, ends } = expected;\n const found: string[] = [];\n if (read.connected !== expected.connects)\n found.push(`${name}: ${read.connected ? \"connected\" : \"did not connect\"}, against the prediction`);\n if (expected.syns !== undefined) found.push(...waitFindings(`${name} SYN`, read.syns, expected.syns));\n if (expected.synAcks !== undefined) found.push(...waitFindings(`${name} SYN-ACK`, read.synAcks, expected.synAcks));\n if (expected.unacked !== undefined && read.unacked !== expected.unacked)\n found.push(`${name}: ${read.unacked ?? \"no\"} segments without an ACK, not ${expected.unacked}`);\n if (ends === null) {\n if (read.errno !== null) found.push(`${name}: ended with ${read.errno}, and the prediction has no end`);\n return found;\n }\n if (read.errno !== ends.errno) found.push(`${name}: ended with ${read.errno ?? \"nothing\"}, not ${ends.errno}`);\n if (read.ended === null) return [...found, `${name}: no time for its end`];\n if (!inside(read.ended, ends.within))\n found.push(`${name}: its end came at ${valueIn(read.ended, \"s\")} s, outside ${bandWords(ends.within)}`);\n if (ends.retransmitted === undefined) return found;\n if (read.afterLast === null || !inside(read.afterLast, ends.retransmitted))\n found.push(`${name}: its end came ${read.afterLast === null ? \"with no retransmission\" : `${valueIn(read.afterLast, \"s\")} s after its last retransmission`}, outside ${bandWords(ends.retransmitted)}`);\n if (expiredAt === null) return found;\n const before = stamps.at(-2);\n const last = stamps.at(-1);\n if (last === undefined || last < expiredAt || (before !== undefined && before > expiredAt))\n found.push(`${name}: its last two retransmissions do not span the expiry`);\n return found;\n};\n\n/**\n * This function reads one run of a queue cell. The client lines give the connections and the\n * counters at the two ends of the run. The target lines give the count of the queue. The records of\n * the prober give the waits of each socket.\n */\nexport const measureQueue = (run: Run, expected: QueuePrediction): Measured => {\n const { events, kernel } = run;\n const lineOf = (ev: string): ProbeEvent | undefined => events.find((event) => event.ev === ev);\n const base = {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions: kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length,\n acks: 0,\n };\n const voided = (why: string): Measured => ({ ...base, void: why, finding: null });\n const opened = lineOf(\"opened\");\n const stats = lineOf(\"stats\");\n if (opened === undefined) return voided(\"the target did not open its listener\");\n if (stats === undefined || lineOf(\"done\") === undefined) return voided(\"the client did not reach its end\");\n if (run.lost === null) return voided(\"the prober wrote no clock line after the run, so nothing says what it dropped\");\n if (run.lost > 0) return voided(`the prober dropped ${run.lost} records`);\n const lines = (run.server ?? []).filter((line) => line.ev === \"queue\" && line.t >= opened.t);\n if (lines.length === 0) return voided(\"the target wrote no queue line in the run\");\n\n const named = [...new Set(events.filter((event) => event.ev === \"dial\").map((event) => String(event[\"name\"])))];\n const predicted = new Map(expected.connections.map((each) => [each.name, each]));\n const connections = named.map((name) => readConnection(name, run, predicted.get(name)));\n const admitted = expected.admitted === undefined ? undefined : connections.find((each) => each.name === expected.admitted);\n if (expected.admitted !== undefined && (admitted === undefined || !admitted.connected || admitted.unacked !== 0))\n return voided(`${expected.admitted} did not take the last place in the queue: the burst did not land in its sequence`);\n\n const change = (field: string): number => numberOf(stats, field) - numberOf(opened, field);\n const burst = events.find((event) => event.ev === \"dial\" && event[\"name\"] === \"in\")?.t ?? opened.t;\n const counted = expected.expiry?.timeouts;\n const expired = counted === undefined ? undefined : lines.find((line) => numberOf(line, \"timeouts\") - numberOf(opened, \"timeouts\") >= counted);\n const accepted = events.find((event) => event.ev === \"accepted\");\n // the rise counts from the first count below it: a line of the count before the accept can come after the reply of the accept\n const rise = expected.rise?.count ?? 0;\n const low = accepted === undefined ? -1 : lines.findIndex((line) => line.t >= accepted.t && numberOf(line, \"count\") < rise);\n const risen = low < 0 ? undefined : lines.slice(low).find((line) => numberOf(line, \"count\") >= rise);\n const drained = events\n .filter((event) => event.ev === \"accepted\")\n .reduce((sum, event) => sum + (Array.isArray(event[\"peers\"]) ? event[\"peers\"].length : 0), 0);\n const queue: QueueReading = {\n max: numberOf(opened, \"max\"),\n held: Math.max(...lines.map((line) => numberOf(line, \"count\"))),\n connected: connections.filter((each) => each.connected).length,\n overflows: change(\"overflows\"),\n drops: change(\"drops\"),\n cookies: change(\"cookies\"),\n timeouts: change(\"timeouts\"),\n resets: change(\"resets\"),\n drained,\n expiry: expired === undefined ? null : between(burst, expired.t),\n rise: risen === undefined ? null : between(burst, risen.t),\n connections,\n };\n\n const found: string[] = [];\n if (queue.max !== expected.max) found.push(`the limit is ${queue.max}, not ${expected.max}`);\n if (queue.held !== expected.held) found.push(`the queue held ${queue.held}, not ${expected.held}`);\n if (queue.connected !== expected.connected) found.push(`${queue.connected} connected, not ${expected.connected}`);\n if (queue.overflows < expected.overflows.low || queue.overflows > expected.overflows.high)\n found.push(`${queue.overflows} overflows, outside [${expected.overflows.low}, ${expected.overflows.high}]`);\n if (queue.resets !== expected.resets) found.push(`${queue.resets} resets, not ${expected.resets}`);\n if (queue.cookies !== 0) found.push(`${queue.cookies} SYN cookies, and the law has none`);\n if (expected.drained !== undefined && queue.drained !== expected.drained)\n found.push(`${queue.drained} accepted, not ${expected.drained}`);\n if (expected.expiry !== undefined && (queue.expiry === null || !inside(queue.expiry, expected.expiry.within)))\n found.push(`the expiry came at ${queue.expiry === null ? \"no time\" : `${valueIn(queue.expiry, \"s\")} s`}, outside ${bandWords(expected.expiry.within)}`);\n if (expected.rise !== undefined && (queue.rise === null || !inside(queue.rise, expected.rise.within)))\n found.push(`the count got back to ${expected.rise.count} at ${queue.rise === null ? \"no time\" : `${valueIn(queue.rise, \"s\")} s`}, outside ${bandWords(expected.rise.within)}`);\n for (const each of expected.connections) {\n const read = connections.find((connection) => connection.name === each.name);\n if (read === undefined) {\n found.push(`${each.name}: the client did not dial it`);\n continue;\n }\n const dial = events.find((event) => event.ev === \"dial\" && event[\"name\"] === each.name);\n const stamps = socketsAt(run, dial?.[\"local\"]).filter((record) => record.ev === \"retrans\").map((record) => record.mono);\n found.push(...connectionFindings(each, read, expired?.t ?? null, stamps));\n }\n return { ...base, void: null, finding: found.length === 0 ? null : found.join(\". \"), queue };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { ConntrackPrediction, ProbeEvent, Run } from \"./cell.ts\";\nimport type { Measured } from \"./observe.ts\";\nimport { bandWords, between, inside } from \"./queue.ts\";\n\n/** This errno tells that a connect got a slot. */\nconst NONE = \"none\";\n\n/** This record is the end of a connect that found no entry at its start. */\nexport interface StallReading {\n readonly errno: string;\n readonly time: Quantity;\n /** This count is the rise of the field `drop` of the conntrack statistics during the connect. */\n readonly drops: number;\n /** This count is the rise of `TCPRetransFail` during the connect. */\n readonly retransFail: number;\n}\n\n/** This record is what a run of a conntrack cell measured. */\nexport interface ConntrackReading {\n /** This count is the flows that the client holds at its `full` line. */\n readonly flows: number;\n /** This count is what the namespace of the client reads at that line. */\n readonly count: number;\n /** This count is what the namespace of the target reads while the client holds its flows. */\n readonly neighbor: number | null;\n readonly stall: StallReading | null;\n /** This time is from the `closing` line to the first fall of the count. */\n readonly firstFall: Quantity | null;\n /** This time is from the `closing` line to the zero of the count. */\n readonly zero: Quantity | null;\n /** This count is what the namespace reads after each side closes. */\n readonly closed: number | null;\n /** This count is the lowest that the poll of the count read. */\n readonly lowest: number | null;\n /** This count is what the namespace reads after a connect that got a slot. */\n readonly after: number | null;\n}\n\nconst numberOr = (line: ProbeEvent | undefined, field: string): number | null => {\n const value = line?.[field];\n return typeof value === \"number\" ? value : null;\n};\n\n/** This function gives the time from one stamp to a stamp of a field of a line, when the line has it. */\nconst untilField = (from: ProbeEvent | undefined, line: ProbeEvent | undefined, field: string): Quantity | null => {\n const stamp = numberOr(line, field);\n return from === undefined || stamp === null ? null : between(from.t, stamp);\n};\n\nconst stallOf = (line: ProbeEvent | undefined): StallReading | null =>\n line === undefined\n ? null\n : {\n errno: String(line[\"errno\"]),\n time: quantity(Math.round((numberOr(line, \"elapsed\") ?? 0) / 1e3) / 1e6, \"s\"),\n drops: numberOr(line, \"drops\") ?? 0,\n retransFail: numberOr(line, \"retrans_fail\") ?? 0,\n };\n\n/** This function tells where a reading differs from the law of its cell. */\nconst findingsOf = (read: ConntrackReading, failed: unknown, expected: ConntrackPrediction): string[] => {\n const found: string[] = [];\n const { max, neighbor, refused, drained, pressure } = expected;\n if (typeof failed === \"string\") found.push(`a connect failed with ${failed} before the client held its flows`);\n if (read.flows !== max) found.push(`the client held ${read.flows} flows, not ${max}`);\n if (read.count !== max) found.push(`the count read ${read.count} at the fill, not ${max}`);\n if (neighbor !== undefined && read.neighbor !== neighbor)\n found.push(`the namespace of the target read ${read.neighbor ?? \"nothing\"}, not ${neighbor}`);\n if (refused !== undefined) {\n const stall = read.stall;\n if (stall === null) found.push(\"no connect after the fill ended\");\n else {\n if (stall.errno !== refused.errno) found.push(`the connect after the fill ended with ${stall.errno}, not ${refused.errno}`);\n if (!inside(stall.time, refused.within))\n found.push(`the connect after the fill took ${valueIn(stall.time, \"s\")} s, outside ${bandWords(refused.within)}`);\n if (stall.drops !== refused.drops) found.push(`the field drop rose by ${stall.drops}, not ${refused.drops}`);\n if (stall.retransFail !== refused.retransFail) found.push(`TCPRetransFail rose by ${stall.retransFail}, not ${refused.retransFail}`);\n }\n }\n if (drained !== undefined) {\n for (const [name, time] of [[\"first fall\", read.firstFall], [\"zero\", read.zero]] as const) {\n if (time === null || !inside(time, drained))\n found.push(`the ${name} of the count came at ${time === null ? \"no time\" : `${valueIn(time, \"s\")} s`}, outside ${bandWords(drained)}`);\n }\n }\n if (pressure !== undefined) {\n const stall = read.stall;\n if (read.closed !== max) found.push(`the count read ${read.closed ?? \"nothing\"} after each side closed, not ${max}`);\n const { highest } = pressure;\n if (highest === undefined) {\n if (read.lowest !== pressure.lowest) found.push(`the lowest count was ${read.lowest ?? \"nothing\"}, not ${pressure.lowest}`);\n if (read.after !== pressure.after) found.push(`the count read ${read.after ?? \"nothing\"} after the connect, not ${pressure.after}`);\n } else if (read.lowest === null || read.lowest < pressure.lowest || read.lowest > highest) {\n found.push(`the lowest count was ${read.lowest ?? \"nothing\"}, outside ${pressure.lowest} to ${highest}`);\n } else if (read.after !== read.lowest + 1) {\n found.push(`the count read ${read.after ?? \"nothing\"} after the connect, not ${read.lowest + 1}`);\n }\n if (stall === null) found.push(\"no connect after the close ended\");\n else {\n if (stall.errno !== NONE) found.push(`the connect after the close ended with ${stall.errno}`);\n if (!pressure.points.some((point) => inside(stall.time, point)))\n found.push(`the connect after the close took ${valueIn(stall.time, \"s\")} s, on no point of the schedule`);\n }\n }\n return found;\n};\n\n/**\n * This function reads one run of a conntrack cell from the lines of its client and its target. An\n * `unsettled` line makes the run void. The entries of the run before it were still in the table, thus\n * the run did not start from an empty table.\n */\nexport const measureConntrack = (run: Run, expected: ConntrackPrediction): Measured => {\n const { events, kernel } = run;\n const retransmissions = kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length;\n const base = {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions,\n acks: 0,\n };\n const voided = (why: string): Measured => ({ ...base, void: why, finding: null });\n const unsettled = events.find((event) => event.ev === \"unsettled\");\n if (unsettled !== undefined) return voided(`the table held ${String(unsettled[\"count\"])} entries at the end of the wait before the run`);\n if (events.find((event) => event.ev === \"done\") === undefined) {\n // the program writes the error that stopped it as its last line\n const error = events.find((event) => event.ev === \"error\");\n return voided(error === undefined ? \"the client did not reach its end\" : `the client did not reach its end: ${String(error[\"what\"])}`);\n }\n if (run.lost === null) return voided(\"the prober wrote no clock line after the run, so nothing says what it dropped\");\n if (run.lost > 0) return voided(`the prober dropped ${run.lost} records`);\n\n const full = events.find((event) => event.ev === \"full\");\n if (full === undefined) return voided(\"the client wrote no line for its fill\");\n const stall = events.find((event) => event.ev === \"stall\");\n const closing = events.find((event) => event.ev === \"closing\");\n const drained = events.find((event) => event.ev === \"drained\");\n const closed = events.find((event) => event.ev === \"closed\");\n // the count of the neighbor while the client holds its flows: from the fill to the end of the connect after it\n const neighbor = (run.server ?? []).filter((line) => line.ev === \"count\" && line.t >= full.t && (stall === undefined || line.t <= stall.t)).at(-1);\n const conntrack: ConntrackReading = {\n flows: numberOr(full, \"flows\") ?? 0,\n count: numberOr(full, \"count\") ?? 0,\n neighbor: numberOr(neighbor, \"count\"),\n stall: stallOf(stall),\n firstFall: untilField(closing, drained, \"first_fall\"),\n zero: untilField(closing, drained, \"zero\"),\n closed: numberOr(closed, \"count\"),\n lowest: numberOr(drained ?? stall, \"lowest\"),\n after: numberOr(stall, \"after\"),\n };\n const found = findingsOf(conntrack, full[\"errno\"], expected);\n return { ...base, void: null, finding: found.length === 0 ? null : found.join(\". \"), conntrack };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { PauseBand, PausePrediction, ProbeEvent, Run } from \"./cell.ts\";\nimport type { Measured } from \"./observe.ts\";\n\n/**\n * This module reads one run of a paused consumer against its law. Two members of a group each hold\n * one partition. A SIGSTOP stops the first member while it holds a batch, and a SIGCONT ends that\n * stop. Three sources give the reading: the lines of each member, the log lines of the brokers, and\n * the stamps of the injector.\n *\n * The broker writes its log on the clock of the wall, and the members and the injector use the\n * monotonic clock. The `start` line of a member has both clocks, thus it converts a log line.\n */\n\n/** A commit reading is the first commit of the stopped member after the stop. */\nexport interface PauseCommit {\n readonly acked: boolean;\n /** This name is the class of the error of the commit. It is null for a commit that the broker acknowledged. */\n readonly name: string | null;\n readonly message: string | null;\n /** This number is the epoch that the member held at the commit. */\n readonly epoch: number | null;\n}\n\n/** A pause reading is what one run of a paused consumer measured. Each offset is the next offset to read, as a commit names it. */\nexport interface PauseReading {\n /** This number is the partition of the stopped member before the stop. */\n readonly partition: number;\n /** This time is from the stop to the log line of the broker that removes the member. It is null when no such line came. */\n readonly fence: Quantity | null;\n /** This time is from the stop to the first report of the partition by the other member. It is null when no report came. */\n readonly takeover: Quantity | null;\n readonly commit: PauseCommit | null;\n /** This number is the epoch at the last acknowledged commit before the stop. */\n readonly epochBefore: number | null;\n /** This offset is the last acknowledged commit of the stopped member before the stop. */\n readonly lastAck: number;\n /** This offset is the first offset of the partition that the other member read after the stop. */\n readonly otherFirst: number | null;\n /** This offset is the last acknowledged commit of the other member on the partition, before the commit of the stopped member. */\n readonly otherLast: number | null;\n /** This time is from the end of the stop to the new epoch of the member. It is null when no new epoch came. */\n readonly rejoin: Quantity | null;\n /** This value tells if the stopped member reported the partition again between the end of the stop and its commit. */\n readonly reassigned: boolean;\n /** This offset is the committed offset that the member read after its commit. */\n readonly committed: number | null;\n /** This offset is what the first commit after the stop names for the partition. */\n readonly stale: number | null;\n}\n\n/** This expression finds the stamp of a log line of a broker, as its console writes it, on UTC. */\nconst LOG_TIME = /\\[(\\d{4})-(\\d\\d)-(\\d\\d) (\\d\\d):(\\d\\d):(\\d\\d),(\\d{3})\\]/;\n\n/** This function gives the time of a log line on the monotonic clock of a member, in ns, from the `start` line of that member. It is null for a line with no stamp. */\nexport const logTimeOf = (line: string, start: ProbeEvent): number | null => {\n const found = LOG_TIME.exec(line);\n if (found === null) return null;\n const wall = Date.UTC(Number(found[1]), Number(found[2]) - 1, Number(found[3]), Number(found[4]), Number(found[5]), Number(found[6]), Number(found[7]));\n return start.t + (wall - Number(start[\"wall\"])) * 1e6;\n};\n\n/** This function gives the time between two instants of the monotonic clock, in s, to 1 microsecond. */\nconst secondsBetween = (from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\nconst isInside = (time: Quantity, band: PauseBand): boolean => {\n const seconds = valueIn(time, \"s\");\n return seconds >= valueIn(band.low, \"s\") && seconds <= valueIn(band.high, \"s\");\n};\n\nconst bandText = (band: PauseBand): string => `[${valueIn(band.low, \"s\")}, ${valueIn(band.high, \"s\")}] s`;\n\nconst isChange = (event: ProbeEvent): boolean => event.ev === \"assigned\" || event.ev === \"revoked\" || event.ev === \"lost\";\n\n/** This function gives the partitions that a line of the rebalance listener names, in its field `partitions` or `held`. */\nconst partitionsOf = (event: ProbeEvent, field: \"partitions\" | \"held\"): readonly number[] => (event[field] as readonly number[] | undefined) ?? [];\n\n/** This function gives the last line of the rebalance listener in a list of lines. */\nconst lastChange = (events: readonly ProbeEvent[]): ProbeEvent | undefined => events.findLast(isChange);\n\n/** This function gives the offset that a commit names for a partition, or null. */\nconst offsetOf = (event: ProbeEvent, partition: number): number | null => {\n const value = (event[\"offsets\"] as Readonly<Record<string, number | null>> | undefined)?.[String(partition)];\n return typeof value === \"number\" ? value : null;\n};\n\n/**\n * This function tells if the two members can take the fault. Each member holds one partition, the\n * two partitions differ, and the first member has two acknowledged commits on its partition after its\n * last change. Thus the first member reads and commits at a steady rate.\n */\nexport const pauseReady = (first: readonly ProbeEvent[], other: readonly ProbeEvent[]): boolean => {\n const mine = lastChange(first);\n const theirs = lastChange(other);\n if (mine === undefined || theirs === undefined) return false;\n const held = partitionsOf(mine, \"held\");\n const others = partitionsOf(theirs, \"held\");\n if (held.length !== 1 || others.length !== 1 || held[0] === others[0]) return false;\n const commits = first.filter((event) => event.ev === \"commit\" && event.t > mine.t && offsetOf(event, held[0]!) !== null);\n return commits.length >= 2;\n};\n\n/** This function tells if a log line of a broker tells that a member left a group, under either protocol. */\nexport const isFenceLine = (line: string): boolean =>\n /Member \\S+ fenced from the group because|Member \\S+ in group \\S+ has failed, removing it from the group/.test(line);\n\n/** This function tells if a fence line names a group. The two protocols write the name in different words. */\nexport const namesGroup = (line: string, group: string): boolean => line.includes(`[GroupId ${group}]`) || line.includes(`in group ${group} has`);\n\n/** This function compares a reading to the law, and gives each disagreement. */\nconst findingsOf = (reading: PauseReading, prediction: PausePrediction, fences: readonly string[], otherReports: boolean): string[] => {\n const found: string[] = [];\n const { commit, fence, takeover } = reading;\n if (prediction.fence === null) {\n if (fences.length > 0) found.push(`the group removed a member: ${fences[0]}`);\n if (otherReports) found.push(\"the other member reported the partition\");\n } else {\n if (fence === null) found.push(\"no log line tells of a fence, and the other member did not report the partition\");\n else if (!isInside(fence, prediction.fence)) found.push(`the fence is ${valueIn(fence, \"s\")} s, outside ${bandText(prediction.fence)}`);\n if (reading.otherFirst !== reading.lastAck) found.push(`the other member started at offset ${reading.otherFirst}, and the last commit is ${reading.lastAck}`);\n }\n if (prediction.takeover !== null) {\n if (takeover === null) found.push(\"the other member did not report the partition\");\n else if (!isInside(takeover, prediction.takeover)) found.push(`the other member reported the partition at ${valueIn(takeover, \"s\")} s, outside ${bandText(prediction.takeover)}`);\n }\n if (commit === null) {\n found.push(\"the member made no commit after the stop\");\n return found;\n }\n switch (prediction.thaw) {\n case \"fails\":\n if (commit.name !== \"CommitFailedException\") found.push(`the commit after the stop gave ${commit.name ?? \"an acknowledgment\"}, not CommitFailedException`);\n break;\n case \"acknowledged\":\n if (!commit.acked) found.push(`the commit after the stop failed with ${commit.name}`);\n if (commit.epoch !== reading.epochBefore) found.push(`the epoch changed from ${reading.epochBefore} to ${commit.epoch}`);\n break;\n case \"rejoin\": {\n const within = prediction.rejoinWithin;\n if (reading.rejoin === null) found.push(\"the member did not get a new epoch\");\n else if (within !== undefined && valueIn(reading.rejoin, \"s\") > valueIn(within, \"s\")) found.push(`the new epoch came at ${valueIn(reading.rejoin, \"s\")} s, above ${valueIn(within, \"s\")} s`);\n if (!commit.acked) found.push(`the stale commit failed with ${commit.name}`);\n if (reading.reassigned) found.push(\"the member held the partition again before its commit\");\n if (reading.committed !== reading.stale) found.push(`the committed offset is ${reading.committed}, and the stale commit named ${reading.stale}`);\n if (reading.stale === null || reading.otherLast === null || reading.stale >= reading.otherLast) found.push(`the stale commit ${reading.stale} is not below the progress ${reading.otherLast} of the other member`);\n break;\n }\n }\n return found;\n};\n\n/** This function reads one run of a paused consumer against its law. */\nexport const measurePause = (run: Run, prediction: PausePrediction): Measured => {\n const retransmissions = run.kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length;\n const base = {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions,\n acks: 0,\n };\n const voided = (why: string): Measured => ({ ...base, void: why, finding: null });\n\n const { fault, heal, pause } = run;\n if (fault === null || pause === undefined) return voided(\"the partitions were not one for each member before the stop\");\n if (heal === undefined || heal === null) return voided(\"the stop did not end\");\n const stop = fault.t0;\n const thaw = heal.t0;\n const before = run.events.filter((event) => event.t < stop);\n const after = run.events.filter((event) => event.t >= stop);\n const start = run.events.find((event) => event.ev === \"start\");\n if (start === undefined) return voided(\"the member wrote no start line\");\n\n const mine = lastChange(before);\n const theirs = lastChange(pause.other.filter((event) => event.t < stop));\n const held = mine === undefined ? [] : partitionsOf(mine, \"held\");\n const others = theirs === undefined ? [] : partitionsOf(theirs, \"held\");\n const partition = held[0];\n if (partition === undefined || held.length !== 1 || others.length !== 1 || others[0] === partition)\n return voided(\"the partitions were not one for each member before the stop\");\n if (after.find((event) => event.ev === \"pause\")?.[\"in\"] !== \"process\") return voided(\"the stop landed outside the processing of a batch\");\n if (before.findLast((event) => event.ev === \"read\")?.[\"partition\"] !== partition) return voided(\"the last read before the stop was on another partition\");\n const lastCommit = before.findLast((event) => event.ev === \"commit\" && offsetOf(event, partition) !== null);\n if (lastCommit === undefined) return voided(\"the member had no acknowledged commit on its partition before the stop\");\n\n const member = String(mine?.[\"member\"]);\n const fenceLines = pause.fences.filter((line) => line.includes(member));\n const fenceAt = fenceLines.map((line) => logTimeOf(line, start)).find((time) => time !== null && time >= stop) ?? null;\n const taken = pause.other.find((event) => event.ev === \"assigned\" && event.t >= stop && partitionsOf(event, \"partitions\").includes(partition));\n if (prediction.fence !== null && fenceAt === null && taken !== undefined) return voided(\"the broker log lost the line of the fence\");\n\n const thawed = after.find((event) => event.ev === \"commit\" || event.ev === \"commit-fail\");\n const rejoined = after.find((event) => event.ev === \"rejoined\");\n const ackAt = thawed?.t ?? Number.POSITIVE_INFINITY;\n const otherCommit = pause.other.findLast((event) => event.ev === \"commit\" && event.t < ackAt && offsetOf(event, partition) !== null);\n const committed = after.find((event) => event.ev === \"committed\");\n const epochOf = (event: ProbeEvent | undefined): number | null => (typeof event?.[\"epoch\"] === \"number\" ? event[\"epoch\"] : null);\n\n const pauseReading: PauseReading = {\n partition,\n fence: fenceAt === null ? null : secondsBetween(stop, fenceAt),\n takeover: taken === undefined ? null : secondsBetween(stop, taken.t),\n commit:\n thawed === undefined\n ? null\n : {\n acked: thawed.ev === \"commit\",\n name: typeof thawed[\"name\"] === \"string\" ? thawed[\"name\"] : null,\n message: typeof thawed[\"message\"] === \"string\" ? thawed[\"message\"] : null,\n epoch: epochOf(thawed),\n },\n epochBefore: epochOf(lastCommit),\n lastAck: offsetOf(lastCommit, partition)!,\n otherFirst: (pause.other.find((event) => event.ev === \"read\" && event.t >= stop && event[\"partition\"] === partition)?.[\"first\"] as number | undefined) ?? null,\n otherLast: otherCommit === undefined ? null : offsetOf(otherCommit, partition),\n rejoin: rejoined === undefined ? null : secondsBetween(thaw, rejoined.t),\n reassigned: after.some((event) => event.ev === \"assigned\" && event.t >= thaw && event.t <= ackAt && partitionsOf(event, \"partitions\").includes(partition)),\n committed: committed === undefined ? null : offsetOf(committed, partition),\n stale: thawed === undefined ? null : offsetOf(thawed, partition),\n };\n const findings = findingsOf(pauseReading, prediction, pause.fences, taken !== undefined);\n return { ...base, void: null, finding: findings.length === 0 ? null : findings.join(\". \"), pause: pauseReading };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { PortsPrediction, ProbeEvent, Run } from \"./cell.ts\";\nimport type { Measured } from \"./observe.ts\";\nimport { bandWords, between, inside } from \"./queue.ts\";\n\n/** This errno ends a search that found no port. */\nconst NO_PORT = \"EADDRNOTAVAIL\";\n\n/** This record is what a run of a port cell measured. */\nexport interface PortsReading {\n /** This count is the rounds of the run, each destination once. */\n readonly rounds: number;\n /** This record gives the count of searches for each count of connects, by that count. */\n readonly counts: Readonly<Record<string, number>>;\n /** These offsets from the low port are the ports that the run used, in rising order. */\n readonly seen: readonly number[];\n /** These errnos ended the searches of the run, each one time. */\n readonly errnos: readonly string[];\n /** This time is the longest connect that failed. */\n readonly refusal: Quantity;\n /** This time is from the `closing` line to the first `freed` line. */\n readonly firstFreed: Quantity | null;\n /** This time is from the `closing` line to the last `freed` line. */\n readonly lastFreed: Quantity | null;\n /** This count is the `freed` lines of the run. */\n readonly freed: number;\n /** This count is the connects that failed before the last `freed` line. */\n readonly tries: number;\n}\n\nconst portsOf = (line: ProbeEvent): readonly number[] =>\n Array.isArray(line[\"ports\"]) ? line[\"ports\"].filter((port): port is number => typeof port === \"number\") : [];\n\n/** This function says if the ports of the parity of the low port come first in one search. */\nconst lowFirst = (ports: readonly number[], low: number): boolean => {\n const odd = ports.findIndex((port) => (port - low) % 2 !== 0);\n return odd < 0 || ports.slice(odd).every((port) => (port - low) % 2 !== 0);\n};\n\n/**\n * This function reads one run of a port cell. The `round` lines give each search. The `closing` and\n * `freed` lines give when each held port comes back. The records of the prober give the\n * retransmissions.\n */\nexport const measurePorts = (run: Run, expected: PortsPrediction): Measured => {\n const { events, kernel } = run;\n const retransmissions = kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length;\n const base = {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions,\n acks: 0,\n };\n const voided = (why: string): Measured => ({ ...base, void: why, finding: null });\n if (events.find((event) => event.ev === \"done\") === undefined) return voided(\"the client did not reach its end\");\n if (run.lost === null) return voided(\"the prober wrote no clock line after the run, so nothing says what it dropped\");\n if (run.lost > 0) return voided(`the prober dropped ${run.lost} records`);\n\n const rounds = events.filter((event) => event.ev === \"round\");\n const closing = events.find((event) => event.ev === \"closing\");\n const freedLines = events.filter((event) => event.ev === \"freed\");\n const counts: Record<string, number> = {};\n for (const round of rounds) {\n const count = String(portsOf(round).length);\n counts[count] = (counts[count] ?? 0) + 1;\n }\n const seen = [...new Set(rounds.flatMap((round) => portsOf(round).map((port) => port - expected.low)))].sort((a, b) => a - b);\n const refusal = Math.max(0, ...rounds.map((round) => (typeof round[\"refusal\"] === \"number\" ? round[\"refusal\"] : 0)));\n const first = freedLines[0];\n const last = freedLines.at(-1);\n const ports: PortsReading = {\n rounds: rounds.length,\n counts,\n seen,\n errnos: [...new Set(rounds.map((round) => String(round[\"errno\"])))],\n refusal: quantity(Math.round(refusal / 1e3) / 1e6, \"s\"),\n firstFreed: closing === undefined || first === undefined ? null : between(closing.t, first.t),\n lastFreed: closing === undefined || last === undefined ? null : between(closing.t, last.t),\n freed: freedLines.length,\n tries: last === undefined || typeof last[\"tries\"] !== \"number\" ? 0 : last[\"tries\"],\n };\n\n const found: string[] = [];\n const searches = expected.rounds * expected.destinations;\n if (ports.rounds !== searches) found.push(`${ports.rounds} searches, not ${searches}`);\n const stray = Object.keys(counts).filter((count) => !expected.counts.includes(Number(count)));\n if (stray.length > 0) found.push(`a search gave ${stray.join(\" or \")} connects, outside ${expected.counts.join(\" or \")}`);\n if (seen.join() !== expected.seen.join()) found.push(`the ports at offsets ${seen.join(\" \")} were used, not ${expected.seen.join(\" \")}`);\n if (ports.errnos.join() !== NO_PORT) found.push(`the searches ended with ${ports.errnos.join(\" and \")}, not ${NO_PORT}`);\n if (valueIn(ports.refusal, \"s\") > valueIn(expected.refusedWithin, \"s\"))\n found.push(`a refused connect took ${valueIn(ports.refusal, \"s\")} s, above ${valueIn(expected.refusedWithin, \"s\")} s`);\n if (expected.share !== undefined) {\n const { count, low, high } = expected.share;\n const share = (counts[String(count)] ?? 0) / Math.max(1, ports.rounds);\n if (share < low || share > high) found.push(`the share of ${count} connects is ${share}, outside [${low}, ${high}]`);\n }\n if (expected.lowFirst === true && !rounds.every((round) => lowFirst(portsOf(round), expected.low)))\n found.push(\"a search got a port of the other parity before each port of the parity of the low port\");\n if (expected.retransmissions !== undefined && retransmissions !== expected.retransmissions)\n found.push(`${retransmissions} retransmissions, not ${expected.retransmissions}`);\n if (expected.freed !== undefined) {\n const held = Math.max(...expected.counts);\n if (ports.freed !== held) found.push(`${ports.freed} ports came back, not ${held}`);\n for (const [name, time] of [[\"first\", ports.firstFreed], [\"last\", ports.lastFreed]] as const) {\n if (time === null || !inside(time, expected.freed))\n found.push(`the ${name} port came back at ${time === null ? \"no time\" : `${valueIn(time, \"s\")} s`}, outside ${bandWords(expected.freed)}`);\n }\n if (ports.tries === 0) found.push(\"no connect was refused before the ports came back\");\n }\n return { ...base, void: null, finding: found.length === 0 ? null : found.join(\". \"), ports };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Drill, ProbeEvent, ReplicaSet, Run } from \"./cell.ts\";\nimport type { Writes } from \"./timeline.ts\";\n\n/**\n * This module holds the pure parts of a recovery drill. These are the scripts of the shell, the reader\n * of the output of `bsondump`, and the set check of a recovery. It has no container, thus unit tests\n * run it. `drill.ts` does the drill on a lab.\n *\n * A dump with `--oplog` reads the oplog from the start of the dump to its end. A slice reads the\n * oplog after the last entry of the backup before it. Thus the backups together hold each write up\n * to the last entry of the last backup, and no write after it. One writer sends the writes one at a\n * time, thus the highest sequence number is also the latest write.\n */\n\n/** This size is one document of generated data. A tenant holds as many documents as its size needs. */\nexport const SEED_DOCUMENT = 65_536;\n/** This count is how far the lost writes can be from the writes after the last backup: the writes in flight at the fault. */\nexport const LOSS_MARGIN = 2;\n/** This time is how long a script waits for a server to stop, in tenths of a second. */\nconst STOP_TENTHS = 600;\n\n/** This function gives the time of a drill from the start of the backups to the fault, in seconds. */\nexport const drillSpan = (drill: Drill): number => drill.slices * valueIn(drill.sliceEvery, \"s\") + valueIn(drill.age, \"s\");\n\n/**\n * This script writes the generated data of each tenant into the collection `tenants`. Each write\n * waits for `copies` members, thus each member holds the data when the script ends.\n */\nexport const seedScript = (drill: Drill, copies: number): string => {\n const documents = Math.ceil(valueIn(drill.perTenant, \"B\") / SEED_DOCUMENT);\n const blob = `BinData(0, require(\"crypto\").randomBytes(${SEED_DOCUMENT}).toString(\"base64\"))`;\n return (\n 'const c = db.getSiblingDB(\"cells\"); ' +\n `c.tenants.drop({ writeConcern: { w: ${copies} } }); ` +\n `for (let t = 1; t <= ${drill.tenants}; t += 1) { const docs = []; ` +\n `for (let d = 1; d <= ${documents}; d += 1) docs.push({ _id: \"t\" + t + \".d\" + d, tenant: t, blob: ${blob} }); ` +\n `c.tenants.insertMany(docs, { writeConcern: { w: ${copies}, wtimeout: 60000 } }); } ` +\n \"print(JSON.stringify({ ok: true }))\"\n );\n};\n\n/** This script prints the hash of the collection `tenants`. It takes locks, thus a run reads it with no writer. */\nexport const HASH_SCRIPT: string =\n 'print(JSON.stringify({ hash: db.getSiblingDB(\"cells\").runCommand({ dbHash: 1, collections: [\"tenants\"] }).collections.tenants }))';\n\n/** This function gives the hash from the output of `HASH_SCRIPT`. */\nexport const hashOf = (text: string): string => {\n const line = text.split(\"\\n\").filter((each) => each.trim() !== \"\").at(-1) ?? \"\";\n const { hash } = JSON.parse(line) as { readonly hash?: unknown };\n if (typeof hash !== \"string\" || hash === \"\") throw new Error(`no hash of the tenants in: ${line}`);\n return hash;\n};\n\n/** This function gives the command of a server with no set, on its own port. A client of the set cannot reach that server, and a restore writes to it. */\nexport const standaloneCommand = (set: ReplicaSet, port: number): string =>\n `${set.programs.server} --bind_ip_all --port ${port} ${(set.args ?? []).join(\" \")}`.trim();\n\n/**\n * This script waits for the end of the server of a box, and it can stop the server first. `kill -0`\n * also succeeds on a zombie, and the shell of the box can leave its child as a zombie for a long\n * time. Thus the script reads the state of the process, and a zombie has ended.\n */\nexport const stopScript = (terminate: boolean): string =>\n \"pid=$(cat /tmp/server.pid); \" +\n (terminate ? 'kill -TERM \"$pid\"; ' : \"\") +\n `for i in $(seq 1 ${STOP_TENTHS}); do s=$(cut -d' ' -f3 /proc/$pid/stat 2>/dev/null); ` +\n 'if [ -z \"$s\" ] || [ \"$s\" = Z ]; then exit 0; fi; sleep 0.1; done; exit 1';\n\n/** This function gives a number from Extended JSON, in its relaxed form or in its canonical form, or null. */\nconst numberOf = (value: unknown): number | null => {\n if (typeof value === \"number\") return value;\n if (typeof value !== \"object\" || value === null) return null;\n const wrapped = value as { readonly $numberInt?: unknown; readonly $numberLong?: unknown; readonly $numberDouble?: unknown };\n const text = wrapped.$numberInt ?? wrapped.$numberLong ?? wrapped.$numberDouble;\n return typeof text === \"string\" && text !== \"\" && Number.isFinite(Number(text)) ? Number(text) : null;\n};\n\n/** This function gives each document of the output of `bsondump`. A line that is not a document does not count. */\nconst documentsOf = (text: string): Array<Record<string, unknown>> =>\n text.split(\"\\n\").flatMap((line) => {\n if (!line.trim().startsWith(\"{\")) return [];\n try {\n return [JSON.parse(line) as Record<string, unknown>];\n } catch {\n return [];\n }\n });\n\n/** An oplog time is the `ts` of an oplog entry: a time in seconds, and the count of the entry in that second. */\nexport interface OplogTime {\n readonly t: number;\n readonly i: number;\n}\n\n/** This function gives the `ts` of an oplog entry, or null. */\nconst timeOf = (entry: Record<string, unknown>): OplogTime | null => {\n const stamp = (entry[\"ts\"] as { readonly $timestamp?: { readonly t?: unknown; readonly i?: unknown } } | undefined)?.$timestamp;\n const t = numberOf(stamp?.t);\n const i = numberOf(stamp?.i);\n return t === null || i === null ? null : { t, i };\n};\n\n/** An oplog read is what an oplog file holds: its last entry, and the highest sequence number that it inserts. */\nexport interface OplogRead {\n readonly last: OplogTime | null;\n readonly highest: number | null;\n}\n\n/** This function reads an oplog file from the output of `bsondump`. Only an insert into `cells.w` is a write of a client. */\nexport const readOplog = (text: string): OplogRead => {\n let last: OplogTime | null = null;\n let highest: number | null = null;\n for (const entry of documentsOf(text)) {\n const time = timeOf(entry);\n if (time !== null && (last === null || time.t > last.t || (time.t === last.t && time.i > last.i))) last = time;\n if (entry[\"op\"] !== \"i\" || entry[\"ns\"] !== \"cells.w\") continue;\n const n = numberOf((entry[\"o\"] as { readonly n?: unknown } | undefined)?.n);\n if (n !== null && (highest === null || n > highest)) highest = n;\n }\n return { last, highest };\n};\n\n/** This function gives the highest sequence number of the file of the writes in a dump, from the output of `bsondump`, or null. */\nexport const highestHeld = (text: string): number | null => {\n const held = documentsOf(text).flatMap((document) => {\n const n = numberOf(document[\"n\"]);\n return n === null ? [] : [n];\n });\n return held.length === 0 ? null : Math.max(...held);\n};\n\n/** This function gives the query of a slice of the oplog: each entry after an oplog time, in Extended JSON. */\nexport const sliceQuery = (after: OplogTime): string => JSON.stringify({ ts: { $gt: { $timestamp: { t: after.t, i: after.i } } } });\n\n/** A recovery measurement is what a drill found, beside the writes of the run. */\nexport interface RecoveryMeasured {\n /** This time is from the reply to the last accepted write that the store kept to the fault, or null with no such write. */\n readonly rpo: Quantity | null;\n /** This time is `rpo` less the age of the drill: what a schedule adds to its interval. It is null for a control and for an election. */\n readonly excess: Quantity | null;\n /** These are the accepted writes that the store lost, below a write that it kept. A restore must leave none. */\n readonly holes: readonly number[];\n /** This count is the number of accepted writes after the last write of the last backup, or null without a backup. */\n readonly afterBackup: number | null;\n /** This flag tells if the tenants have the same data after the recovery, or null when that is not known. */\n readonly sameData: boolean | null;\n}\n\nconst rounded = (value: number): number => Math.round(value * 1e6) / 1e6;\n\n/** This function gives the acknowledgement time of each accepted write of the first client of a run. */\nconst firstAcks = (events: readonly ProbeEvent[], second: number | null): Map<number, number> => {\n const acks = new Map<number, number>();\n for (const event of events) {\n const n = Number(event[\"n\"]);\n if (event.ev === \"ack\" && (second === null || n < second)) acks.set(n, event.t);\n }\n return acks;\n};\n\n/** This function gives the measurement of a drill, from its run. `t0` is the fault. */\nexport const recoveryOf = (drill: Drill, run: Run, t0: number): RecoveryMeasured => {\n const record = run.group?.drill;\n const sameData = record === undefined || record.after === null ? null : record.after === record.before;\n if (drill.recovery === \"election\" || record === undefined) return { rpo: null, excess: null, holes: [], afterBackup: null, sameData };\n const acks = firstAcks(run.events, record.second);\n const accepted = [...acks.keys()].sort((a, b) => a - b);\n const cutoff = record.backups.at(-1)?.last?.n ?? 0;\n const afterBackup = accepted.filter((n) => n > cutoff).length;\n const holds = run.group?.holds ?? null;\n if (holds === null) return { rpo: null, excess: null, holes: [], afterBackup, sameData };\n const kept = new Set(holds);\n const ownKept = holds.filter((n) => record.second === null || n < record.second);\n const highest = ownKept.length === 0 ? 0 : Math.max(...ownKept);\n const holes = accepted.filter((n) => n < highest && !kept.has(n));\n const lastKept = accepted.filter((n) => kept.has(n)).at(-1);\n const rpo = lastKept === undefined ? null : rounded((t0 - acks.get(lastKept)!) / 1e9);\n return {\n rpo: rpo === null ? null : { value: rpo, unit: \"s\" },\n excess: rpo === null || drill.quiet === true ? null : { value: rounded(rpo - valueIn(drill.age, \"s\")), unit: \"s\" },\n holes,\n afterBackup,\n sameData,\n };\n};\n\n/** This function gives the findings of a drill: each rule of a recovery that its run broke. */\nexport const recoveryFindings = (measured: RecoveryMeasured, writes: Writes): string[] => {\n const findings: string[] = [];\n if (measured.sameData === null) findings.push(\"the set did not converge, thus nothing compared the data of the tenants\");\n else if (!measured.sameData) findings.push(\"the data of the tenants changed in the recovery\");\n if (measured.holes.length > 0)\n findings.push(`the restore lost ${measured.holes.length} accepted writes below a write that it kept, the first at ${measured.holes[0]}`);\n const lost = writes.lost?.length ?? null;\n if (measured.afterBackup !== null && lost !== null && Math.abs(lost - measured.afterBackup) > LOSS_MARGIN)\n findings.push(`the restore lost ${lost} accepted writes, and ${measured.afterBackup} came after the last backup`);\n return findings;\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, ClusterStage, KernelRecord, ProbeEvent, ReplicaSetStage, Run, SentinelEvent, SentinelStage, Stage } from \"./cell.ts\";\nimport { socketsOf } from \"./driver.ts\";\nimport type { RecoveryMeasured } from \"./recovery.ts\";\nimport { recoveryFindings, recoveryOf } from \"./recovery.ts\";\nimport { INJECT, noiseOf } from \"./verdict.ts\";\n\n/**\n * This module measures a run of a group cell. It gives the first write that a primary accepted\n * after the fault, and the timeline of the group. The Sentinels of a group announce its timeline.\n * The logs of the members of a replica set or of the nodes of a cluster, and its client, tell it. The\n * module also gives what became of each write.\n */\n\n/** These are the stages of a timeline under Sentinels, in their sequence after a fault. */\nexport const STAGES: readonly SentinelStage[] = [\n \"+sdown\",\n \"+odown\",\n \"+try-failover\",\n \"+elected-leader\",\n \"+selected-slave\",\n \"+promoted-slave\",\n \"+switch-master\",\n \"+convert-to-slave\",\n];\n\n/** An error on the way is one kind of error that the client met after the fault. It has its first time from the fault, and its count. */\nexport interface ErrorOnTheWay {\n readonly name: string;\n readonly first: Quantity;\n readonly count: number;\n}\n\n/**\n * A writes record tells what became of the writes of a run, by their sequence numbers:\n * - `old` counts the writes that the primary of the start of the run accepted after the fault. A\n * cluster counts none: its client publishes through one node, not through the leader of the queue.\n * - `lost` are the writes that a primary accepted and the group did not keep. They are the cost\n * of a split brain. It is null when the group did not converge after the run.\n * - `unknown` are the writes that the client sent and did not see accepted: an error, or no answer.\n * `held` tells if the group kept each one, or null when it did not converge.\n * - `duplicates` has one entry for each extra copy that the group holds: a write held three times\n * has two entries. It is null when the group did not converge. A key holds one copy by\n * construction, thus only a list can show a copy.\n */\nexport interface Writes {\n readonly sent: number;\n readonly acked: number;\n readonly old: number;\n readonly lost: readonly number[] | null;\n readonly unknown: ReadonlyArray<{ readonly n: number; readonly held: boolean | null }>;\n readonly duplicates?: readonly number[] | null;\n /** These are the counts of a pair (`Cell.pair`), from its two final reads. */\n readonly sets?: PairSets;\n}\n\n/** These are the counts that the bands of `Outcomes` judge: each one has the same name there. */\nexport interface PairSets {\n readonly unknown: number;\n readonly kept: number;\n readonly stranded: number;\n readonly absent: number;\n readonly missing: number;\n readonly warnings: number;\n}\n\n/** A group measurement is what one run of a group cell measured, beside its time. */\nexport interface GroupMeasured {\n /** These are the member that was the primary at the start, and the member of the first accepted write after the fault. */\n readonly from: string;\n readonly to: string | null;\n /** These are the times of each stage from the fault: the first announcement by any Sentinel. A stage that no Sentinel announced is absent. */\n readonly stages: Partial<Record<Stage, Quantity>>;\n readonly writes: Writes;\n readonly errors: readonly ErrorOnTheWay[];\n /** These are the delays of the stamps of the observer after the writes of the Sentinels, for a calibration. */\n readonly lags?: readonly Quantity[];\n /** This is what a recovery drill measured, for a drill only. */\n readonly recovery?: RecoveryMeasured;\n}\n\nconst between =(from: number, to: number): Quantity => quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\n/** This function gives the member whose address and port is `at`, or null. */\nconst memberAt = (run: Run, at: unknown): string | null => {\n if (typeof at !== \"string\") return null;\n const ip = at.split(\":\")[0];\n return Object.entries(run.group?.members ?? {}).find(([, part]) => part.ip === ip)?.[0] ?? null;\n};\n\n/** This function gives the time of each stage of a timeline from an instant: the first announcement of each, after the instant. */\nexport const stagesOf = (timeline: readonly SentinelEvent[], from: number): Partial<Record<Stage, Quantity>> => {\n const out: Partial<Record<Stage, Quantity>> = {};\n for (const line of timeline) {\n if (line.ev !== \"sentinel\" || line.t < from) continue;\n const stage = STAGES.find((each) => each === line.event);\n if (stage === undefined || out[stage] !== undefined) continue;\n // the down states count for the primary only, not for a replica or a Sentinel\n if ((stage === \"+sdown\" || stage === \"+odown\") && !String(line.detail ?? \"\").startsWith(\"master \")) continue;\n out[stage] = between(from, line.t);\n }\n return out;\n};\n\n/** These are the stages of the timeline of a replica set, in their usual sequence after a fault. */\nexport const REPLICA_SET_STAGES: readonly ReplicaSetStage[] = [\n \"member-down\",\n \"election-start\",\n \"elected\",\n \"caught-up\",\n \"writable\",\n \"old-primary-steps-down\",\n \"discovered\",\n \"written-off\",\n \"first-write\",\n];\n\n/**\n * A member mark is how a log line of mongod marks a stage: by its id, or by its message. The\n * message is the fallback for a version whose ids differ. `at` tells where the line comes from:\n * the old primary, or another member.\n */\ninterface MemberMark {\n readonly ids: readonly number[];\n readonly message: RegExp;\n readonly at: \"old\" | \"other\";\n}\n\n/** These are the log lines of mongod that mark each stage of a member. */\nexport const MEMBER_MARKS: Readonly<Record<Exclude<ReplicaSetStage, \"discovered\" | \"written-off\" | \"first-write\">, MemberMark>> = {\n \"member-down\": { ids: [21216], message: /now in state DOWN/, at: \"other\" },\n \"election-start\": { ids: [4615652, 21437], message: /^Starting an election|Skipping dry run|Conducting a dry run/, at: \"other\" },\n elected: { ids: [21450], message: /^Election succeeded/, at: \"other\" },\n \"caught-up\": { ids: [21363], message: /^Exited primary catch-up mode/, at: \"other\" },\n writable: { ids: [21331], message: /^Transition to primary complete/, at: \"other\" },\n \"old-primary-steps-down\": { ids: [21809, 21475, 962660], message: /relinquishing primary|Stepping down from primary/, at: \"old\" },\n};\n\n/** This function tells if a log line of a member marks a stage, with the old primary of the run. */\nconst marks = (line: SentinelEvent, stage: keyof typeof MEMBER_MARKS, old: string, oldAddress: string): boolean => {\n const mark = MEMBER_MARKS[stage];\n const member = String(line[\"member\"] ?? \"\");\n if ((mark.at === \"old\") !== (member === old)) return false;\n const attr = (line[\"attr\"] ?? {}) as Record<string, unknown>;\n // the DOWN state counts for the old primary only, as another member sees it\n if (stage === \"member-down\" && !JSON.stringify(attr).includes(oldAddress)) return false;\n // the generic state change of the old primary: PRIMARY to another state\n if (stage === \"old-primary-steps-down\" && Number(line[\"id\"]) === 21358 && attr[\"oldState\"] === \"PRIMARY\") return true;\n return mark.ids.includes(Number(line[\"id\"])) || mark.message.test(String(line[\"msg\"] ?? \"\"));\n};\n\n/**\n * This function gives the time of each stage of a replica set from an instant, in a run. The stages\n * of the members come from their log lines (`ev` \"mongod\"), whose times the lab puts on the\n * monotonic clock. The stages of the client come from its lines:\n * - `discovered`: a member other than the old primary becomes RSPrimary in the view of the client.\n * - `written-off`: the first heartbeat of the client to the old primary that fails.\n * - `first-write`: the first write that a primary accepts, of a write that the client sent after\n * the commit of the fault (`sentAfter`). It is on a new primary when `lands` is `new`.\n */\nexport const replicaSetStagesOf = (\n run: Run,\n from: number,\n sentAfter: number,\n lands: \"new\" | \"same\",\n): Partial<Record<Stage, Quantity>> => {\n const out: Partial<Record<Stage, Quantity>> = {};\n const old = run.group?.primary ?? \"\";\n const oldIp = run.group?.members[old]?.ip ?? \"\";\n const oldAddress = `${oldIp}:`;\n for (const line of run.group?.timeline ?? []) {\n if (line.ev !== \"mongod\" || line.t < from) continue;\n for (const stage of Object.keys(MEMBER_MARKS) as Array<keyof typeof MEMBER_MARKS>)\n if (out[stage] === undefined && marks(line, stage, old, oldAddress)) out[stage] = between(from, line.t);\n }\n const isOld = (address: unknown): boolean => typeof address === \"string\" && address.startsWith(oldAddress);\n for (const event of run.events) {\n if (event.t < from) continue;\n if (out.discovered === undefined && event.ev === \"sdam\" && event[\"event\"] === \"server-changed\" && !isOld(event[\"address\"])) {\n const next = event[\"next\"] as { readonly type?: string } | null;\n if (next?.type === \"RSPrimary\") out.discovered = between(from, event.t);\n }\n if (out[\"written-off\"] === undefined && event.ev === \"sdam\" && event[\"event\"] === \"heartbeat-failed\" && isOld(event[\"address\"]))\n out[\"written-off\"] = between(from, event.t);\n }\n const accepted = acceptedAfter(run, sentAfter, lands);\n if (accepted !== undefined) out[\"first-write\"] = between(from, accepted.t);\n return out;\n};\n\n/** These are the stages of the timeline of a cluster of RabbitMQ, in their usual sequence after a fault. */\nexport const CLUSTER_STAGES: readonly ClusterStage[] = [\"monitor-down\", \"elected\", \"followed\", \"old-leader-steps-down\", \"first-write\"];\n\n/**\n * These are the log lines of RabbitMQ that mark each stage of a cluster, by their message (ra 3.1.10,\n * ra_server_proc.erl:871, :1336-1345 and :1974). `at` tells where the line comes from: the node of the\n * old leader, or another node.\n */\nexport const NODE_MARKS: Readonly<Record<Exclude<ClusterStage, \"first-write\">, { readonly message: RegExp; readonly at: \"old\" | \"other\" }>> = {\n \"monitor-down\": { message: /Leader monitor down/, at: \"other\" },\n elected: { message: /: candidate -> leader in term/, at: \"other\" },\n followed: { message: /detected a new leader/, at: \"other\" },\n \"old-leader-steps-down\": { message: /: leader -> \\w+ in term/, at: \"old\" },\n};\n\n/**\n * This function gives the time of each stage of a cluster from an instant, in a run. The stages of\n * the nodes come from their log lines (`ev` \"rabbit\"), whose times the lab puts on the monotonic\n * clock. `first-write` is the first confirm of a publish that the client sent after the commit of\n * the fault (`sentAfter`), through any node.\n */\nexport const clusterStagesOf = (run: Run, from: number, sentAfter: number): Partial<Record<Stage, Quantity>> => {\n const out: Partial<Record<Stage, Quantity>> = {};\n const old = run.group?.primary ?? \"\";\n for (const line of run.group?.timeline ?? []) {\n if (line.ev !== \"rabbit\" || line.t < from) continue;\n const member = String(line[\"member\"] ?? \"\");\n for (const stage of Object.keys(NODE_MARKS) as Array<keyof typeof NODE_MARKS>) {\n const mark = NODE_MARKS[stage];\n if (out[stage] === undefined && (mark.at === \"old\") === (member === old) && mark.message.test(String(line[\"msg\"] ?? \"\"))) out[stage] = between(from, line.t);\n }\n }\n const accepted = acceptedAfter(run, sentAfter, \"same\");\n if (accepted !== undefined) out[\"first-write\"] = between(from, accepted.t);\n return out;\n};\n\n/** This function gives the first write that a primary accepted, of a write sent after an instant. It is on a new primary for `new`. */\nconst acceptedAfter = (run: Run, sentAfter: number, lands: \"new\" | \"same\"): ProbeEvent | undefined => {\n const sent = new Map<number, number>();\n for (const event of run.events) if (event.ev === \"sent\") sent.set(Number(event[\"n\"]), event.t);\n const primary = run.group?.primary ?? \"\";\n return run.events.find((event) => {\n if (event.ev !== \"ack\" || (sent.get(Number(event[\"n\"])) ?? -Infinity) <= sentAfter) return false;\n const member = memberAt(run, event[\"at\"]);\n return member !== null && (lands === \"new\" ? member !== primary : true);\n });\n};\n\n/** This function gives what became of each write of a run, from the lines of the client and the keys that the group kept. */\nexport const writesOf = (run: Run, after: number, primary: string): Writes => {\n const { events } = run;\n const sent = events.filter((event) => event.ev === \"sent\");\n // without its done line, the stop ended the last write that the client sent\n const done = events.find((event) => event.ev === \"done\")?.t ?? sent.at(-1)?.t ?? Infinity;\n const acks = new Map<number, ProbeEvent>();\n for (const event of events) if (event.ev === \"ack\") acks.set(Number(event[\"n\"]), event);\n const holds = run.group?.holds ?? null;\n const kept = holds === null ? null : new Set(holds);\n const old = [...acks.values()].filter((event) => event.t > after && memberAt(run, event[\"at\"]) === primary).length;\n const lost = kept === null ? null : [...acks.keys()].filter((n) => !kept.has(n)).sort((a, b) => a - b);\n // a write in flight when the client stopped is not on the way: the stop ended it\n const unknown = sent\n .filter((event) => event.t < done && !acks.has(Number(event[\"n\"])))\n .map((event) => {\n const n = Number(event[\"n\"]);\n return { n, held: kept === null ? null : kept.has(n) };\n });\n // each entry that repeats the one before it, in order, is one extra copy\n const duplicates = holds === null ? null : [...holds].sort((a, b) => a - b).filter((n, at, all) => all[at - 1] === n);\n const oldHolds = run.group?.oldHolds;\n return { sent: sent.length, acked: acks.size, old, lost, unknown, duplicates, ...(oldHolds === undefined ? {} : { sets: setsOf(run, acks.keys(), unknown, new Set(oldHolds)) }) };\n};\n\n/**\n * This function splits the writes of a pair by its two final reads. A write with no reply is `kept`\n * on the new primary. It is `stranded` on the old primary alone, or `absent` from each server.\n */\nconst setsOf = (run: Run, acked: Iterable<number>, unknown: Writes[\"unknown\"], old: ReadonlySet<number>): PairSets => {\n const kept = unknown.filter((each) => each.held === true).length;\n const stranded = unknown.filter((each) => each.held !== true && old.has(each.n)).length;\n return {\n unknown: unknown.length,\n kept,\n stranded,\n absent: unknown.length - kept - stranded,\n missing: [...acked].filter((n) => !old.has(n)).length,\n warnings: run.events.filter((event) => event.ev === \"notice\" && event[\"severity\"] === \"WARNING\").length,\n };\n};\n\n/** This function gives the errors that the client met after an instant: each kind, its first time, and its count. */\nexport const errorsOf = (events: readonly ProbeEvent[], after: number): ErrorOnTheWay[] => {\n const done = events.find((event) => event.ev === \"done\")?.t ?? Infinity;\n const kinds = new Map<string, { first: number; count: number }>();\n for (const event of events) {\n if (event.t <= after || event.t >= done) continue;\n const name =\n event.ev === \"error\"\n ? String(event[\"errno\"] ?? event[\"name\"] ?? \"error\")\n : event.ev === \"fail\"\n ? String(event[\"name\"] ?? \"fail\")\n : event.ev === \"sentinel-error\"\n ? \"sentinel-error\"\n : null;\n if (name === null) continue;\n const seen = kinds.get(name);\n if (seen === undefined) kinds.set(name, { first: event.t, count: 1 });\n else seen.count += 1;\n }\n return [...kinds].map(([name, { first, count }]) => ({ name, first: between(after, first), count }));\n};\n\n/**\n * This function gives the delay of each stamp of the observer after the write of its Sentinel that\n * the observer read. That write is the latest write of the Sentinel's socket toward the observer,\n * at the stamp or before it. The prober records each write (`tx`) on the clock of the stamps.\n */\nexport const lagsOf = (run: Run, kernel: readonly KernelRecord[]): Quantity[] => {\n const timeline = run.group?.timeline ?? [];\n const locals = new Map<string, string>();\n for (const line of timeline) if (line.ev === \"subscribed\") locals.set(String(line.sentinel), String(line[\"local\"]));\n const out: Quantity[] = [];\n for (const line of timeline) {\n if (line.ev !== \"sentinel\") continue;\n const sentinel = String(line.sentinel);\n const local = locals.get(sentinel);\n if (local === undefined) continue;\n const write = kernel\n .filter((record) => record.ev === \"tx\" && record.src === sentinel && record.dst === local && record.mono <= line.t)\n .at(-1);\n if (write !== undefined) out.push(between(write.mono, line.t));\n }\n return out;\n};\n\n/** This type is the measurement of observe.ts, which a group run fills. */\nexport interface GroupReading {\n readonly outcome: { readonly kind: \"answered\" } | { readonly kind: \"silent\" };\n readonly elapsed: Quantity | null;\n readonly socket: Quantity | null;\n readonly noticed: Quantity | null;\n readonly void: string | null;\n readonly finding: string | null;\n readonly group: GroupMeasured;\n}\n\n/**\n * This function reads one run of a group cell.\n * - The reference is the start of the commit of the fault, as the injector stamped it. For a\n * stall, it is the first write into the fault, as for the stall of a direct pair.\n * - The outcome is the first write that a primary accepted after the fault. The prediction says\n * which primary: a new one, or the same one after the lift. In a replica set, it is the first\n * accepted write of a write that the client sent after the commit of the fault.\n * - The stages come from the Sentinels, or from the logs of the members of a replica set and the\n * lines of its client (`replicaSetStagesOf`).\n * - Its time is the last segment with data that the client's socket to that primary received\n * before the client saw the acceptance. The stamp of the client is the fallback.\n * - A run is void when the prober lost records, or when the client did not become ready. It is\n * also void when a Sentinel entered its TILT mode, or when the election split its votes. A band\n * from the fault whose commit took longer than δ_abs is void too. So is a band whose hold lifted\n * more than δ_abs late.\n */\nexport const measureGroup = (cell: Cell, run: Run): GroupReading => {\n const { events, kernel } = run;\n const { prediction } = cell;\n const expected = prediction.group;\n const primary = run.group?.primary ?? \"\";\n const ready = events.find((event) => event.ev === \"ready\");\n const t0 = run.fault?.t0;\n const empty: GroupMeasured = {\n from: primary,\n to: null,\n stages: {},\n writes: { sent: 0, acked: 0, old: 0, lost: null, unknown: [] },\n errors: [],\n };\n const silent = { outcome: { kind: \"silent\" } as const, elapsed: null, socket: null, noticed: null, finding: null };\n if (ready === undefined) return { ...silent, void: \"the client never became ready\", group: empty };\n if (t0 === undefined || run.fault === null) return { ...silent, void: \"the fault never committed\", group: empty };\n if (run.lost === null)\n return { ...silent, void: \"the prober wrote no clock line after the run, so nothing says what it dropped\", group: empty };\n if (run.lost > 0) return { ...silent, void: `the prober dropped ${run.lost} records`, group: empty };\n const timeline = run.group?.timeline ?? [];\n const heal = run.heal ?? null;\n const lands = expected?.lands ?? \"new\";\n // a replica set and a cluster have no authority: their members and the client tell their stages. The\n // client of a cluster publishes through one node, and the leader of the queue can be on another one\n const cluster = cell.cluster !== undefined;\n // a Kafka group has no log lines in its record: the client and the whole partition tell its run\n const kafka = cell.kafka !== undefined;\n const replica = cell.replicaSet !== undefined || cluster || kafka;\n const stall = prediction.detects === false && prediction.recovers !== undefined;\n const stages = kafka ? {} : cluster ? clusterStagesOf(run, t0, run.fault.t1) : replica ? replicaSetStagesOf(run, t0, run.fault.t1, lands) : stagesOf(timeline, t0);\n // the first write that a primary accepted after the fault: on a new primary, or on the same one\n // after the lift. In a replica set, it is the first write sent after the commit of the fault\n // that a primary accepts: a partial cut leaves the old primary its writes\n const after = lands === \"same\" && heal !== null && (!replica || stall) ? heal.t0 : t0;\n const sentAt = new Map<number, number>();\n for (const event of events) if (event.ev === \"sent\") sentAt.set(Number(event[\"n\"]), event.t);\n const accepted = events.find((event) => {\n if (event.ev !== \"ack\" || event.t <= after) return false;\n if (replica && (sentAt.get(Number(event[\"n\"])) ?? -Infinity) <= run.fault!.t1) return false;\n const member = memberAt(run, event[\"at\"]);\n return member !== null && (lands === \"new\" && !cluster ? member !== primary : true);\n });\n const to = accepted === undefined ? null : memberAt(run, accepted[\"at\"]);\n // the first write of a replica set is the outcome itself: a stall's first write is the write into it\n if (replica) {\n delete stages[\"first-write\"];\n if (accepted !== undefined) stages[\"first-write\"] = between(t0, accepted.t);\n }\n const group: GroupMeasured = {\n from: primary,\n to,\n stages,\n writes: writesOf(run, t0, cluster ? \"\" : primary),\n errors: errorsOf(events, t0),\n ...(cell.calibrates === \"sentinels\" ? { lags: lagsOf(run, kernel) } : {}),\n ...(cell.drill === undefined ? {} : { recovery: recoveryOf(cell.drill, run, t0) }),\n };\n let voided: string | null = null;\n const tilt = timeline.find((line) => line.ev === \"sentinel\" && line.event === \"+tilt\" && line.t >= t0);\n if (tilt !== undefined) voided = `a Sentinel entered TILT ${between(t0, tilt.t).value} s after the fault: the host delayed it, not its timers`;\n const split = timeline.find((line) => line.ev === \"sentinel\" && line.event === \"-failover-abort-not-elected\" && line.t >= t0);\n const elected = timeline.find((line) => line.ev === \"sentinel\" && line.event === \"+elected-leader\" && line.t >= t0);\n if (voided === null && split !== undefined && (elected === undefined || elected.t > split.t))\n voided = \"the election split its votes and runs again after 2 × failover-timeout, which the band does not bound\";\n // a Sentinel starts a failover in the tick of its +odown, unless an attempt of its own came less\n // than 2 × failover-timeout before: then the run measured an earlier run, not its own fault\n const odown = stages[\"+odown\"];\n if (voided === null && odown !== undefined && stages[\"+try-failover\"] === undefined)\n voided = \"no Sentinel started a failover after +odown: each was in the hold-off of 2 × failover-timeout after an earlier attempt\";\n // a hold lifts at its instant in the VM: a band assumes that instant, and a lift later than the\n // noise moved each stage after it\n if (voided === null && cell.hold !== undefined && (prediction.detects !== null || kafka)) {\n if (heal === null) voided = \"the fault never lifted\";\n else {\n const late = (heal.t0 - t0) / 1e9 - valueIn(cell.hold, \"s\");\n if (late > valueIn(INJECT, \"s\"))\n voided = `the lift came ${Math.round(late * 1e4) / 10} ms after its hold: the injector was late, not the group`;\n }\n }\n // a band holds for the round trips that it assumes: the first one of the client's socket to the old\n // primary, or to the first node of a cluster\n const firstAddress = cluster\n ? String(events.find((event) => event.ev === \"connected\")?.[\"at\"] ?? \"\")\n : `${run.group?.members[primary]?.ip}:${(cell.group ?? cell.replicaSet ?? cell.kafka)?.port}`;\n const assumed = prediction.detects === null ? undefined : prediction.rtt;\n const first = kernel.find(\n (record) =>\n record.netns === run.netns &&\n record.dst === firstAddress &&\n record.tcp?.srtt !== undefined,\n );\n const rtt = first?.tcp?.srtt === undefined ? null : valueIn(first.tcp.srtt, \"us\") / 1000;\n if (voided === null && assumed !== undefined && rtt !== null && rtt > valueIn(assumed.high, \"ms\"))\n voided = `rtt-over-assumption: its first round trip was ${rtt} ms, above the ${valueIn(assumed.high, \"ms\")} ms that the prediction assumes`;\n if (voided === null && prediction.detects === true && prediction.from === \"fault\" && (run.fault.t1 - run.fault.t0) / 1e6 > valueIn(INJECT, \"ms\"))\n voided = `the commit of the fault took ${Math.round((run.fault.t1 - run.fault.t0) / 1e5) / 10} ms, longer than the noise of the pipeline: its start is not known`;\n\n // the reference: the fault, or for a stall the first write into it\n let reference = t0;\n if (prediction.detects === false && prediction.recovers !== undefined) {\n const into = events.find((event) => event.ev === \"sent\" && event.t > run.fault!.t1);\n if (into === undefined || (heal !== null && into.t > heal.t0)) {\n voided ??= \"the write in flight went out before the fault held\";\n } else {\n reference = into.t;\n // the stall must end where the prediction assumed: after the firing before, and before its own\n const { heal: bounds } = prediction.recovers;\n if (heal === null) voided ??= \"the stall never ended\";\n else if (\n valueIn(between(reference, heal.t0), \"s\") <= valueIn(bounds.low, \"s\") ||\n valueIn(between(reference, heal.t1), \"s\") >= valueIn(bounds.high, \"s\")\n )\n voided ??= `the stall ended ${between(reference, heal.t0).value}–${between(reference, heal.t1).value} s after the write, outside the ${bounds.low.value}–${bounds.high.value} s its prediction assumed`;\n }\n }\n\n // findings: a failover where none should be, a client on the wrong primary, an error out of its band\n const findings: string[] = [];\n // a failover: a Sentinel switches the primary, or another member of a replica set wins an election\n const switched = replica ? stages[\"elected\"] : stages[\"+switch-master\"];\n if (expected?.failover === false && switched !== undefined)\n findings.push(`the group failed over ${switched.value} s after the fault, where it should not`);\n // a Kafka run has no line of an election: the leader after the run tells if the leader changed\n const leaderAfter = run.group?.after ?? null;\n if (kafka && expected !== undefined && leaderAfter !== null && expected.failover !== (leaderAfter !== primary))\n findings.push(expected.failover ? `the leader stayed on ${primary}, where it should change` : `the leader moved to ${leaderAfter}, where it should stay on ${primary}`);\n for (const stage of expected?.quiet ?? []) {\n const at = stages[stage];\n if (at !== undefined) findings.push(`${stage} came ${at.value} s after the fault, where it should not`);\n }\n if (accepted !== undefined && lands === \"same\" && !cluster && !kafka && to !== primary)\n findings.push(`the client wrote to ${to ?? String(accepted[\"at\"])}, where it should stay on ${primary}`);\n for (const error of expected?.errors ?? []) {\n const met = group.errors.find((each) => each.name === error.name);\n const noise = valueIn(noiseOf(cell), \"s\");\n if (met === undefined) findings.push(`the client never met ${error.name}`);\n else if (met.first.value < valueIn(error.low, \"s\") - noise || met.first.value > valueIn(error.high, \"s\") + noise)\n findings.push(`the client met ${error.name} ${met.first.value} s after the fault, outside [${valueIn(error.low, \"s\")}, ${valueIn(error.high, \"s\")}] s`);\n }\n if (expected?.lost !== undefined) {\n const { low, high } = expected.lost;\n const lost = group.writes.lost;\n if (lost === null) findings.push(\"the group did not converge, thus the count of its lost writes is not known\");\n else if (lost.length < low || lost.length > high) findings.push(`the group lost ${lost.length} accepted writes, outside [${low}, ${high}]`);\n }\n if (expected?.duplicates !== undefined) {\n const { low, high } = expected.duplicates;\n const copies = group.writes.duplicates ?? null;\n if (copies === null) findings.push(\"the group did not converge, thus the count of its extra copies is not known\");\n // a read that found no write counts no copy: that zero says nothing\n else if (run.group?.holds?.length === 0) findings.push(\"the group holds no write, thus the count of its extra copies says nothing\");\n else if (copies.length < low || copies.length > high) findings.push(`the group holds ${copies.length} extra copies, outside [${low}, ${high}]`);\n }\n const { sets } = group.writes;\n for (const [name, band] of Object.entries(expected?.outcomes ?? {})) {\n const count = sets?.[name as keyof PairSets];\n if (count === undefined) findings.push(`the run has no count of ${name}`);\n else if (count < band.low || count > band.high) findings.push(`the count of ${name} is ${count}, outside [${band.low}, ${band.high}]`);\n }\n if (group.recovery !== undefined) findings.push(...recoveryFindings(group.recovery, group.writes));\n if (accepted === undefined) {\n if (prediction.detects !== null || kafka)\n findings.push(lands === \"new\" ? \"the client never wrote to a new primary in the window\" : \"the client never wrote again in the window\");\n return { ...silent, void: voided, finding: findings[0] ?? null, group };\n }\n // the kernel's time of the acceptance: the last segment with data from that primary at the\n // client's stamp or before it. The monitor and the pinger of a driver have their own sockets to\n // each member, thus only the sockets of the pool count\n const address = String(accepted[\"at\"]);\n const others = new Set(socketsOf(events).filter((socket) => socket.role !== \"pool\").map((socket) => socket.local));\n const segment = kernel\n .filter(\n (record) =>\n record.netns === run.netns &&\n record.ev === \"rx\" &&\n record.dst === address &&\n !others.has(String(record.src)) &&\n (record.seg?.len.value ?? 0) > 0 &&\n record.mono <= accepted.t &&\n record.mono > after,\n )\n .at(-1);\n const at = segment?.mono ?? accepted.t;\n return {\n outcome: { kind: \"answered\" },\n elapsed: between(reference, at),\n socket: between(reference, accepted.t),\n noticed: segment === undefined ? null : between(segment.mono, accepted.t),\n void: voided,\n finding: findings[0] ?? null,\n group,\n };\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { quantity, valueIn } from \"@mark1russell7/quantity\";\nimport type { CallReading, ReconnectReading } from \"./application.ts\";\nimport type { RunEstimate, RunLoad } from \"./load.ts\";\nimport {\n callOf,\n closeOrExit,\n dropFinding,\n dropOf,\n exitOf,\n firstUnanswered,\n leftAfter,\n jitterOfLines,\n pingsOf,\n programLines,\n reconnectFinding,\n reconnectOf,\n} from \"./application.ts\";\nimport type { Cell, Jitter, KernelRecord, ProbeEvent, Reference, Run } from \"./cell.ts\";\nimport { requestFirst } from \"./cell.ts\";\nimport type { DriverStepTime } from \"./driver.ts\";\nimport { countFinding, measureDriver, proxiedClose } from \"./driver.ts\";\nimport type { ConntrackReading } from \"./conntrack.ts\";\nimport { measureConntrack } from \"./conntrack.ts\";\nimport { estimateOf, loadOf, streamsLoadOf } from \"./load.ts\";\nimport type { PauseReading } from \"./pause.ts\";\nimport { measurePause } from \"./pause.ts\";\nimport type { GroupMeasured } from \"./timeline.ts\";\nimport type { PortsReading } from \"./ports.ts\";\nimport { measurePorts } from \"./ports.ts\";\nimport type { QueueReading } from \"./queue.ts\";\nimport { measureQueue } from \"./queue.ts\";\nimport { measureGroup } from \"./timeline.ts\";\nimport type { Pairing } from \"./verdict.ts\";\nimport { INJECT, delayVoids, noiseOf, pairingOf, requestWords } from \"./verdict.ts\";\n\n/**\n * An outcome tells how the wait of a run ended. The socket failed with an errno, or it read the\n * end of the file. Or nothing came, or the reply came back after a stall. The observer can also\n * close the connection itself (`closed`), or its program can drop it on its own timer (`dropped`).\n */\nexport type Outcome =\n | { readonly kind: \"error\"; readonly errno: string }\n | { readonly kind: \"eof\" }\n | { readonly kind: \"silent\" }\n | { readonly kind: \"answered\" }\n | { readonly kind: \"closed\" }\n | { readonly kind: \"dropped\" };\n\n/**\n * A request reading is what the second request of an HTTP client met, from the lines of the\n * client. It holds the connection of its first try, a new try, and its outcome. `gap` is the time\n * from the end of the first reply to the send of the second request.\n */\nexport interface RequestReading {\n readonly connection: \"reused\" | \"new\";\n readonly retried: boolean;\n readonly error: string | null;\n readonly pending: boolean;\n readonly gap: Quantity | null;\n}\n\n/** A measurement is what one run measured, against the prediction of its cell. */\nexport interface Measured {\n readonly environment: number;\n readonly index: number;\n readonly outcome: Outcome;\n /**\n * This time is from the reference event of the prediction to the detection, both as the kernel\n * stamped them in the records of the prober. It is null when nothing detected the fault.\n */\n readonly elapsed: Quantity | null;\n /** This time is the same interval from the TCP_INFO samples of the client, the second vantage. */\n readonly socket: Quantity | null;\n /** This time is how long the client took to see the error after the kernel reported it. */\n readonly noticed: Quantity | null;\n /**\n * These are the steps of the kernel after the reference: each keepalive probe, or each firing of\n * the RTO timer. After a stall, they are each retransmission from the send, the loss probe first.\n */\n readonly steps: readonly Quantity[];\n /**\n * These are the reply times of a measurement-only cell. For each request after the first, a\n * sample is the time from its send to the first data after it.\n */\n readonly samples?: readonly Quantity[];\n /** This measure is the run of an open-loop cell against its schedule (`Run.schedule`), with its failed replies. Its times are in ms. */\n readonly load?: RunLoad;\n /** This estimate is the open loop that a closed-loop stream of the client of the harness hid (SYS-91). Its times are in ms. */\n readonly estimate?: RunEstimate;\n /** This count is the number of keepalive probes that the kernel sent. */\n readonly probes: number;\n /** This count is the number of segments that the kernel sent again. */\n readonly retransmissions: number;\n /** This count is the number of segments that the socket received after the request. */\n readonly acks: number;\n /** This count is the number of bytes that the client read after the request. */\n readonly bytes?: number;\n /**\n * This time is when a router of the topology forgot the flow of the client. It counts from the\n * last segment that the client received before the fault. It is null when no router forgot the flow.\n */\n readonly forgot?: Quantity | null;\n /**\n * This time is the first round trip of the socket of the observer. It is the smoothed round trip\n * in its first record, which is the sample of the handshake. It is null when no record has it.\n */\n readonly rtt?: Quantity | null;\n /** This record tells what reordering did in a run of a measurement-only cell, from the records of its two ends. */\n readonly reordering?: Reordering;\n /** These are the times of the proxy of a calibration cell, one for each request and its reply. */\n readonly crossings?: Crossings;\n /** This record is what a run of a group cell measured: the stages of its timeline, and what became of each write. */\n readonly group?: GroupMeasured;\n /** This record is what a run of a queue cell measured: the count of the queue, its counters, and each connection. */\n readonly queue?: QueueReading;\n /** This record is what a run of a port cell measured: the count of each search, and when each port came back. */\n readonly ports?: PortsReading;\n /** This record is what a run of a conntrack cell measured: the flows, the count, and when a slot came back. */\n readonly conntrack?: ConntrackReading;\n /** This record is what the second request of an HTTP client met, for a cell whose prediction says it. */\n readonly request?: RequestReading | null;\n /** This record is the time of each later band of a driver cell (`DriverBand.then`). */\n readonly driver?: { readonly steps: readonly DriverStepTime[] };\n /** This record is what the client did after the detection, for a prediction that says when it reconnects. */\n readonly reconnect?: ReconnectReading;\n /** This record is what the call in flight of a WebSocket client met. */\n readonly call?: CallReading;\n /**\n * This time is from the drop line of the program to the close of its socket by its own side: a\n * FIN or an abort. A prediction that says how the program drops (`drop`) gets it. It is null\n * when the socket did not close itself in the run. A prediction can say that the client process\n * ends with the run (`exits`). Then a close at that end is no close by the program, and `left` is null.\n */\n readonly left?: Quantity | null;\n /**\n * This time is from the drop line of the program to the end of the client process. A socket gets\n * it when it stayed open until that end. The kernel closed it then, not the program (`exits`).\n */\n readonly exited?: Quantity;\n /**\n * This record is the pairing window of the run: the jitter bound that it measured, and the\n * window that its pairings used (`pairingOf`). A run that has a jitter record gets it. Thus a\n * reader can check each pairing of the run again.\n */\n readonly pairing?: Pairing;\n /** This record is what a run of a paused consumer measured. */\n readonly pause?: PauseReading;\n /** This text is the reason that the run cannot count, or null. A void run is not a pass and not a finding. */\n readonly void: string | null;\n /** This text tells what in the run disagrees with the prediction, other than its timing, or null. */\n readonly finding: string | null;\n}\n\n/**\n * A reordering record is what reordering, duplicates and losses did to the data of a run. The\n * receiver is the client, and the sender is the socket of its peer.\n * - `outOfOrder` counts the arrivals at the client beyond a hole, and `duplicates` counts the\n * arrivals whose data the client had. The prober reads the two from each arrival, against `rcv_nxt`.\n * - An arrival can hold more than one segment. The kernel joins the segments that wait in the\n * backlog of a socket while its owner holds it.\n * - `ooo` is the count of the kernel of the client in segments (`rcv_ooopack`).\n * - `sacked` and `lost` are the most segments that the sender held as SACKed and as lost.\n * - `dsacks` is the DSACK blocks that the sender received, and `fast` its fast retransmissions.\n * - `degree` is the highest reordering degree of the sender (`tp->reordering`), and `seen` the\n * reorderings that it detected (`reord_seen`).\n *\n * The counts of the kernel are null for a record of the prober before version 0.2.\n */\nexport interface Reordering {\n readonly outOfOrder: number;\n readonly duplicates: number;\n readonly ooo: number | null;\n readonly sacked: number | null;\n readonly lost: number | null;\n readonly dsacks: number | null;\n readonly fast: number;\n readonly degree: number | null;\n readonly seen: number | null;\n}\n\n/**\n * A crossings record is the time of a proxy for each request (`up`) and for each reply (`down`).\n * The time of a request starts at its arrival on the socket toward the client. It stops at the\n * write on the socket toward the target. The time of a reply goes the other way. A write is a\n * `tx` record of the prober.\n */\nexport interface Crossings {\n readonly hop: string;\n readonly up: readonly Quantity[];\n readonly down: readonly Quantity[];\n}\n\n/** These are the errno numbers that the kernel reports to a socket, by the names that predictions use. */\nconst ERRNO: Readonly<Record<number, string>> = {\n 32: \"EPIPE\",\n 101: \"ENETUNREACH\",\n 103: \"ECONNABORTED\",\n 104: \"ECONNRESET\",\n 110: \"ETIMEDOUT\",\n 111: \"ECONNREFUSED\",\n 113: \"EHOSTUNREACH\",\n};\n\n/** This function gives the interval between two instants on the one clock, in seconds to the microsecond. */\nconst between = (from: number, to: number): Quantity =>\n quantity(Math.round((to - from) / 1e3) / 1e6, \"s\");\n\n/** These functions give the states of a state record: before the change, and after it. TCP_ESTABLISHED is 1, TCP_CLOSE_WAIT 8. */\nconst oldState = (record: KernelRecord): number | undefined => (record as { readonly old?: number }).old;\nconst newState = (record: KernelRecord): number | undefined => (record as { readonly new?: number }).new;\n\nconst count = (event: ProbeEvent | undefined, field: string): number =>\n event === undefined ? 0 : Number(event[field] ?? 0);\n\n/** This function gives the view of the client on the same interval: TCP_INFO, with a sample each 2 ms. */\nconst socketVantage = (\n cell: Cell,\n events: readonly ProbeEvent[],\n ready: ProbeEvent,\n request: ProbeEvent,\n): Quantity | null => {\n const { from } = cell.prediction.detects === true ? cell.prediction : { from: undefined };\n if (from === undefined || from === \"peer-closed\" || from === \"fault\" || from === \"ping-sent\" || from === \"first-sent\" || from === \"last-data\" || from === \"last-reply\") return null;\n const ended = events.find((event) => event.ev === \"error\" || event.ev === \"eof\");\n const reference =\n from === \"last-received\"\n ? ready\n : from === \"request-sent\"\n ? request\n : events.find(\n (event) =>\n event.ev === \"kernel\" && event.t >= request.t && count(event, \"retransmits\") > 0,\n );\n return ended === undefined || reference === undefined ? null : between(reference.t, ended.t);\n};\n\n/** A socket place is a socket of a run: its namespace and its cookie. */\nexport interface SocketPlace {\n readonly netns: number;\n readonly cookie: number;\n}\n\nconst ipOf = (address: string): string => address.split(\":\")[0]!;\n\n/**\n * This function finds the socket that became ESTABLISHED in a run, in a namespace, whose peer\n * matches. In a topology, an address of a hop serves each run, thus only the socket that the\n * run opened is the socket of the run.\n */\nconst opened = (\n run: Run,\n netns: number,\n peer: (dst: string) => boolean,\n): SocketPlace | undefined => {\n const record = run.kernel.find(\n (each) =>\n each.netns === netns &&\n each.ev === \"state\" &&\n newState(each) === 1 &&\n each.dst !== undefined &&\n peer(each.dst),\n );\n return record?.cookie === undefined ? undefined : { netns, cookie: record.cookie };\n};\n\n/**\n * This function finds the socket of a hop that carries the request of a run toward the target. It is\n * the first socket of the hop that sends data to the target after the send of the request. A pooler can\n * reuse a server that it opened before the run, in the warm-up of the environment. Then the first\n * socket that it opens in the run is another one (run 39160356281).\n */\nconst carried = (run: Run, netns: number, target: string): SocketPlace | undefined => {\n const request = run.events.filter((event) => event.ev === \"sent\")[1];\n if (request === undefined) return undefined;\n const record = run.kernel.find(\n (each) => each.netns === netns && each.ev === \"tx\" && each.dst === target && (each.seg?.len.value ?? 0) > 0 && each.mono >= request.t,\n );\n return record?.cookie === undefined ? undefined : { netns, cookie: record.cookie };\n};\n\n/** This function finds the socket of the target for the connection of a run. In a topology, its peer is the last hop. */\nconst targetSocket = (run: Run, local: unknown): SocketPlace | undefined => {\n if (run.topology === undefined) {\n const cookie = run.kernel.find(\n (record) => record.netns === run.targetNetns && record.dst === local,\n )?.cookie;\n return cookie === undefined ? undefined : { netns: run.targetNetns, cookie };\n }\n const peer = run.topology.targetPeer;\n return opened(run, run.targetNetns, (dst) => ipOf(dst) === peer);\n};\n\n/**\n * This function finds the socket of the observer of a cell in a run:\n * - the client socket, by the address that it connected from, in its namespace.\n * - the socket of the target for the same connection, in its namespace.\n * - a socket of a proxy of the topology, toward the client or toward the target. Toward the target,\n * it is the socket that carries the request, else the first socket that the run opens.\n */\nexport const socketOf = (cell: Cell, run: Run): SocketPlace | undefined => {\n const local = run.events.find((event) => event.ev === \"connected\")?.[\"local\"];\n const observer = cell.observer ?? \"client\";\n if (observer === \"client\") {\n const cookie = run.kernel.find((record) => record.netns === run.netns && record.src === local)?.cookie;\n return cookie === undefined ? undefined : { netns: run.netns, cookie };\n }\n if (observer === \"server\") return targetSocket(run, local);\n const hop = run.topology?.hops[observer.hop];\n if (hop === undefined) return undefined;\n return observer.toward === \"client\"\n ? opened(run, hop.netns, (dst) => ipOf(dst) === hop.client)\n : (carried(run, hop.netns, hop.target) ?? opened(run, hop.netns, (dst) => dst === hop.target));\n};\n\n/**\n * This function finds the socket of the peer of the observer: its close is the reference of a FIN.\n * In a direct pair, it is the other end of the connection. In a topology, it is the socket of the\n * target, for the client.\n */\nconst peerOf = (cell: Cell, run: Run): SocketPlace | undefined => {\n const local = run.events.find((event) => event.ev === \"connected\")?.[\"local\"];\n const server = cell.observer === \"server\";\n if (run.topology !== undefined) return server ? undefined : targetSocket(run, local);\n const netns = server ? run.netns : run.targetNetns;\n const cookie = run.kernel.find(\n (record) => record.netns === netns && (server ? record.src : record.dst) === local,\n )?.cookie;\n return cookie === undefined ? undefined : { netns, cookie };\n};\n\n/** This function tells if sequence number a is after b, in the 32-bit space of TCP (`after` in include/net/tcp.h). */\nconst after32 = (a: number, b: number): boolean => ((a - b) | 0) > 0;\n\n/** This function gives the largest value of a count of the kernel in records, or null when no record has it. */\nconst most = (records: readonly KernelRecord[], count: (record: KernelRecord) => number | undefined): number | null =>\n records.reduce<number | null>((top, record) => {\n const value = count(record);\n return value === undefined ? top : Math.max(top ?? 0, value);\n }, null);\n\n/** This function gives what reordering did in a run, from the records of the receiver and of the sender. */\nexport const reorderingOf = (\n receiver: readonly KernelRecord[],\n sender: readonly KernelRecord[],\n): Reordering => {\n const arrivals = receiver.filter(\n (record) => record.ev === \"rx\" && (record.seg?.len.value ?? 0) > 0 && record.tcp?.rcv_nxt !== undefined,\n );\n const outOfOrder = arrivals.filter((record) => after32(record.seg!.seq, record.tcp!.rcv_nxt!)).length;\n const duplicates = arrivals.filter(\n (record) => !after32(record.seg!.seq + record.seg!.len.value, record.tcp!.rcv_nxt!),\n ).length;\n return {\n outOfOrder,\n duplicates,\n ooo: most(receiver, (record) => record.tcp?.rcv_ooopack),\n sacked: most(sender, (record) => record.tcp?.sacked),\n lost: most(sender, (record) => record.tcp?.lost),\n dsacks: most(sender, (record) => record.tcp?.dsack_dups),\n fast: sender.filter((record) => record.ev === \"retrans\" && record.why === \"fast\").length,\n degree: most(sender, (record) => record.tcp?.reordering),\n seen: most(sender, (record) => record.tcp?.reord_seen),\n };\n};\n\n/**\n * This function gives the times of a proxy in a run, for each request after the first. The time\n * of a request starts at its arrival on the socket of the proxy toward the client. It stops at the\n * next write on the socket toward the target. The time of its reply starts at its arrival on the\n * socket toward the target, and it stops at the next write toward the client. A request without\n * each record gives no time.\n */\nexport const crossingsOf = (\n run: Run,\n hop: string,\n toClient: SocketPlace | undefined,\n toTarget: SocketPlace | undefined,\n): Crossings => {\n const up: Quantity[] = [];\n const down: Quantity[] = [];\n if (toClient === undefined || toTarget === undefined) return { hop, up, down };\n const of = (place: SocketPlace) =>\n run.kernel.filter((record) => record.netns === place.netns && record.cookie === place.cookie);\n const near = of(toClient);\n const far = of(toTarget);\n const arrival = (records: readonly KernelRecord[], from: number, to: number) =>\n records.find((record) => record.ev === \"rx\" && (record.seg?.len.value ?? 0) > 0 && record.mono > from && record.mono < to);\n const write = (records: readonly KernelRecord[], from: number, to: number) =>\n records.find((record) => record.ev === \"tx\" && record.mono >= from && record.mono < to);\n const sends = run.events.filter((event) => event.ev === \"sent\").slice(1);\n sends.forEach((send, n) => {\n const next = sends[n + 1]?.t ?? Infinity;\n const request = arrival(near, send.t, next);\n const relayed = request === undefined ? undefined : write(far, request.mono, next);\n if (request === undefined || relayed === undefined) return;\n up.push(between(request.mono, relayed.mono));\n const reply = arrival(far, relayed.mono, next);\n const answered = reply === undefined ? undefined : write(near, reply.mono, next);\n if (reply !== undefined && answered !== undefined) down.push(between(reply.mono, answered.mono));\n });\n return { hop, up, down };\n};\n\n/**\n * This function reads one run against its cell, from the records of the kernel first.\n * - The socket of the run is the socket of its observer. It is the socket that the client connected\n * from, in its namespace, or the socket of the target or of a proxy for that connection.\n * - The fault must hold before the event that it must meet. That is before the request goes into\n * it, and before the first keepalive probe. A live peer answers that probe, and the answer\n * starts the idle time again. A run where the fault was late is void. A run whose records the\n * prober lost is also void.\n * - For an HTTP client, it also reads what the second request met (`requestOf`). An outcome other\n * than the one that the prediction gives is a finding.\n */\nexport const measure = (cell: Cell, run: Run): Measured => {\n const socketRead = measureSocket(cell, run);\n // a run with a jitter record says the window of its pairings. A record from before SYS-25 has none\n const read: Measured = run.jitter === undefined ? socketRead : { ...socketRead, pairing: pairingOf(cell, run) };\n const expected = cell.prediction.request;\n if (cell.probe.http === undefined && expected === undefined) return read;\n const request = requestOf(run.events);\n if (expected === undefined || read.void !== null) return { ...read, request };\n const differs = requestFinding(expected, request);\n const finding = read.finding === null ? differs : differs === null ? read.finding : `${read.finding}. ${differs}`;\n return { ...read, request, finding };\n};\n\n/**\n * This function measures the jitter of the program of the observer in a run, from its records\n * (`Jitter`). The acts count up to the start of the fault, or up to the reply of the client when\n * the fault has no stamp. A run with no lines of a program, or no socket of the observer, has no act.\n */\nexport const jitterOf = (cell: Cell, run: Run): Jitter => {\n const lines = programLines(cell, run);\n const ready = run.events.find((event) => event.ev === \"ready\");\n const place = lines.length === 0 || ready === undefined ? undefined : socketOf(cell, run);\n if (ready === undefined || place === undefined) return { acts: 0, bound: null };\n const socket = run.kernel.filter((record) => record.netns === place.netns && record.cookie === place.cookie);\n const local = run.events.find((event) => event.ev === \"connected\")?.[\"local\"];\n // a line of a server names its connection by its peer: the peer of the socket of the server\n const named = cell.observer === \"server\" ? (socket.find((record) => record.dst !== undefined)?.dst ?? local) : local;\n return jitterOfLines(lines, socket, named, run.fault?.t0 ?? ready.t);\n};\n\n/** This function tells how a request reading differs from its prediction, or gives null. */\nconst requestFinding = (expected: NonNullable<Cell[\"prediction\"][\"request\"]>, read: RequestReading | null): string | null => {\n if (read === null) return `the second request never went out, where it should meet: ${requestWords(expected)}`;\n const same =\n read.connection === expected.connection &&\n read.retried === expected.retried &&\n read.error === expected.error &&\n read.pending === (expected.pending === true);\n return same ? null : `the second request met: ${requestWords(read)}, not ${requestWords(expected)}`;\n};\n\n/**\n * This function reads the second request of an HTTP client from its lines. Its first try is its\n * first `request` line, and each `retry` line is a new try. Its end is its `error` line, or its\n * `replied` line. A request with neither is pending. It gives null when the client wrote no try.\n *\n * A new try that gets no connection writes no `retry` line. Its dial writes a `dial-error` line.\n * Thus a `dial-error` line after the first try and before the end is also a new try.\n */\nexport const requestOf = (events: readonly ProbeEvent[]): RequestReading | null => {\n const of = (event: ProbeEvent) => Number(event[\"i\"]) === 2;\n const tries = events.filter((event) => (event.ev === \"request\" || event.ev === \"retry\") && of(event));\n const first = tries[0];\n if (first === undefined) return null;\n const failed = events.find((event) => event.ev === \"error\" && of(event));\n const replied = events.some((event) => event.ev === \"replied\" && of(event));\n const ready = events.find((event) => event.ev === \"ready\");\n const sent = events.find((event) => event.ev === \"sent\" && of(event));\n const end = failed ?? events.find((event) => event.ev === \"done\" && of(event));\n const dialed = events.some(\n (event) => event.ev === \"dial-error\" && event.t > first.t && (end === undefined || event.t <= end.t),\n );\n return {\n connection: first[\"reused\"] === true ? \"reused\" : \"new\",\n retried: dialed || tries.some((each) => each.ev === \"retry\"),\n error: failed === undefined ? null : String(failed[\"errno\"]),\n pending: failed === undefined && !replied,\n gap: ready === undefined || sent === undefined ? null : between(ready.t, sent.t),\n };\n};\n\n/** This function reads the socket of one run against its cell, as `measure` does without the second request of an HTTP client. */\nconst measureSocket = (cell: Cell, run: Run): Measured => {\n if (run.missing !== undefined)\n return {\n environment: run.environment,\n index: run.index,\n outcome: { kind: \"answered\" },\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n probes: 0,\n retransmissions: 0,\n acks: 0,\n void: `the environment cannot do this cell: ${run.missing}`,\n finding: null,\n };\n if (cell.prediction.detects === null && cell.prediction.pause !== undefined) return measurePause(run, cell.prediction.pause);\n if (cell.group !== undefined || cell.replicaSet !== undefined || cell.cluster !== undefined || cell.pair !== undefined || cell.kafka !== undefined) {\n const read = measureGroup(cell, run);\n return {\n environment: run.environment,\n index: run.index,\n outcome: read.outcome,\n elapsed: read.elapsed,\n socket: read.socket,\n noticed: read.noticed,\n steps: [],\n probes: 0,\n retransmissions: run.kernel.filter((record) => record.netns === run.netns && record.ev === \"retrans\").length,\n acks: read.group.writes.acked,\n void: read.void,\n finding: read.finding,\n group: read.group,\n };\n }\n if (cell.prediction.detects === null && cell.prediction.queue !== undefined)\n return measureQueue(run, cell.prediction.queue);\n if (cell.prediction.detects === null && cell.prediction.ports !== undefined)\n return measurePorts(run, cell.prediction.ports);\n if (cell.prediction.detects === null && cell.prediction.conntrack !== undefined)\n return measureConntrack(run, cell.prediction.conntrack);\n // a driver with more than one socket: its bands name their socket and their line\n if (cell.prediction.detects !== null && cell.prediction.driver !== undefined) return measureDriver(cell, run);\n const { events, kernel } = run;\n const ready = events.find((event) => event.ev === \"ready\");\n const local = events.find((event) => event.ev === \"connected\")?.[\"local\"];\n // a client in a gap sends its second request by itself, and its idle connection counts from its first reply\n const inflight = cell.probe.mode !== \"idle\" && cell.probe.mode !== \"gap\";\n const request = inflight ? events.filter((event) => event.ev === \"sent\")[1] : ready;\n const server = cell.observer === \"server\";\n const place = socketOf(cell, run);\n const netns = place?.netns;\n const cookie = place?.cookie;\n const socket = kernel.filter((record) => record.netns === netns && record.cookie === cookie);\n // the socket of the peer for the same connection: a FIN counts from the change of state that its close makes\n const peerPlace = peerOf(cell, run);\n const peerNetns = peerPlace?.netns;\n const peerCookie = peerPlace?.cookie;\n // the bytes that the client read after its request, and the first and last time that data came\n const after = request === undefined ? [] : events.filter((event) => event.ev === \"data\" && event.t > request.t);\n const bytes = after.reduce((sum, event) => sum + Number(event[\"n\"] ?? 0), 0);\n // the end of the flow in a router of the topology: its DESTROY line, by the address of the client\n const forgotten = (run.middlebox ?? []).find(\n (line) =>\n line.ev === \"ct\" &&\n line[\"type\"] === \"DESTROY\" &&\n typeof line[\"orig\"] === \"string\" &&\n (line[\"orig\"] as string).startsWith(`${String(local)}>`),\n );\n const keepalives = socket.filter(\n (record) => record.ev === \"probe\" && record.what === \"keepalive\",\n );\n const retransmitted = socket.filter((record) => record.ev === \"retrans\");\n /**\n * This function examines the timer that drives the measurement: keepalive or retransmit. It\n * finds the first firing in an interval that was two jiffies or more behind its wheel slot. The\n * wheel does a slot in the tick when it is due, thus such a delay comes from the CPU: the host\n * stopped a vCPU. The prediction is about the timing of the kernel, and that firing measured\n * the timing of the host. One jiffy is a tick that occurred while the wheel worked, and δ_abs\n * includes it. The function ignores the other timer: the retransmit timer fires one time, idle,\n * after a reply, and it does not move a keepalive.\n */\n const delayed = (from: number, to: number, timer: \"keepalive\" | \"retransmit\"): string | null => {\n const firings = socket.filter(\n (record) =>\n record.ev === \"timer\" && record.what === timer && record.mono >= from && record.mono <= to,\n );\n const late = firings.find((record) => delayVoids(record.behind?.value ?? 0, run.hz, noiseOf(cell)));\n if (late !== undefined)\n return `its ${timer} timer ran ${late.behind!.value} jiffies behind its wheel slot: the VM delayed it, not the kernel`;\n // a keepalive timer that finds its socket held by its owner sends nothing, and it tries again\n // HZ/20 later (tcp_keepalive_timer). The retransmit timer only gives its work to the release\n // by the owner, some microseconds later\n const held = firings.find((record) => timer === \"keepalive\" && record.owned === true);\n return held === undefined\n ? null\n : \"its keepalive timer found the socket held by its owner and put itself off by HZ/20: the run measured the owner, not the timer\";\n };\n const acks =\n request === undefined\n ? 0\n : socket.filter((record) => record.ev === \"rx\" && record.mono > request.t).length;\n // the first round trip of the observer: the smoothed round trip in its first record, the sample of the handshake\n const srtt = socket.find((record) => record.tcp?.srtt !== undefined)?.tcp?.srtt;\n const rtt = srtt === undefined ? null : quantity(valueIn(srtt, \"us\") / 1000, \"ms\");\n const base = {\n environment: run.environment,\n index: run.index,\n probes: keepalives.length,\n retransmissions: retransmitted.length,\n acks,\n rtt,\n };\n const nothing = {\n outcome: { kind: \"silent\" } as const,\n elapsed: null,\n socket: null,\n noticed: null,\n steps: [],\n finding: null,\n };\n\n if (ready === undefined) return { ...base, ...nothing, void: \"the client never had its reply\" };\n if (request === undefined)\n return { ...base, ...nothing, void: \"the request was never sent into the fault\" };\n if (run.lost === null)\n return {\n ...base,\n ...nothing,\n void: \"the prober wrote no clock line after the run, so nothing says what it dropped\",\n };\n if (run.lost > 0) return { ...base, ...nothing, void: `the prober dropped ${run.lost} records` };\n if (cookie === undefined)\n return { ...base, ...nothing, void: \"the prober saw nothing of this connection\" };\n let voided: string | null = null;\n if (run.fault !== null) {\n // the request of a client must go into the fault. The request of a cell on the server side must\n // reach the server first, and its reply must not reach the client before the fault holds. An\n // mtu-blackhole drops only the long reply, thus its request goes after the fault, as a client's does.\n // An event at a hop that comes while the request is in flight comes after the request too\n const replyFirst = (server && inflight && cell.fault !== \"mtu-blackhole\") || requestFirst(cell);\n const replied = events.some(\n (event) => event.ev === \"data\" && event.t > request.t && event.t < run.fault!.t1,\n );\n if (inflight && !replyFirst && run.fault.t1 > request.t)\n voided = \"the request went out before the fault held\";\n else if (replyFirst && run.fault.t1 < request.t)\n voided = \"the request went out into the fault, so the server never had it\";\n else if (replyFirst && replied)\n voided = \"the server's reply arrived before the fault held\";\n else if (keepalives[0] !== undefined && keepalives[0].mono < run.fault.t1)\n voided = \"a keepalive probe went out before the fault held\";\n }\n // a band holds for the first round trips that its prediction assumes. Above them, the run measured another path\n const assumed = cell.prediction.detects === null ? undefined : cell.prediction.rtt;\n if (voided === null && assumed !== undefined && rtt !== null && valueIn(rtt, \"ms\") > valueIn(assumed.high, \"ms\"))\n voided = `rtt-over-assumption: its first round trip was ${rtt.value} ms, above the ${valueIn(assumed.high, \"ms\")} ms that the prediction assumes`;\n\n // the detection as the kernel reported it to the owner of the socket, and as the client saw it.\n // The process of a server or of a proxy tells nothing that the harness reads, thus its kernel tells all\n const remote = cell.observer !== undefined && cell.observer !== \"client\";\n // the run stops the client at its end: what the own close of the client draws after its done line is\n // not a detection. A broker with linger 0, as RabbitMQ, resets each connection that its client closes\n const stop = events.find((event) => event.ev === \"done\")?.t ?? Number.POSITIVE_INFINITY;\n const anError = socket.find((record) => record.ev === \"error\" && (record.err ?? 0) !== 0 && record.mono < stop);\n const seen = remote\n ? undefined\n : events.find((event) => (event.ev === \"error\" || event.ev === \"eof\") && event.t < stop);\n // an end of file without an error is the change of state that the FIN of the peer makes, from\n // ESTABLISHED to CLOSE_WAIT, as the kernel stamps it\n const closeWait = socket.find((record) => record.ev === \"state\" && newState(record) === 8 && record.mono < stop);\n // a close of the observer itself, for a prediction that says it: from ESTABLISHED to FIN_WAIT1,\n // the FIN that its pool sends when it closes an idle connection\n const own =\n (cell.prediction.detects === true && cell.prediction.errno === \"CLOSED\") ||\n (cell.prediction.detects === null && cell.prediction.ends === \"own-close\")\n ? socket.find((record) => record.ev === \"state\" && oldState(record) === 1 && newState(record) === 4 && record.mono < stop)\n : undefined;\n // an error after that own close is what the close draws, not a detection. The run lifts its fault\n // after the outcome: a frozen broker then thaws, sees the FIN, and resets the socket (linger 0)\n const reported = anError !== undefined && own !== undefined && own.mono < anError.mono ? undefined : anError;\n // a drop by the program of the observer on its own timer: its `drop` line, at the kernel's stamp\n // of its close frame or its close. It counts when it comes before each report of the kernel\n const lines = programLines(cell, run);\n // a line of the client names the connection by its local address, and a line of a server by its\n // peer. That peer is the peer of the socket of the server: the last hop of a topology\n const named = server ? (socket.find((record) => record.dst !== undefined)?.dst ?? local) : local;\n const kernelEnded = reported?.mono ?? closeWait?.mono ?? own?.mono ?? seen?.t;\n // the window of each pairing of a line with its act: δ_abs, or the jitter of the program in this run\n const paired = pairingOf(cell, run).delta;\n const first = dropOf(lines, socket, named, paired);\n const drop = first !== undefined && (kernelEnded === undefined || first.at <= kernelEnded) ? first : undefined;\n const dropped = drop !== undefined;\n const outcome: Outcome = dropped\n ? { kind: \"dropped\" }\n : reported !== undefined\n ? { kind: \"error\", errno: ERRNO[reported.err!] ?? `E${reported.err}` }\n : closeWait !== undefined || seen?.ev === \"eof\"\n ? { kind: \"eof\" }\n : own !== undefined\n ? { kind: \"closed\" }\n : seen !== undefined\n ? { kind: \"error\", errno: String(seen[\"errno\"]) }\n : { kind: \"silent\" };\n const ended = drop?.at ?? kernelEnded;\n const noticed =\n reported !== undefined && seen !== undefined && !dropped ? between(reported.mono, seen.t) : null;\n const { prediction } = cell;\n // the pings of a heartbeat of the program, at the kernel's stamps of their writes\n const pings = pingsOf(lines, socket, named, paired);\n // keepalive counts from the last segment received before the fault. The budget of the give-up\n // counts from the first retransmission of the RTO timer after the fault holds, not from the tail\n // loss probe before it. A retransmission before the fault is of an earlier segment, for example\n // the SYN of the connect of a proxy in a fresh environment. A reset counts from the send of the client. The kernel has no record of that send, thus the\n // stamp is the stamp of the client. A toxic counts from the start of its commit. A heartbeat\n // counts from the write of its first ping that got no answer before the detection\n const before = run.fault?.t1 ?? ready.t;\n const referenceAt = (from: Reference): number | undefined => {\n if (from === \"request-sent\") return request.t;\n if (from === \"fault\") return run.fault?.t0;\n if (from === \"client-start\") return (events.find((event) => event.ev === \"connecting\") ?? events[0])?.t;\n if (from === \"ping-sent\") return firstUnanswered(pings, socket, ended)?.at;\n const record: KernelRecord | undefined =\n from === \"last-received\"\n ? socket.filter((each) => each.ev === \"rx\" && each.mono <= before).at(-1)\n : from === \"last-data\"\n ? // the receive check of a heartbeat counts bytes, not an ACK: the last segment with data before the end\n socket.filter((each) => each.ev === \"rx\" && (each.seg?.len.value ?? 0) > 0 && each.mono <= (ended ?? before)).at(-1)\n : from === \"last-reply\"\n ? // a retry counts from the refusal before it: the last segment with data before the end\n socket.filter((each) => each.ev === \"rx\" && (each.seg?.len.value ?? 0) > 0 && each.mono < (ended ?? Infinity)).at(-1)\n : from === \"first-retransmission\"\n ? retransmitted.find((each) => each.why === \"rto\" && each.mono > before)\n : from === \"first-sent\"\n ? socket.find((each) => each.ev === \"tx\" && each.mono > before && (each.seg?.len.value ?? 0) > 0)\n : from === \"syn-sent\"\n ? socket.find((each) => each.ev === \"state\" && newState(each) === 2)\n : from === \"peer-closed\"\n ? kernel.find(\n (each) =>\n each.netns === peerNetns &&\n each.cookie === peerCookie &&\n each.ev === \"state\" &&\n oldState(each) === 1,\n )\n : // a reference that this judge does not know does not come: its band is a finding\n undefined;\n // behind a proxy, a pooler keeps its connection to the target across its clients: the run can\n // reuse one that it did not open, and the close of the target closes each of them at once\n if (record === undefined && from === \"peer-closed\" && peerCookie === undefined) return proxiedClose(run);\n return record?.mono;\n };\n // in a topology, the bytes after the request and the instant that a router forgot the flow\n const lastRx =\n kernel\n .filter((each) => each.netns === run.netns && each.src === local && each.ev === \"rx\" && each.mono <= before)\n .at(-1)?.mono ?? ready.t;\n const chain =\n run.topology === undefined\n ? {}\n : { bytes, forgot: forgotten === undefined ? null : between(lastRx, forgotten.t) };\n\n // a measurement-only cell: each request of the run and the time to its reply, and the time from\n // its reference to the end of the connection, or to the last data\n if (prediction.detects === null) {\n // an open-loop client names the arrival of each line, and each time counts from its planned time\n // the client load has one schedule for each stream, and its measure is the pool of the streams\n const load =\n run.streams !== undefined\n ? (streamsLoadOf(events, run.streams)?.pool ?? null)\n : run.schedule === undefined\n ? undefined\n : loadOf(events, run.schedule);\n if (load === null) return { ...base, ...nothing, void: \"the client never started its schedule\" };\n const sends = load === undefined ? events.filter((event) => event.ev === \"sent\").slice(1) : [];\n // a reply ends at its last byte when the client says so (`replied`), and at its first data otherwise\n const answers = events.some((event) => event.ev === \"replied\") ? \"replied\" : \"data\";\n const requests = sends.map((send, n) => {\n const next = sends[n + 1]?.t ?? Infinity;\n return { send, reply: events.find((event) => event.ev === answers && event.t > send.t && event.t < next) };\n });\n const samples = requests.flatMap(({ send, reply }) => (reply === undefined ? [] : [between(send.t, reply.t)]));\n // a stream of the client of the harness waits its interval after each reply: the closed loop of SYS-91\n const estimate =\n cell.probe.mode === \"stream\" && cell.probe.driver === undefined && cell.probe.interval !== undefined\n ? estimateOf(\n requests.map(({ send, reply }) => ({ sent: send.t, done: reply?.t ?? null })),\n events.reduce((latest, event) => Math.max(latest, event.t), 0),\n valueIn(cell.probe.interval, \"ms\"),\n )\n : undefined;\n const from = prediction.from === undefined ? undefined : referenceAt(prediction.from);\n const until = ended ?? after.at(-1)?.t;\n // the data of the client comes from its peer: the receiver and the sender of each reply\n const peerRecords =\n peerCookie === undefined\n ? []\n : kernel.filter((record) => record.netns === peerNetns && record.cookie === peerCookie);\n const proxy = cell.calibrates === undefined ? undefined : run.topology?.hops[cell.calibrates];\n const crossings =\n cell.calibrates === undefined\n ? {}\n : {\n crossings: crossingsOf(\n run,\n cell.calibrates,\n proxy === undefined ? undefined : socketOf({ ...cell, observer: { hop: cell.calibrates, toward: \"client\" } }, run),\n proxy === undefined ? undefined : socketOf({ ...cell, observer: { hop: cell.calibrates, toward: \"target\" } }, run),\n ),\n };\n // the reconnect after the end of the connection, against the bands of its waits. The end has no band\n const reconnect =\n prediction.reconnects === undefined || ended === undefined ? undefined : reconnectOf(run, ended, cookie, drop?.line.t ?? ended);\n const late = reconnect === undefined || prediction.reconnects === undefined ? null : reconnectFinding(prediction.reconnects, reconnect, noiseOf(cell));\n // the exact counts of the lines of the target: a count reads no timer\n const counted = prediction.counts === undefined ? null : countFinding(prediction.counts, run.server ?? []);\n return {\n ...base,\n ...nothing,\n ...chain,\n ...(reconnect === undefined ? {} : { reconnect }),\n finding: late ?? counted,\n outcome: ended !== undefined ? outcome : { kind: \"answered\" },\n ...(from === undefined || until === undefined ? {} : { elapsed: between(from, until) }),\n noticed: prediction.from === undefined ? null : noticed,\n steps: retransmitted\n .filter((record) => record.mono > request.t)\n .map((record) => between(request.t, record.mono)),\n samples,\n ...(load === undefined ? {} : { load }),\n ...(estimate === undefined ? {} : { estimate }),\n reordering: reorderingOf(\n socket.filter((record) => record.mono > request.t),\n peerRecords.filter((record) => record.mono > request.t),\n ),\n ...crossings,\n void: voided,\n };\n }\n\n // a stall: nothing must detect it, and the connection must move again at the first\n // retransmission after it stops, timed from the send of the request, or of the first ping\n if (!prediction.detects && prediction.recovers !== undefined) {\n const { recovers } = prediction;\n // an idle client sends only the pings of its heartbeat: its stall counts from its first ping into it\n const start =\n cell.probe.mode === \"idle\"\n ? (lines.find((line) => line.ev === \"ping\" && line.t >= (run.fault?.t1 ?? 0)) ?? request)\n : request;\n const heal = run.heal ?? null;\n if (voided === null && heal === null) voided = \"the stall never ended\";\n else if (voided === null && heal !== null) {\n const from = between(start.t, heal.t0);\n const to = between(start.t, heal.t1);\n if (\n valueIn(from, \"s\") <= valueIn(recovers.heal.low, \"s\") ||\n valueIn(to, \"s\") >= valueIn(recovers.heal.high, \"s\")\n )\n voided = `the stall ended ${from.value}–${to.value} s after the send, outside the ${recovers.heal.low.value}–${recovers.heal.high.value} s its prediction assumed`;\n }\n const steps = retransmitted\n .filter((record) => record.mono > start.t)\n .map((record) => between(start.t, record.mono));\n if (ended !== undefined)\n return {\n ...base,\n ...nothing,\n outcome,\n steps,\n void: voided,\n finding: `detected after ${between(start.t, ended).value} s, where it should recover`,\n };\n // the first segment back after the stall stopped: the answer of the server to the\n // retransmission that got through, and the read of the reply by the client\n const answer =\n heal === null\n ? undefined\n : socket.find((record) => record.ev === \"rx\" && record.mono > heal.t0);\n if (answer === undefined)\n return {\n ...base,\n ...nothing,\n steps,\n void: voided,\n finding: \"it never moved again: nothing came back after the stall ended\",\n };\n const reply = events.find((event) => event.ev === \"data\" && event.t > start.t);\n voided ??= delayed(start.t, answer.mono, \"retransmit\");\n return {\n ...base,\n outcome: { kind: \"answered\" },\n elapsed: between(start.t, answer.mono),\n socket: reply === undefined ? null : between(start.t, reply.t),\n noticed: reply === undefined ? null : between(answer.mono, reply.t),\n steps,\n void: voided,\n finding: null,\n };\n }\n\n // a reply in a band: nothing must detect the fault, and the reply must come back in its time,\n // from the send of the request to the first segment that the socket receives after it\n if (!prediction.detects && prediction.replies !== undefined) {\n const window = valueIn(prediction.window, \"s\") * 1e9;\n if (ended !== undefined && ended - request.t <= window)\n return {\n ...base,\n ...nothing,\n ...chain,\n outcome,\n elapsed: between(request.t, ended),\n void: voided,\n finding: `detected after ${between(request.t, ended).value} s, where the reply should come`,\n };\n // the first segment with data: a proxy can acknowledge the request first, with no data\n const answer = socket.find(\n (record) => record.ev === \"rx\" && record.mono > request.t && (record.seg?.len.value ?? 0) > 0,\n );\n const reply = after[0];\n if (answer === undefined)\n return { ...base, ...nothing, ...chain, void: voided, finding: \"the reply never came\" };\n return {\n ...base,\n ...chain,\n outcome: { kind: \"answered\" },\n elapsed: between(request.t, answer.mono),\n socket: reply === undefined ? null : between(request.t, reply.t),\n noticed: reply === undefined ? null : between(answer.mono, reply.t),\n steps: [],\n void: voided,\n finding: null,\n };\n }\n\n if (!prediction.detects) {\n // the test of silence covers the window from the send of the request\n const window = valueIn(prediction.window, \"s\") * 1e9;\n if (ended === undefined || ended - request.t > window) {\n // the router keeps the flow in the window, unless the prediction says that it forgets it,\n // and when. Either way, nothing detects it\n const forgetIn = forgotten !== undefined && forgotten.t - request.t <= window ? forgotten : undefined;\n const expected = prediction.middlebox?.forgets;\n const after = forgetIn === undefined ? null : between(lastRx, forgetIn.t);\n let finding: string | null = null;\n if (expected === undefined) {\n if (after !== null) finding = `a router forgot the flow ${after.value} s after the last segment, where it should keep it`;\n } else if (after === null) {\n finding = \"no router forgot the flow in the window, where it should forget it\";\n } else {\n const noise = valueIn(noiseOf(cell), \"s\");\n const low = valueIn(expected.low, \"s\") - noise;\n const high = valueIn(expected.high, \"s\") + noise;\n if (after.value < low || after.value > high)\n finding = `a router forgot the flow ${after.value} s after the last segment, outside [${Math.round(low * 1e6) / 1e6}, ${Math.round(high * 1e6) / 1e6}] s`;\n }\n return { ...base, ...nothing, ...chain, void: voided, finding };\n }\n return {\n ...base,\n ...nothing,\n ...chain,\n outcome,\n elapsed: between(request.t, ended),\n void: voided,\n finding: `detected after ${between(request.t, ended).value} s, where nothing should`,\n };\n }\n\n if (ended === undefined)\n return {\n ...base,\n ...nothing,\n ...chain,\n void: voided,\n finding: `nothing detected it: ${prediction.timer} never fired`,\n };\n const reference = referenceAt(prediction.from);\n if (reference === undefined) {\n return {\n ...base,\n ...nothing,\n ...chain,\n outcome,\n noticed,\n void: voided,\n finding: `it ended without its reference event (${prediction.from})`,\n };\n }\n // the steps of a heartbeat are its later pings, each from the first ping that got no answer\n const steps =\n prediction.from === \"ping-sent\"\n ? pings.filter((ping) => ping.at > reference && ping.at <= ended).map((ping) => between(reference, ping.at))\n : (prediction.from === \"last-received\"\n ? keepalives\n : prediction.from === \"first-retransmission\"\n ? retransmitted.filter((record) => record.why === \"rto\" && record.mono > reference)\n : []\n ).map((record) => between(reference, record.mono));\n const matches =\n prediction.errno === \"EOF\"\n ? outcome.kind === \"eof\"\n : prediction.errno === \"CLOSED\"\n ? outcome.kind === \"closed\"\n : prediction.errno === \"DROPPED\"\n ? outcome.kind === \"dropped\"\n : outcome.kind === \"error\" && outcome.errno === prediction.errno;\n const words =\n outcome.kind === \"error\"\n ? outcome.errno\n : outcome.kind === \"closed\"\n ? \"its own close\"\n : outcome.kind === \"dropped\"\n ? \"a drop by its own program\"\n : \"end of file\";\n // the reconnect of the client after the detection, against the bands of its waits\n const reconnect = prediction.reconnects === undefined ? undefined : reconnectOf(run, ended, cookie, drop?.line.t ?? ended);\n const late = reconnect === undefined || prediction.reconnects === undefined ? null : reconnectFinding(prediction.reconnects, reconnect, noiseOf(cell));\n // a drop of the program against the way that the prediction gives: a close frame or a close\n const closed = prediction.drop === undefined || drop === undefined ? undefined : leftAfter(socket, drop.line);\n // the end of the client process closes each socket that is still open: that close is not the program's\n const { left, exited } =\n closed === undefined || drop === undefined || prediction.exits !== true\n ? { left: closed, exited: undefined }\n : closeOrExit(drop.line, closed, exitOf(run, cookie), noiseOf(cell));\n const how = prediction.drop === undefined || drop === undefined || left === undefined ? null : dropFinding(prediction.drop, drop, left, paired, exited);\n const found = [matches ? null : `it ended with ${words}, not ${prediction.errno}`, late, how].filter((each) => each !== null);\n const finding = found.length === 0 ? null : found.join(\". \");\n // the timer of an HTTP client or server is a timer of the program, not of the kernel: the kernel\n // timers of its socket do not drive the measurement\n const programTimer = cell.probe.http !== undefined && prediction.from === \"last-received\" && prediction.timer !== \"keepalive\";\n // a firing at the reference itself only moves the start of the interval. A reset meets the send\n // with no timer, a FIN arrives with none, and a toxic has its own clock\n if ((prediction.from === \"last-received\" && !programTimer) || prediction.from === \"first-retransmission\")\n voided ??= delayed(\n reference,\n ended,\n prediction.from === \"last-received\" ? \"keepalive\" : \"retransmit\",\n );\n // a heartbeat is a timer of the program. The retransmit timer of its ping fires in the same\n // interval, thus a delay of that timer behind its wheel slot tells that the VM stopped a vCPU\n if (prediction.from === \"ping-sent\") voided ??= delayed(reference, ended, \"retransmit\");\n // a timer of conntrack (expire_…) reaches its DESTROY through the listing of the router. A slow\n // listing between the expiry and the detection breaks the bound of its lag: the run measured the\n // pump, not the router. The expiry is at most the width of the band before the detection\n const lag = (valueIn(prediction.high, \"s\") - valueIn(prediction.low, \"s\")) * 1e9;\n const slow = prediction.timer.startsWith(\"expire_\")\n ? (run.middlebox ?? []).find(\n (line) =>\n line.ev === \"pump-slow\" &&\n line.t <= ended &&\n line.t + Number(line[\"took\"]) * 1e9 >= ended - lag,\n )\n : undefined;\n if (slow !== undefined)\n voided ??= `a listing of the router took ${Math.round(Number(slow[\"took\"]) * 1e4) / 10} ms, longer than the bound of its prediction`;\n // a toxic starts somewhere in the commit of its request. A commit longer than the noise of the\n // pipeline leaves its start unknown within δ_abs\n const commit = run.fault === null ? 0 : (run.fault.t1 - run.fault.t0) / 1e6;\n if (prediction.from === \"fault\" && commit > valueIn(INJECT, \"ms\"))\n voided ??= `the commit of the fault took ${Math.round(commit * 10) / 10} ms, longer than the noise of the pipeline: its start is not known`;\n // the view of the program of a heartbeat: from the line of its first ping without an answer to\n // the line of its drop, or to the line of the error that it saw\n const unanswered = prediction.from === \"ping-sent\" ? firstUnanswered(pings, socket, ended) : undefined;\n const endLine = drop?.line ?? seen;\n const view =\n unanswered !== undefined\n ? endLine === undefined\n ? null\n : between(unanswered.line.t, endLine.t)\n : remote\n ? null\n : socketVantage(cell, events, ready, request);\n return {\n ...base,\n ...chain,\n outcome,\n elapsed: between(reference, ended),\n socket: view,\n noticed,\n steps,\n ...(reconnect === undefined ? {} : { reconnect }),\n ...(left === undefined ? {} : { left }),\n ...(exited === undefined ? {} : { exited }),\n ...(cell.probe.ws !== undefined && inflight ? { call: callOf(events, request, ended) } : {}),\n void: voided,\n finding,\n };\n};\n","import { execFile } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { StartedTestContainer } from \"testcontainers\";\nimport type { Fabric, FabricManifest, RunRoute } from \"./cell.ts\";\n\n/**\n * A fabric is a routed network between the client and the target, on layer E3 (docs/S7.md). Four\n * routers of FRRouting, two leaves and two spines, run real BGP over veth pairs that containerlab\n * makes. The client hangs off leaf1 and the target off leaf2. The path between them goes through\n * spine1 by a weight, and spine2 holds the other path. A cell silences spine1, and the routes of\n * the leaves move to spine2 when a detector of the routers fires.\n *\n * This file holds the plan of the fabric as pure functions, and `openFabric` that starts it. A lab\n * opens a fabric with `Topology.fabric`. Thus the client, the target, the prober and the verdict\n * stay the same as on layer E1. The fabric needs a Linux host with containerlab and sudo.\n */\n\n/** This image is FRRouting 10.7.1, pinned by digest. */\nexport const FRR_IMAGE =\n \"quay.io/frrouting/frr:10.7.1@sha256:e995beaa50fdc9edb35eadcfefa29b7f062cc06f2b812613789b68fa541554d2\";\n\n/** This device is the side of the fabric in the client and in the target. Docker keeps eth0. */\nexport const FABRIC_DEVICE = \"eth1\";\n/** This address is the client on its network behind leaf1. */\nexport const FABRIC_CLIENT = \"10.1.0.2\";\n/** This address is the target on its network behind leaf2. */\nexport const FABRIC_TARGET = \"10.2.0.2\";\n\n/** This device of a leaf goes to spine1, thus a route on it is on the preferred path. */\nconst PREFERRED_DEVICE = \"eth1\";\n/** This limit is the time that the sessions and the routes get to come back before a run. */\nconst READY_MS = 90_000;\nconst READY_POLL_MS = 250;\n\n/** A router is one box of the fabric, as data. */\ninterface Router {\n readonly name: string;\n readonly as: number;\n readonly id: string;\n readonly interfaces: Readonly<Record<string, string>>;\n readonly neighbors: ReadonlyArray<{ readonly address: string; readonly as: number; readonly weight?: number }>;\n /** This prefix is the network behind a leaf, which its BGP advertises. */\n readonly network?: string;\n /** This prefix is the network behind the other leaf. A move is a change of its route. */\n readonly remote?: string;\n}\n\nconst CLIENT_NET = \"10.1.0.0/24\";\nconst TARGET_NET = \"10.2.0.0/24\";\n\n/** These are the routers. Each leaf prefers spine1 by a weight of 100, thus the path of each run is known. */\nexport const ROUTERS: readonly Router[] = [\n {\n name: \"leaf1\",\n as: 65001,\n id: \"10.255.0.1\",\n interfaces: { eth1: \"10.0.1.0/31\", eth2: \"10.0.2.0/31\", eth3: \"10.1.0.1/24\" },\n neighbors: [\n { address: \"10.0.1.1\", as: 65101, weight: 100 },\n { address: \"10.0.2.1\", as: 65102 },\n ],\n network: CLIENT_NET,\n remote: TARGET_NET,\n },\n {\n name: \"leaf2\",\n as: 65002,\n id: \"10.255.0.2\",\n interfaces: { eth1: \"10.0.3.0/31\", eth2: \"10.0.4.0/31\", eth3: \"10.2.0.1/24\" },\n neighbors: [\n { address: \"10.0.3.1\", as: 65101, weight: 100 },\n { address: \"10.0.4.1\", as: 65102 },\n ],\n network: TARGET_NET,\n remote: CLIENT_NET,\n },\n {\n name: \"spine1\",\n as: 65101,\n id: \"10.255.1.1\",\n interfaces: { eth1: \"10.0.1.1/31\", eth2: \"10.0.3.1/31\" },\n neighbors: [\n { address: \"10.0.1.0\", as: 65001 },\n { address: \"10.0.3.0\", as: 65002 },\n ],\n },\n {\n name: \"spine2\",\n as: 65102,\n id: \"10.255.1.2\",\n interfaces: { eth1: \"10.0.2.1/31\", eth2: \"10.0.4.1/31\" },\n neighbors: [\n { address: \"10.0.2.0\", as: 65001 },\n { address: \"10.0.4.0\", as: 65002 },\n ],\n },\n];\n\nconst LEAVES = ROUTERS.filter((router) => router.remote !== undefined);\n\n/** These are the links between the routers. The links to the client and the target come from `topologyOf`. */\nconst LINKS: ReadonlyArray<readonly [string, string]> = [\n [\"leaf1:eth1\", \"spine1:eth1\"],\n [\"leaf1:eth2\", \"spine2:eth1\"],\n [\"leaf2:eth1\", \"spine1:eth2\"],\n [\"leaf2:eth2\", \"spine2:eth2\"],\n];\n\n/** This text is the `daemons` file of each router: BGP and BFD, on top of what FRRouting always starts. */\nexport const DAEMONS: string = [\n \"bgpd=yes\",\n \"bfdd=yes\",\n \"vtysh_enable=yes\",\n 'zebra_options=\" -A 127.0.0.1 -s 90000000\"',\n 'mgmtd_options=\" -A 127.0.0.1\"',\n 'bgpd_options=\" -A 127.0.0.1\"',\n 'bfdd_options=\" -A 127.0.0.1\"',\n 'staticd_options=\"-A 127.0.0.1\"',\n \"\",\n].join(\"\\n\");\n\n/**\n * This function gives the configuration of a router. Graceful restart is off: after a hold expiry,\n * a helper can keep the stale routes, and the move that a cell measures does not come.\n * `maximum-paths 1` keeps one path, thus a move is one change of one route.\n */\nexport const frrConf = (router: Router, fabric: Fabric): string => {\n const keepalive = valueIn(fabric.keepalive, \"s\");\n const hold = valueIn(fabric.hold, \"s\");\n const out = [\"frr defaults traditional\", `hostname ${router.name}`, \"ip forwarding\", \"!\"];\n for (const [name, address] of Object.entries(router.interfaces))\n out.push(`interface ${name}`, ` ip address ${address}`, \"!\");\n if (fabric.bfd !== null) {\n const interval = valueIn(fabric.bfd.interval, \"ms\");\n out.push(\n \"bfd\",\n \" profile fast\",\n ` receive-interval ${interval}`,\n ` transmit-interval ${interval}`,\n ` detect-multiplier ${fabric.bfd.multiplier}`,\n \" exit\",\n \"exit\",\n \"!\",\n );\n }\n out.push(\n `router bgp ${router.as}`,\n ` bgp router-id ${router.id}`,\n \" no bgp ebgp-requires-policy\",\n \" no bgp network import-check\",\n \" bgp graceful-restart-disable\",\n );\n for (const neighbor of router.neighbors) {\n out.push(\n ` neighbor ${neighbor.address} remote-as ${neighbor.as}`,\n ` neighbor ${neighbor.address} timers ${keepalive} ${hold}`,\n ` neighbor ${neighbor.address} timers connect 1`,\n ` neighbor ${neighbor.address} advertisement-interval 0`,\n );\n if (fabric.bfd !== null) out.push(` neighbor ${neighbor.address} bfd profile fast`);\n }\n out.push(\" !\", \" address-family ipv4 unicast\");\n if (router.network !== undefined) out.push(` network ${router.network}`);\n out.push(\" maximum-paths 1\");\n for (const neighbor of router.neighbors)\n if (neighbor.weight !== undefined) out.push(` neighbor ${neighbor.address} weight ${neighbor.weight}`);\n out.push(\" exit-address-family\", \"exit\", \"\");\n return out.join(\"\\n\");\n};\n\n/**\n * This function gives the topology file of containerlab. The client and the target are containers\n * of the lab, and the fabric adds a device to each. Each link has the MTU of a Docker network, thus\n * a segment is as long as on layer E1. The default of containerlab is 9500. The management network\n * belongs to the lab, and Docker chooses its subnet.\n */\nexport const topologyOf = (lab: string, dir: string, client: string, target: string): string => {\n const nodes = ROUTERS.flatMap((router) => [\n ` ${router.name}:`,\n \" kind: linux\",\n ` image: ${FRR_IMAGE}`,\n \" binds:\",\n ` - ${dir}/${router.name}.conf:/etc/frr/frr.conf`,\n ` - ${dir}/daemons:/etc/frr/daemons`,\n \" sysctls:\",\n \" net.ipv4.ip_forward: 1\",\n \" net.ipv4.conf.all.rp_filter: 0\",\n \" net.ipv4.conf.default.rp_filter: 0\",\n ]);\n const links = [...LINKS, [\"leaf1:eth3\", `${client}:${FABRIC_DEVICE}`], [\"leaf2:eth3\", `${target}:${FABRIC_DEVICE}`]];\n return [\n `name: ${lab}`,\n \"mgmt:\",\n ` network: clab-${lab}`,\n \" ipv4-subnet: auto\",\n \"topology:\",\n \" nodes:\",\n ...nodes,\n ` ${client}:`,\n \" kind: ext-container\",\n ` ${target}:`,\n \" kind: ext-container\",\n \" links:\",\n ...links.flatMap(([a, b]) => [` - endpoints: [\"${a}\", \"${b}\"]`, \" mtu: 1500\"]),\n \"\",\n ].join(\"\\n\");\n};\n\n/** A route line is one line of `ip -ts -o monitor route`, with its time on the wall clock in ms. */\nexport interface RouteLine {\n readonly wall: number;\n readonly deleted: boolean;\n readonly prefix: string;\n readonly via: string | null;\n readonly dev: string | null;\n}\n\n/** This function reads a line of `ip -ts -o monitor route`, or it gives null for another line. The clock of a container is UTC. */\nexport const routeLine = (text: string): RouteLine | null => {\n const line = text.trim();\n const found = /^\\[(\\d{4})-(\\d\\d)-(\\d\\d)T(\\d\\d):(\\d\\d):(\\d\\d)\\.(\\d{6})\\] /.exec(line);\n if (found === null) return null;\n const [stamp, year, month, day, hour, minute, second, micro] = found;\n const words = line.slice(stamp.length).split(\" \").filter((word) => word !== \"\");\n const change = words[0] === \"Deleted\" || words[0] === \"Replaced\" ? words[0] : null;\n const prefix = words[change === null ? 0 : 1];\n if (prefix === undefined) return null;\n const after = (name: string): string | null => {\n const at = words.indexOf(name);\n return at === -1 ? null : (words[at + 1] ?? null);\n };\n return {\n wall:\n Date.UTC(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute), Number(second)) +\n Number(micro) / 1_000,\n deleted: change === \"Deleted\",\n prefix,\n via: after(\"via\"),\n dev: after(\"dev\"),\n };\n};\n\n/** A clock pair is one instant on the monotonic clock in ns and on the wall clock in ms. */\nexport interface ClockPair {\n readonly mono: number;\n readonly wall: number;\n}\n\n/**\n * This function takes a time on the wall clock to the monotonic clock. The harness runs on the host\n * of the containers, thus `process.hrtime` reads the CLOCK_MONOTONIC of the injector and the\n * prober. The error of the pair is approximately 1 ms, the step of `Date.now`.\n */\nexport const monotonicAt = (wall: number, pair: ClockPair): number => pair.mono + (wall - pair.wall) * 1e6;\n\n/** This function gives the state of the BGP sessions from `show bgp neighbors json`. */\nexport const sessionsOf = (json: string): { readonly up: number; readonly established: number } => {\n const views = Object.values(JSON.parse(json) as Record<string, { bgpState?: string; connectionsEstablished?: number }>);\n return {\n up: views.filter((view) => view.bgpState === \"Established\").length,\n established: views.reduce((sum, view) => sum + (view.connectionsEstablished ?? 0), 0),\n };\n};\n\n/** These are the views of a leaf that tell if a run can start on it. */\nexport interface LeafViews {\n readonly neighbors: string;\n /** This text is the kernel's route to the far network, from `ip -o route show`. */\n readonly route: string;\n /** This text is `show bgp ipv4 unicast PREFIX json`. */\n readonly paths: string;\n /** This text is `show bfd peers json`, or null when the fabric has no BFD. */\n readonly bfd: string | null;\n}\n\n/**\n * This function tells what a leaf still lacks before a run, or it gives null. The two sessions must\n * be up and the route must be on spine1. Spine2 must hold the other path. Without these, the fault\n * of a run acts on another path, or nothing can take over.\n */\nexport const leafLacks = (views: LeafViews): string | null => {\n const { up } = sessionsOf(views.neighbors);\n if (up < 2) return `${up} of 2 BGP sessions are up`;\n if (!views.route.includes(` dev ${PREFERRED_DEVICE} `)) return `the route is not on spine1: ${views.route || \"no route\"}`;\n const paths = (JSON.parse(views.paths) as { paths?: unknown[] }).paths?.length ?? 0;\n if (paths < 2) return `BGP holds ${paths} of 2 paths`;\n if (views.bfd !== null) {\n const peers = JSON.parse(views.bfd) as Array<{ status?: string }>;\n const live = peers.filter((peer) => peer.status === \"up\").length;\n if (live < 2) return `${live} of 2 BFD peers are up`;\n }\n return null;\n};\n\n/**\n * This function gives the later move of the leaves after an instant: for each leaf, the first route\n * to its far network that leaves spine1. It gives null when a leaf has no move. The later move ends\n * the outage in the two directions.\n */\nexport const laterMove = (routes: readonly RunRoute[], after: number): number | null => {\n const firsts = LEAVES.map(\n (leaf) =>\n routes.find(\n (route) =>\n route.leaf === leaf.name && route.prefix === leaf.remote && route.t > after && !route.deleted && route.dev !== PREFERRED_DEVICE,\n )?.t,\n );\n return firsts.every((t) => t !== undefined) ? Math.max(...(firsts as number[])) : null;\n};\n\n/** A fabric lab is the open fabric of a lab. */\nexport interface FabricLab {\n /** These are the lines of the route monitors of the leaves, on the monotonic clock. */\n readonly routes: readonly RunRoute[];\n /** This method drops each packet of spine1 in one commit, and the links stay up. */\n silence(): Promise<{ t0: number; t1: number }>;\n /** This method ends a silence. */\n clear(): Promise<{ t0: number; t1: number }>;\n /** This method waits until each leaf is on spine1 with each session up. */\n ready(): Promise<void>;\n /** This method gives the count of established sessions of each leaf so far. */\n sessions(): Promise<Readonly<Record<string, number>>>;\n /** This method gives the record of the fabric for a manifest. */\n manifest(): FabricManifest;\n /** This method destroys the routers. */\n close(): Promise<void>;\n}\n\n/** These are the parts of a lab that a fabric uses. */\nexport interface FabricParts {\n readonly fabric: Fabric;\n readonly image: string;\n readonly client: StartedTestContainer;\n readonly server: StartedTestContainer;\n readonly admin: StartedTestContainer;\n readonly injector: StartedTestContainer;\n readonly opened: StartedTestContainer[];\n readonly output: (container: StartedTestContainer, argv: string[]) => Promise<string>;\n}\n\n/** This function runs a program on the host and gives its output. Its error holds the stderr of the program. */\nconst host = (program: string, args: readonly string[]): Promise<string> =>\n new Promise((resolve, reject) => {\n execFile(program, [...args], { maxBuffer: 16 * 1024 * 1024 }, (error, stdout, stderr) => {\n if (error === null) resolve(stdout);\n else reject(new Error(`${program} ${args.join(\" \")}: ${error.message}\\n${stderr}`));\n });\n });\n\nconst nameOf = (container: StartedTestContainer): string => container.getName().replace(/^\\//, \"\");\n\n/** This function gives a clock pair at this instant. */\nconst clockPair = (): ClockPair => ({ mono: Number(process.hrtime.bigint()), wall: Date.now() });\n\n/**\n * This function deploys the routers of a lab and joins the client and the target to them. It also\n * starts the sidecars: the injector of spine1 and a route monitor on each leaf. The caller stops the\n * sidecars with the other containers of the lab, and it calls `close` first.\n */\nexport const openFabric = async (parts: FabricParts): Promise<FabricLab> => {\n const { fabric, image, admin, injector, opened, output } = parts;\n const { GenericContainer } = await import(\"testcontainers\");\n const lab = `e3-${randomBytes(4).toString(\"hex\")}`;\n const dir = await mkdtemp(join(tmpdir(), \"fabric-\"));\n const file = join(dir, \"lab.clab.yml\");\n await writeFile(join(dir, \"daemons\"), DAEMONS);\n for (const router of ROUTERS) await writeFile(join(dir, `${router.name}.conf`), frrConf(router, fabric));\n await writeFile(file, topologyOf(lab, dir, nameOf(parts.client), nameOf(parts.server)));\n const close = async (): Promise<void> => {\n await host(\"sudo\", [\"containerlab\", \"destroy\", \"-t\", file, \"--cleanup\"]).catch(() => undefined);\n await rm(dir, { recursive: true, force: true }).catch(() => undefined);\n };\n const node = (name: string) => `clab-${lab}-${name}`;\n try {\n await host(\"sudo\", [\"containerlab\", \"deploy\", \"-t\", file]);\n const version = /version:\\s*(\\S+)/.exec(await host(\"containerlab\", [\"version\"]))?.[1] ?? \"unknown\";\n await output(admin, [\"ip\", \"addr\", \"add\", `${FABRIC_CLIENT}/24`, \"dev\", FABRIC_DEVICE]);\n await output(admin, [\"ip\", \"route\", \"replace\", TARGET_NET, \"via\", \"10.1.0.1\", \"dev\", FABRIC_DEVICE]);\n await output(injector, [\"ip\", \"addr\", \"add\", `${FABRIC_TARGET}/24`, \"dev\", FABRIC_DEVICE]);\n await output(injector, [\"ip\", \"route\", \"replace\", CLIENT_NET, \"via\", \"10.2.0.1\", \"dev\", FABRIC_DEVICE]);\n\n const silencer = await new GenericContainer(image)\n .withNetworkMode(`container:${node(\"spine1\")}`)\n .withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\")\n .start();\n opened.push(silencer);\n const routes: RunRoute[] = [];\n const monitors = new Map<string, StartedTestContainer>();\n for (const leaf of LEAVES) {\n const monitor = await new GenericContainer(image)\n .withNetworkMode(`container:${node(leaf.name)}`)\n .withCommand([\"ip\", \"-ts\", \"-o\", \"monitor\", \"route\"])\n .withLogConsumer((stream) => {\n let rest = \"\";\n stream.on(\"data\", (chunk: Buffer | string) => {\n const text = (rest + chunk.toString()).split(\"\\n\");\n rest = text.pop() ?? \"\";\n for (const each of text) {\n const line = routeLine(each);\n if (line === null) continue;\n const { wall, ...route } = line;\n routes.push({ ...route, leaf: leaf.name, t: monotonicAt(wall, clockPair()) });\n }\n });\n })\n .start();\n opened.push(monitor);\n monitors.set(leaf.name, monitor);\n }\n const stamp = async (action: string): Promise<{ t0: number; t1: number }> => {\n const last = (await output(silencer, [\"/opt/harness/inject\", action])).split(\"\\n\").at(-1)!;\n const { t0, t1 } = JSON.parse(last) as { t0: number; t1: number };\n return { t0, t1 };\n };\n const vtysh = (leaf: string, view: string) => host(\"docker\", [\"exec\", node(leaf), \"vtysh\", \"-c\", view]);\n return {\n routes,\n silence: () => stamp(\"silence\"),\n clear: () => stamp(\"clear-silence\"),\n async ready() {\n const deadline = Date.now() + READY_MS;\n for (;;) {\n const lacks: string[] = [];\n for (const leaf of LEAVES) {\n const prefix = leaf.remote!;\n // a daemon that still starts refuses vtysh: that is one more reason to wait\n const lacking = await (async () =>\n leafLacks({\n neighbors: await vtysh(leaf.name, \"show bgp neighbors json\"),\n route: `${await output(monitors.get(leaf.name)!, [\"ip\", \"-o\", \"route\", \"show\", prefix])} `,\n paths: await vtysh(leaf.name, `show bgp ipv4 unicast ${prefix} json`),\n bfd: fabric.bfd === null ? null : await vtysh(leaf.name, \"show bfd peers json\"),\n }))().catch((error: unknown) => String(error));\n if (lacking !== null) lacks.push(`${leaf.name}: ${lacking}`);\n }\n if (lacks.length === 0) return;\n if (Date.now() > deadline) throw new Error(`the fabric is not ready: ${lacks.join(\"; \")}`);\n await new Promise((resolve) => setTimeout(resolve, READY_POLL_MS));\n }\n },\n async sessions() {\n const out: Record<string, number> = {};\n for (const leaf of LEAVES) out[leaf.name] = sessionsOf(await vtysh(leaf.name, \"show bgp neighbors json\")).established;\n return out;\n },\n manifest: () => ({ ...fabric, image: FRR_IMAGE, containerlab: version }),\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { release } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * A layer is a rung of the laboratory (`docs/S7.md`). E1 is containers on one kernel, and E2 is a\n * cluster of containers on one kernel. A lab with `Topology.fabric` writes E3: routers in containers.\n * A lab in a guest of QEMU writes E4 (`substrateHere`). The other layers do not have a runner at this\n * time.\n */\nexport type Layer = \"E0\" | \"E1\" | \"E2\" | \"E3\" | \"E4\" | \"E5\" | \"E6\";\n\n/** A cloud is where the runner operates. GitHub can schedule a standard Linux job on Azure or on AWS. */\nexport type Cloud = \"azure\" | \"aws\" | \"unknown\";\n\n/** A host is what a process reads about its own machine. */\nexport interface Host {\n /** This text is the kernel release. */\n readonly kernel: string | null;\n /** This number is `CONFIG_HZ` from the configuration of the kernel, or null without that file. */\n readonly hz: number | null;\n /** This text is the DMI system vendor, for example `Microsoft Corporation`, or null without that file. */\n readonly vendor: string | null;\n /** This value tells if `/dev/kvm` exists. A later VM layer needs it. */\n readonly kvm: boolean;\n /** This text is `$ImageOS $ImageVersion` of a hosted runner, or null elsewhere. */\n readonly image: string | null;\n}\n\n/**\n * A substrate tells where a record comes from. The rules of comparison in `docs/S7.md` read it: no\n * statistic pools two layers, two kernels or two clouds. The digest of each image stays in the\n * manifest. A value is null in a record from before this block.\n */\nexport interface Substrate {\n readonly layer: Layer;\n readonly cloud: Cloud;\n readonly vendor: string | null;\n readonly kernel: string | null;\n readonly hz: number | null;\n readonly kvm: boolean | null;\n readonly image: string | null;\n}\n\n/** GitHub announced Linux jobs on AWS on this date. Each earlier hosted job ran on Azure. */\nexport const AWS_FROM = \"2026-10-28\";\n\n/** This function gives the cloud of a DMI vendor. A kernel name does not tell: one image can start on each cloud. */\nexport const cloudOf = (vendor: string | null): Cloud => {\n if (vendor === null) return \"unknown\";\n if (/microsoft/i.test(vendor)) return \"azure\";\n if (/amazon/i.test(vendor)) return \"aws\";\n return \"unknown\";\n};\n\nconst textOf = (path: string): string | null => {\n try {\n return readFileSync(path, \"utf8\").trim();\n } catch {\n return null;\n }\n};\n\n/** This function reads the host. `root` and `env` are for tests. */\nexport const readHost = (root = \"/\", env: Readonly<Record<string, string | undefined>> = process.env, kernel: string = release()): Host => {\n const config = textOf(join(root, \"boot\", `config-${kernel}`));\n const hz = config === null ? undefined : /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1];\n const os = env[\"ImageOS\"];\n const version = env[\"ImageVersion\"];\n return {\n kernel,\n hz: hz === undefined ? null : Number(hz),\n vendor: textOf(join(root, \"sys\", \"class\", \"dmi\", \"id\", \"sys_vendor\")),\n kvm: existsSync(join(root, \"dev\", \"kvm\")),\n image: os === undefined || version === undefined ? null : `${os} ${version}`,\n };\n};\n\n/** This function gives the substrate of a layer on a host. */\nexport const substrateOn = (layer: Layer, host: Host = readHost()): Substrate => ({ layer, cloud: cloudOf(host.vendor), ...host });\n\n/**\n * This function gives the substrate of a lab at this place. A guest cannot read its own runner: its\n * DMI vendor is QEMU, and `ImageOS` is not set. Thus the runner writes its host to `LAB_RUNNER`, and\n * the guest keeps only its own kernel and HZ. A value of that variable makes the layer E4.\n */\nexport const substrateHere = (layer: Layer, host: Host = readHost(), env: Readonly<Record<string, string | undefined>> = process.env): Substrate => {\n const runner = env[\"LAB_RUNNER\"];\n if (runner === undefined || runner === \"\") return substrateOn(layer, host);\n return substrateOn(\"E4\", { ...(JSON.parse(runner) as Host), kernel: host.kernel, hz: host.hz });\n};\n\n/** A CPU reading is two counters of `/proc/stat`, in ticks of the clock. */\nexport interface CpuTime {\n /** This count is the time that the host gave to another guest while this one had work. */\n readonly steal: number;\n /** This count is the sum of all states of each CPU. */\n readonly total: number;\n}\n\n/** This function reads the CPU time of this machine, or gives null without `/proc/stat`. `root` is for tests. */\nexport const readCpu = (root = \"/\"): CpuTime | null => {\n const line = textOf(join(root, \"proc\", \"stat\"))?.split(\"\\n\")[0];\n if (line === undefined || !line.startsWith(\"cpu \")) return null;\n // user, nice, system, idle, iowait, irq, softirq, steal: the guest counters that follow are in user\n const ticks = line.trim().split(/\\s+/).slice(1, 9).map(Number);\n const steal = ticks[7];\n if (steal === undefined || ticks.some(Number.isNaN)) return null;\n return { steal, total: ticks.reduce((sum, tick) => sum + tick, 0) };\n};\n\n/**\n * This function gives the share of the CPU time between two readings that the host took. The share\n * goes from zero to one. It is null if no tick passed. A guest sees only the host above it. On a hosted\n * runner that host is itself a guest, and this number does not show the contention of the layer below it.\n */\nexport const stealShare = (before: CpuTime, after: CpuTime): number | null => {\n const total = after.total - before.total;\n return total <= 0 ? null : (after.steal - before.steal) / total;\n};\n\n/** A part of a record that can hold a substrate: a manifest of the harness, or the fields of a kind manifest. */\nexport interface SubstrateSource {\n readonly substrate?: Substrate;\n readonly kernel?: string;\n readonly hz?: string | null;\n}\n\n/**\n * This function reads the substrate of a record, the upgrade of a record from before this block.\n * Nothing rewrites such a record. It reads as the given layer. Its cloud is Azure if the record is\n * from before `AWS_FROM`, and unknown after that date, because its runner did not record the cloud.\n */\nexport const substrateOf = (source: SubstrateSource, at: string, layer: Layer = \"E1\"): Substrate =>\n source.substrate ?? {\n layer,\n cloud: at.slice(0, AWS_FROM.length) < AWS_FROM ? \"azure\" : \"unknown\",\n vendor: null,\n kernel: source.kernel ?? null,\n hz: source.hz === undefined || source.hz === null ? null : Number(source.hz),\n kvm: null,\n image: null,\n };\n\nconst differ = <T>(a: T | null, b: T | null, unknown?: T): boolean => a !== null && b !== null && a !== unknown && b !== unknown && a !== b;\n\n/**\n * This function tells if a statistic can pool two substrates. They must have one layer, one kernel\n * and one cloud. An unknown value does not refuse a pair, because an old record cannot tell. The\n * reader of such a pair says so with `substrateKey`.\n */\nexport const comparable = (a: Substrate, b: Substrate): boolean =>\n a.layer === b.layer && !differ(a.kernel, b.kernel) && !differ<Cloud>(a.cloud, b.cloud, \"unknown\");\n\n/** This function gives the one-line name of a substrate, for a summary. */\nexport const substrateKey = (substrate: Substrate): string => `${substrate.layer} ${substrate.cloud} ${substrate.kernel ?? \"unknown\"}`;\n\n/**\n * This function gives the first two substrates that a statistic cannot pool, or undefined. It\n * examines each pair. An unknown value matches Azure and AWS, thus one comparison with the first\n * substrate can miss a pair.\n */\nexport const unpoolable = (substrates: readonly Substrate[]): readonly [Substrate, Substrate] | undefined => {\n for (const [index, a] of substrates.entries()) {\n const b = substrates.slice(index + 1).find((other) => !comparable(a, other));\n if (b !== undefined) return [a, b];\n }\n return undefined;\n};\n","import { createHash } from \"node:crypto\";\nimport type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport type * as Testcontainers from \"testcontainers\";\nimport type { Quantity } from \"@mark1russell7/quantity\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport { isHopPlace } from \"./cell.ts\";\nimport type {\n Client,\n ClientCapability,\n ClientImage,\n FabricManifest,\n FaultPlace,\n Hop,\n HopEvent,\n HopPlace,\n HostSysctl,\n ImageSource,\n KernelRecord,\n MiddleboxEvent,\n ProbeEvent,\n ProxyHop,\n RunTopology,\n Target,\n Topology,\n Toxic,\n} from \"./cell.ts\";\nimport type { FabricLab } from \"./fabric.ts\";\nimport { FABRIC_CLIENT, FABRIC_DEVICE, FABRIC_TARGET, openFabric } from \"./fabric.ts\";\nimport { SHIPPED_CLIENTS, buildRecordOf, harnessImage, harnessVersion, imageOf, routerImage, shippedSource, targetImageOf, targetSourceOf, type BuildRecord } from \"./image.ts\";\nimport type { Substrate } from \"./substrate.ts\";\nimport { substrateHere } from \"./substrate.ts\";\n\n/** This function loads Testcontainers when a lab first opens. Code that only measures and judges does not load it. */\nexport const containers = (): Promise<typeof Testcontainers> => import(\"testcontainers\");\n\n/**\n * This time is the interval of the listing of a router, when its hop does not set one. A listing\n * evicts each expired flow that it walks past, and the DESTROY event of that flow follows.\n */\nexport const PUMP: Quantity = { value: 0.1, unit: \"s\" };\n/**\n * This time is the longest listing of the conntrack table of a router that a prediction assumes.\n * A DESTROY follows an expiry within the interval of the pump and two listings. On 2026-10-15,\n * the slowest of 500 listings in an idle router took 19.4 ms, and the median took 5.5 ms. A\n * longer listing writes a `pump-slow` line, and a run with one near its detection is void.\n */\nexport const LISTING: Quantity = { value: 20, unit: \"ms\" };\n/**\n * This time is how late the pump of a router can be beyond its interval and its two listings. The\n * pump sleeps after each listing, and the sleep can end late. The watcher also reads and stamps each\n * event within a millisecond. Thus a DESTROY follows an expiry within the interval of the pump, two\n * listings and this slack. It is an assumption: in run 39116866471, two of 11 forgets came 1.6 ms\n * and 2.2 ms after the pump and two listings.\n */\nexport const PUMP_SLACK: Quantity = { value: 5, unit: \"ms\" };\n\n/** This count is how many of the last lines of a proxy hop the lab keeps. The error of a hop that does not start gives them. */\nconst TAIL_LINES = 60;\n\n/** This count is how many lines of the output of a proxy hop the lab keeps, for a write that the proxy confirms. */\nconst OUTPUT_LINES = 2000;\n\n/** This time is how long a write of a hop waits for the line that confirms it, in milliseconds. */\nconst CONFIRM_MS = 10_000;\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * A network fault is a fault that the injector applies as a filter rule. It is a black hole (both\n * directions, or one), or a reset on the next segment. It can also be an ICMP unreachable for each\n * segment, or a drop of each segment that is longer than a length.\n */\nexport type NetworkFault = \"blackhole\" | \"rst\" | \"reject\" | \"mtu\";\n\n/** These are the options of a network fault: the direction of a black hole, the code of a reject, the length of an MTU drop. */\nexport interface FaultOptions {\n /** This direction is relative to the namespace of the rule: `in` drops what comes from the peer, `out` what goes to it. */\n readonly direction?: \"in\" | \"out\";\n readonly code?: \"host\" | \"net\" | \"port\" | \"admin\";\n /** This length is the longest segment in bytes that an MTU drop lets through. */\n readonly above?: number;\n /** These are the addresses that the rule faces, in place of the peer of its place. */\n readonly peers?: readonly string[];\n}\n\n/** This function gives the arguments of the injector for the options of a fault. */\nexport const optionArgs = (options: FaultOptions): string[] => [\n ...(options.direction === undefined ? [] : [\"--direction\", options.direction]),\n ...(options.code === undefined ? [] : [\"--code\", options.code]),\n ...(options.above === undefined ? [] : [\"--above\", String(options.above)]),\n];\n\n/** These are the actions of the injector that lift each network fault. */\nexport const LIFT: Readonly<Record<NetworkFault, string>> = {\n blackhole: \"clear\",\n rst: \"clear-rst\",\n reject: \"clear-reject\",\n mtu: \"clear-mtu\",\n};\n\n/**\n * A fault side is the namespace that gets the rules of a fault: the namespace of the peer of the\n * observer. For the client, it is the namespace of the target (the injector). For the server, it\n * is the namespace of the client (its privileged admin). Rules in the namespace of the observer\n * make its sends fail locally, with EPERM, and the network does not lose them. Thus its\n * retransmissions do not go out. The retransmission tracepoint of the kernel then records none,\n * because it fires only for a retransmission that went out.\n */\nexport type FaultSide = \"target\" | \"client\";\n\n/** A hop of a manifest is one hop of a topology, as the lab started it. */\nexport interface ManifestHop {\n readonly name: string;\n readonly kind: \"router\" | \"proxy\";\n readonly image: string;\n readonly id: string;\n /** These are the settings of the hop: the form and the idle timeout of a router, the files and settings of a proxy. */\n readonly settings: Readonly<Record<string, string>>;\n /** These are the sysctls of the namespace of the hop, as read back after the harness set them. */\n readonly sysctls: Readonly<Record<string, string>>;\n}\n\n/** This record is one sysctl of the host for one environment, as the harness read it. */\nexport interface HostSetting {\n readonly name: string;\n readonly before: string;\n readonly set: string;\n /** This value is the read after the restore. It is null until the restore. */\n readonly restored: string | null;\n}\n\n/** A manifest is what a lab records about its machine, its images and its settings. */\nexport interface Manifest {\n readonly kernel: string;\n /** This text is the architecture of the machine, as uname -m gives it: x86_64. */\n readonly architecture: string;\n readonly hz: string | null;\n /**\n * This text tells where the HZ came from: the configuration of the kernel, or a measurement. A\n * host without /proc/config.gz (a hosted runner) gets a measurement of jiffies against the clock.\n */\n readonly hzFrom?: \"config\" | \"measured\";\n readonly boot_id: string;\n readonly docker: string;\n /** This block tells the layer, the cloud and the kernel of the record. A record from before it reads through `substrateOf`. */\n readonly substrate?: Substrate;\n /** This record is the fabric of a cell with `Topology.fabric`. */\n readonly fabric?: FabricManifest;\n /** This record is the target, and its settings as it read them back. */\n readonly target: {\n readonly image: string;\n /** This source is the image of the subject that the target operates (`Target.subject`), with its stock base. */\n readonly subject?: ImageSource;\n readonly base?: string;\n readonly id: string;\n readonly settings: Readonly<Record<string, string>>;\n /** These are the sysctls of its namespace, as read back after the harness set them. */\n readonly sysctls: Readonly<Record<string, string>>;\n /** These are the files that went into the target, by their path, each with the sha256 of its content. */\n readonly files?: Readonly<Record<string, string>>;\n /** This line is the first line of a target that writes them: a server that tells its settings as it reads them. */\n readonly first?: ProbeEvent;\n /** This record tells what the image of a target holds when the harness builds it: the image of a subject (`buildRecordOf`). */\n readonly build?: BuildRecord;\n };\n /**\n * This record is the harness: its image, the id of that image and its Alpine packages. It also\n * has the version of the package of the harness, and the build of its image. The record of a\n * cell gives the commit of the code that operated.\n */\n readonly harness: { readonly image: string; readonly id: string; readonly packages: string[]; readonly version?: string; readonly build?: BuildRecord };\n /**\n * This record is the client of each run: the TCP client of the harness, a driver, or an image that\n * the cell gives. `source` is the source of its image, when it is not a stock image by its name.\n */\n readonly client: {\n readonly kind: Client | \"image\";\n readonly image: string;\n readonly capabilities?: readonly ClientCapability[];\n readonly source?: ImageSource;\n readonly build?: BuildRecord;\n };\n /** These are the namespaces that the prober watched, by inode. */\n readonly netns: {\n readonly client: number;\n readonly target: number;\n readonly hops?: Readonly<Record<string, number>>;\n };\n /** These are the sysctls of the client namespace, as read back after the harness set them. */\n readonly sysctls: Readonly<Record<string, string>>;\n /** These are the sysctls of the host that the cell set: each value before, as set, and as restored. */\n readonly host?: readonly HostSetting[];\n /** These are the hops of a topology, in sequence from the client. */\n readonly hops?: readonly ManifestHop[];\n /** These are the parts of a group, with their settings as each part read them back. */\n readonly group?: {\n readonly members: ReadonlyArray<{ readonly name: string; readonly ip: string; readonly id: string; readonly settings: Readonly<Record<string, string>> }>;\n readonly sentinels: ReadonlyArray<{ readonly name: string; readonly ip: string; readonly id: string; readonly settings: Readonly<Record<string, string>> }>;\n readonly observer: { readonly image: string };\n };\n}\n\n/** These are the JSON lines of a program, as they arrive. */\nexport interface Lines<T extends { readonly ev: string }> {\n readonly seen: T[];\n /** These are the other lines that it wrote, for example an error. They explain a program that stopped its output. */\n readonly other: string[];\n consume: (stream: NodeJS.ReadableStream) => void;\n /** This method gives the first line of one of these kinds, or it rejects after `within` ms. */\n until(kinds: readonly string[], within: number, who: string): Promise<T>;\n}\n\n/** This function collects the JSON lines of a program. It gives each line to `also` too, when the caller gives it. */\nexport const lines = <T extends { readonly ev: string }>(also?: (line: T) => void): Lines<T> => {\n const seen: T[] = [];\n const other: string[] = [];\n const waiting: Array<{ kinds: readonly string[]; resolve: (line: T) => void }> = [];\n let partial = \"\";\n const take = (text: string) => {\n if (!text.startsWith(\"{\")) {\n if (text.length > 0) other.push(text);\n return;\n }\n let line: T;\n try {\n line = JSON.parse(text) as T;\n } catch {\n // not whole JSON, for example an object that the program printed: a throw here stops the lines of the stream\n other.push(text);\n return;\n }\n seen.push(line);\n also?.(line);\n for (const wait of waiting.splice(0)) {\n if (wait.kinds.includes(line.ev)) wait.resolve(line);\n else waiting.push(wait);\n }\n };\n return {\n seen,\n other,\n consume: (stream) =>\n stream.on(\"data\", (chunk: Buffer | string) => {\n partial += chunk.toString();\n const split = partial.split(\"\\n\");\n partial = split.pop() ?? \"\";\n for (const text of split) take(text.trim());\n }),\n until(kinds, within, who) {\n const found = seen.find((line) => kinds.includes(line.ev));\n if (found !== undefined) return Promise.resolve(found);\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n // its last lines tell why: a fail line of a client that could not connect, or a text that is not a line\n const failed = seen.filter((line) => line.ev === \"fail\" || line.ev === \"error\").slice(0, 3);\n const last = [...new Set([...failed, ...seen.slice(-3)])].map((line) => JSON.stringify(line));\n const said = [...(last.length === 0 ? [] : [`its last lines: ${last.join(\" | \")}`]), ...(other.length === 0 ? [] : [`it wrote: ${other.slice(-3).join(\" | \")}`])];\n reject(new Error(`no ${kinds.join(\" or \")} from the ${who} in ${within} ms${said.length === 0 ? \"\" : `; ${said.join(\"; \")}`}`));\n }, within);\n waiting.push({\n kinds,\n resolve: (line) => {\n clearTimeout(timer);\n resolve(line);\n },\n });\n });\n },\n };\n};\n\n/** A probe is the client container of one run. */\nexport interface Probe {\n /** This method gives the first event of one of these kinds, or it rejects after `within` ms. */\n until(kinds: readonly string[], within: number): Promise<ProbeEvent>;\n /** This method lets an in-flight probe send its request. */\n go(): Promise<void>;\n /** This method freezes the client with the cgroup freezer: its process stops, and its kernel continues to answer. */\n freeze(): Promise<void>;\n thaw(): Promise<void>;\n /** This method stops the process of the client with SIGKILL. Its kernel then closes its socket with a FIN, or a reset. */\n kill(): Promise<void>;\n readonly events: readonly ProbeEvent[];\n stop(): Promise<void>;\n}\n\n/** An agent is a container that a lab starts in the namespaces of the target, for example a Node process that signals the server. */\nexport interface Agent {\n /** These are the JSON lines that it wrote, as they arrive. */\n readonly lines: Lines<{ readonly ev: string }>;\n /** This method starts a command in the agent, and gives its standard output. */\n exec(argv: readonly string[]): Promise<string>;\n stop(): Promise<void>;\n}\n\n/** A sibling is a server that a lab starts on the network of the target, for example a standby. */\nexport interface Sibling {\n readonly ip: string;\n readonly netns: number;\n /** This method starts a command in the sibling, and gives its standard output. */\n exec(argv: readonly string[]): Promise<string>;\n}\n\n/** A lab is one environment: the target, the client, the hops of a topology, the injectors and the prober. */\nexport interface Lab {\n /** This address is the address of the target on its own network. */\n readonly serverIp: string;\n /** This address is the address that the client connects to: the target, or the first proxy of a topology. */\n readonly targetIp: string;\n /** This port is the port that the client connects to. */\n readonly targetPort: number;\n readonly clientIp: string;\n readonly netns: {\n readonly client: number;\n readonly target: number;\n readonly hops?: Readonly<Record<string, number>>;\n };\n /** This record is where each socket of a topology is, or null for a direct pair. */\n readonly topology: RunTopology | null;\n /** These are the lines of the routers of a topology, in sequence, each with the name of its hop. A direct pair has none. */\n readonly middlebox: readonly MiddleboxEvent[];\n /** These are the lines of a target that writes them (`Target.lines`), in sequence. Another target has none. */\n readonly server: readonly ProbeEvent[];\n /** This method adds a toxic to the Toxiproxy hop of a topology, or removes it with null. The stamps of the injector bracket it. */\n toxic(toxic: Toxic | null): Promise<{ t0: number; t1: number }>;\n /** This method makes the target close the connection of each client, with the command of the target. */\n serverClose(): Promise<void>;\n /**\n * This method starts an agent in the network namespace of the target, and in its process\n * namespace with `pid`. Its command keeps it up, for example `sleep infinity`.\n */\n agent(image: string, command: readonly string[], options?: { readonly pid?: boolean }): Promise<Agent>;\n /** This method starts a sibling, and waits for a line of its log. */\n sibling(image: string, command: readonly string[], ready: string): Promise<Sibling>;\n /** This method starts a command in the target, and gives its standard output. */\n exec(argv: readonly string[]): Promise<string>;\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method sets the settings of the target in it before a client connects, and reads them back. */\n configure(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method sets the sysctls of the target namespace through a privileged sidecar there, and reads them back. */\n targetSysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method runs each command in the namespace of the client and in the namespace of the target. */\n namespaceSetup(commands: readonly (readonly string[])[]): Promise<void>;\n /** This method sets sysctls of the host through a privileged sidecar on the network of the host, and reads them back. */\n hostSysctl(settings: readonly HostSysctl[]): Promise<void>;\n /** This method puts back each value that `hostSysctl` changed, once, and gives the record of each. Closing the lab also does it. */\n restoreHost(): Promise<readonly HostSetting[]>;\n /**\n * This method applies a fault between the client and the target, by default from the namespace\n * of the target. The fault is a black hole, or a reset that answers the next segment of the\n * client. At a proxy of a topology, the rules face the peer of the proxy on one side. The stamps\n * of the injector bracket it.\n */\n fault(\n kind: NetworkFault,\n at?: FaultPlace,\n options?: FaultOptions,\n ): Promise<{ t0: number; t1: number }>;\n /** This method removes a fault. */\n lift(kind: NetworkFault, at?: FaultPlace, options?: FaultOptions): Promise<void>;\n /**\n * This method puts tc netem on the egress of a namespace, for example \"delay 20ms\" or \"loss 5%\",\n * or removes it with null. At a hop, it is the egress of the device of the hop toward one side.\n * The stamps of the injector bracket it.\n */\n netem(spec: string | null, at?: FaultPlace): Promise<{ t0: number; t1: number }>;\n /**\n * This method sets the TSO, GSO and GRO of a namespace. With them off, netem and a length match\n * act on segments, not on GSO super-packets of up to 64 KB. At a hop, it sets the two devices of the hop.\n */\n offload(on: boolean, at?: FaultPlace): Promise<void>;\n /** This method stops the server process in the target with SIGKILL, with the command of the target. */\n kill(): Promise<void>;\n /**\n * This method resolves the neighbors of the path in the two directions, with a ping from each\n * namespace. Without it, the first connection of an environment waits for ARP. Under a netem\n * delay, that wait is one more delayed round, and its round trip and RTO are longer.\n */\n warm(): Promise<void>;\n /** This method runs commands in the target before a client connects, each as argv. */\n setup(commands: ReadonlyArray<readonly string[]>): Promise<void>;\n /**\n * This method stops a black hole at an instant on the monotonic clock of the VM. The injector\n * waits for that instant in the VM, thus the length of a stall does not include the latency of\n * a docker exec. Stamps bracket it, as for a fault.\n */\n heal(at: FaultPlace, when: number): Promise<{ t0: number; t1: number }>;\n /**\n * This method removes what the two kernels learned from their earlier connections. These are\n * the TCP metrics that each kernel keeps for a peer address when a connection closes. These metrics set the\n * first round trip of the next connection, and thus its RTO. A run with these metrics is not\n * independent of the run before it.\n */\n forget(): Promise<void>;\n /** This part is the routed fabric of a lab with `Topology.fabric`. */\n readonly fabric?: FabricLab;\n /** This method freezes the target with the cgroup freezer: its process stops, and its kernel continues to answer. */\n freeze(): Promise<void>;\n thaw(): Promise<void>;\n /**\n * This method sends a signal to the server process of the target (`Target.program`), at once or\n * at an instant of the VM. A sidecar in the network and process namespaces of the target sends\n * it, and the injector stamps it. The lab starts that sidecar at the first signal.\n */\n signal(signal: \"STOP\" | \"CONT\" | \"KILL\", at?: number): Promise<{ t0: number; t1: number }>;\n /**\n * This method applies an event at a proxy hop (`HopEvent`), or its undo. A signal goes from a\n * sidecar in the network and process namespaces of the hop. The lab starts that sidecar at the\n * first signal of the hop. A query goes from the injector of the hop to its console on 127.0.0.1. The\n * injector stamps each one. An event with no undo gives null for its undo. A signal can wait for an\n * instant on CLOCK_MONOTONIC (`at`), as the thaw at the end of a hold does.\n */\n event(event: HopEvent, undo?: boolean, at?: number): Promise<{ t0: number; t1: number } | null>;\n /** This method starts the client with `args`. Each file is in its container before it starts. */\n probe(args: readonly string[], files?: ReadonlyArray<{ readonly content: string; readonly target: string }>): Promise<Probe>;\n /**\n * This method waits for the next clock line of the prober, which gives the count of lost\n * records. It gives null when no clock line comes in 5 s, because then nothing tells the count.\n */\n settle(): Promise<number | null>;\n manifest(\n sysctls: Readonly<Record<string, string>>,\n settings?: Readonly<Record<string, string>>,\n targetSysctls?: Readonly<Record<string, string>>,\n ): Promise<Manifest>;\n close(): Promise<void>;\n}\n\n/** This function makes a container share the process namespace of another container, for example `container:<id>`. */\nexport const withPid = <T extends Testcontainers.GenericContainer>(container: T, mode: string): T => {\n (container as unknown as { hostConfig: { PidMode?: string } }).hostConfig.PidMode = mode;\n return container;\n};\n\n/** This container class can share the process namespace of another container. */\nconst shared = (Base: typeof Testcontainers.GenericContainer) =>\n class extends Base {\n withPidMode(mode: string): this {\n (this as unknown as { hostConfig: { PidMode?: string } }).hostConfig.PidMode = mode;\n return this;\n }\n };\n\n/**\n * This function gives the content of a file of a proxy. Each {{next}} becomes the address and the\n * port of the next hop. Each {{next.host}} and {{next.port}} becomes one of the two.\n */\nexport const templated = (content: string, next: string): string => {\n const at = next.lastIndexOf(\":\");\n return content\n .replaceAll(\"{{next.host}}\", next.slice(0, at))\n .replaceAll(\"{{next.port}}\", next.slice(at + 1))\n .replaceAll(\"{{next}}\", next);\n};\n\n/** This function gives the JSON body of a toxic for the API of Toxiproxy. Each toxic of a cell has the name `fault`. */\nexport const toxicBody = (toxic: Toxic): string =>\n JSON.stringify({\n name: \"fault\",\n type: toxic.type,\n stream: toxic.stream,\n toxicity: 1,\n attributes: toxic.attributes,\n });\n\n/**\n * This function gives the routes of a chain: for each router, the networks after it, which the\n * element before it reaches through it. Element 0 is the client, and element k is hop k - 1. Network\n * j is the network between element j and element j + 1.\n */\nexport const routesOf = (\n hops: readonly Pick<Hop, \"kind\">[],\n): Array<{ readonly from: number; readonly via: number; readonly networks: readonly number[] }> =>\n hops.flatMap((hop, at) =>\n hop.kind === \"router\"\n ? [\n {\n from: at,\n via: at + 1,\n networks: Array.from({ length: hops.length - at }, (_, k) => at + 1 + k),\n },\n ]\n : [],\n );\n\n/**\n * This function gives the endpoint that an element connects to: the first element after it that\n * is not a router. Element 0 is the client, element k is hop k - 1, and the last element is the target.\n */\nexport const endpointAfter = (hops: readonly Pick<Hop, \"kind\">[], element: number): number => {\n let at = element + 1;\n while (at <= hops.length && hops[at - 1]!.kind === \"router\") at += 1;\n return at;\n};\n\n// each container here is a holder, a probe or the prober: nothing drains, thus the stop is immediate\nexport const STOP = { timeout: 0 };\n\n/** These are the values of CONFIG_HZ that Linux offers. */\nconst RATES: readonly number[] = [100, 250, 300, 1000];\n\n/**\n * This function gives HZ from two readings of /proc/timer_list, one second apart: its `now at`\n * time in ns and its jiffies. It gives the nearest rate that Linux offers, or null when the\n * measurement is more than 5 % from each of them.\n */\nexport const hzOf = (first: { now: number; jiffies: number }, second: { now: number; jiffies: number }): string | null => {\n const seconds = (second.now - first.now) / 1e9;\n if (!(seconds > 0)) return null;\n const rate = (second.jiffies - first.jiffies) / seconds;\n const nearest = RATES.reduce((best, each) => (Math.abs(each - rate) < Math.abs(best - rate) ? each : best));\n return Math.abs(nearest - rate) / nearest <= 0.05 ? String(nearest) : null;\n};\n\n/** This function measures HZ in a privileged container: jiffies against the time of the kernel, one second apart. */\nconst measuredHz = async (container: StartedTestContainer): Promise<string | null> => {\n const read = \"awk '/^now at/ {now=$3} /^jiffies:/ {print now, $2; exit}' /proc/timer_list\";\n const text = await output(container, [\"sh\", \"-c\", `${read}; sleep 1; ${read}`]).catch(() => \"\");\n const values = text.split(/\\s+/).filter((each) => each !== \"\").map(Number);\n if (values.length !== 4 || values.some((each) => !Number.isFinite(each))) return null;\n return hzOf({ now: values[0]!, jiffies: values[1]! }, { now: values[2]!, jiffies: values[3]! });\n};\n\nexport const output = async (container: StartedTestContainer, argv: string[]): Promise<string> => {\n const result = await container.exec(argv);\n if (result.exitCode !== 0)\n throw new Error(`${argv.join(\" \")} exited ${result.exitCode}: ${result.output.trim()}`);\n return result.stdout.trim();\n};\n\n/** This function gives the inode of the network namespace of a container: net:[4026532583]. */\nexport const netnsOf = async (container: StartedTestContainer): Promise<number> => {\n const link = await output(container, [\"readlink\", \"/proc/self/ns/net\"]);\n const inode = /^net:\\[(\\d+)\\]$/.exec(link)?.[1];\n if (inode === undefined) throw new Error(`not a network namespace: ${link}`);\n return Number(inode);\n};\n\n/** This function gives the build record of a source as a part of a manifest: `{ build }`, or nothing for an image that the harness pulls. */\nexport const buildOf = (source: Parameters<typeof buildRecordOf>[0]): { readonly build?: BuildRecord } => {\n const build = buildRecordOf(source);\n return build === undefined ? {} : { build };\n};\n\n/** This function gives the version of the harness and the build of its image, as a part of the harness record of a manifest. */\nexport const harnessRecord = (): { readonly version: string; readonly build?: BuildRecord } => ({\n version: harnessVersion(),\n ...buildOf(shippedSource(\"harness\")),\n});\n\n/**\n * This function gives the record of the client of a run that the harness ships, for a manifest:\n * its kind, its image, and its build.\n */\nexport const shippedClientRecord = (kind: Client, image: string): Manifest[\"client\"] => ({ kind, image, ...buildOf(SHIPPED_CLIENTS[kind].image) });\n\n/**\n * This function gives the image and the command of the client of each run, its kind for the\n * manifest, and the source of its image. A client by its name is a client that the harness ships\n * (`SHIPPED_CLIENTS`). A client image gives its own image and command.\n */\nexport const clientOf = async (\n kind: Client | ClientImage,\n): Promise<{\n clientImage: string;\n command: readonly string[];\n clientKind: Client | \"image\";\n capabilities?: readonly ClientCapability[];\n source?: ImageSource;\n}> => {\n const client = typeof kind === \"string\" ? (Object.hasOwn(SHIPPED_CLIENTS, kind) ? SHIPPED_CLIENTS[kind] : undefined) : kind;\n if (client === undefined) throw new Error(`the harness ships no client ${String(kind)}`);\n return {\n clientImage: await imageOf(client.image),\n command: client.command,\n clientKind: typeof kind === \"string\" ? kind : \"image\",\n ...(client.capabilities === undefined || client.capabilities.length === 0 ? {} : { capabilities: client.capabilities }),\n ...(typeof client.image === \"string\" ? {} : { source: client.image }),\n };\n};\n\n/** These are the containers of one hop of a lab, and the addresses that its rules and the measurement read. */\ninterface HopIn {\n readonly hop: Hop;\n /** This container is the hop itself: the router, or the stock proxy. */\n readonly box: StartedTestContainer;\n /** This sidecar shares the namespace of the hop: the injector of its faults and its toxics. */\n readonly injector: StartedTestContainer;\n /** This record is the address of the hop on the network of each of its sides. */\n readonly ip: { readonly client: string; readonly target: string };\n /** These are the peers of the hop: an address on the side of the client, and an address with its port toward the target. */\n readonly peer: { readonly client: string; readonly target: string };\n /** These are the devices of the hop toward each side, as its routes give them. The rules of a router and netem at a hop face one. */\n readonly devices: { readonly client: string; readonly target: string };\n readonly netns: number;\n sysctls: Record<string, string>;\n}\n\n/** This function gives the device of a route from its line in `ip -o route get`: \"10.0.0.2 dev eth0 src …\". */\nexport const deviceOf = (route: string): string => {\n const device = /\\bdev (\\S+)/.exec(route)?.[1];\n if (device === undefined) throw new Error(`no device in the route: ${route}`);\n return device;\n};\n\n/**\n * This function opens one environment:\n * - a chain of new networks, and the stock target on the last one. A direct pair has one network.\n * - a client that holds its own network namespace, with a privileged sidecar in it for its\n * sysctls and its routes. Docker Desktop keeps /proc/sys read-only in a container that operates\n * without privileges.\n * - each hop of the topology, on the network of each of its sides. A hop is a router, or a stock\n * proxy with an injector sidecar in its namespace.\n * - an injector sidecar in the namespace of the target.\n * - the prober, a privileged container that loads the kernel program and watches the namespace of\n * the client, of the target and of each hop.\n *\n * The client of each run is its own container in the namespace of the client. It is the TCP\n * client of the harness, a driver from its own image (ioredis on Node), or an image that the\n * caller gives. Each prints the same lines.\n *\n * The client reaches the networks after a router through that router, by a route that its\n * privileged sidecar adds. A router translates the address of the side of the client, thus the\n * target and each later hop see the router as the peer.\n */\nexport const openLab = async (\n target: Target,\n kind: Client | ClientImage = \"tcp\",\n topology?: Topology,\n): Promise<Lab> => {\n const image = await harnessImage();\n const { clientImage, command, clientKind, capabilities, source } = await clientOf(kind);\n const hops = topology?.hops ?? [];\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n const networks: StartedNetwork[] = [];\n // the lines of a target that writes them, on the clock of the VM\n const serverLines = lines<ProbeEvent>();\n // the values of the host that this lab changed, which each path out of the lab puts back\n let restoreHost: () => Promise<readonly HostSetting[]> = () => Promise.resolve([]);\n let fabric: FabricLab | undefined;\n const close = async () => {\n // a value of the host outlives the lab: the failure of the restore is the failure of the close, after the containers stop\n const restored = await restoreHost().then(\n () => null,\n (error: unknown) => error,\n );\n await fabric?.close();\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n for (const network of networks.reverse()) await network.stop().catch(() => undefined);\n if (restored !== null) throw restored;\n };\n /** This function gives the address of a container on a network, as Docker has it at this time. A container can join a network after its start. */\n const ipOn = async (container: StartedTestContainer, network: StartedNetwork): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network.getName()}`);\n return ip;\n };\n const join = (container: StartedTestContainer, network: StartedNetwork) =>\n runtime.container.connectToNetwork(\n runtime.container.getById(container.getId()),\n runtime.network.getById(network.getId()),\n [],\n );\n const subnetOf = async (network: StartedNetwork): Promise<string> => {\n const info = await runtime.network.getById(network.getId()).inspect();\n const subnet = (info as { IPAM?: { Config?: Array<{ Subnet?: string }> } }).IPAM?.Config?.[0]?.Subnet;\n if (subnet === undefined) throw new Error(`${network.getName()} has no subnet`);\n return subnet;\n };\n try {\n // network j joins element j and element j + 1: 0 is the client, i + 1 is hop i, the last is the target\n for (let at = 0; at <= hops.length; at += 1) networks.push(await new Network().start());\n const last = networks[hops.length]!;\n // a stock image, or an image of the harness that holds the script of the server\n const targetImage = await targetImageOf(target);\n let stock = new GenericContainer(targetImage)\n .withNetwork(last)\n .withWaitStrategy(Wait.forLogMessage(target.ready));\n // the files of the target go in before it starts, for example the script of a server on a stock image\n if (target.files !== undefined)\n stock = stock.withCopyContentToContainer(\n Object.entries(target.files).map(([path, content]) => ({ content, target: path })),\n );\n if (target.lines === true) stock = stock.withLogConsumer(serverLines.consume);\n // a holder command keeps the container up when a fin fault kills the server process\n const server = await (\n target.command === undefined ? stock : stock.withCommand([...target.command])\n ).start();\n opened.push(server);\n const serverIp = await ipOn(server, last);\n\n // the hops, from the target to the client: each proxy gets the address of the endpoint after it\n const middlebox: MiddleboxEvent[] = [];\n // the last lines of the output of each proxy, and their count, for a write that the proxy confirms\n const hopOutput = new Map<string, { lines: string[]; total: number }>();\n const inChain: HopIn[] = [];\n const endpointOf = (element: number): string => {\n const at = endpointAfter(hops, element);\n if (at === hops.length + 1) return `${serverIp}:${target.port}`;\n const proxy = inChain[at - 1]!;\n return `${proxy.ip.client}:${(proxy.hop as ProxyHop).port}`;\n };\n for (let at = hops.length - 1; at >= 0; at -= 1) {\n const hop = hops[at]!;\n const [clientSide, targetSide] = [networks[at]!, networks[at + 1]!];\n if (hop.kind === \"router\") {\n const seen = lines<MiddleboxEvent>((line) => middlebox.push({ ...line, hop: hop.name }));\n // the router is privileged: it sets the sysctls of its own namespace, conntrack's among them\n const box = await new GenericContainer(await routerImage())\n .withNetwork(clientSide)\n .withPrivilegedMode()\n .withEnvironment({\n FORM: hop.form,\n IDLE: String(valueIn(hop.idle, \"s\")),\n PUMP: String(valueIn(hop.pump ?? PUMP, \"s\")),\n SLOW: String(valueIn(LISTING, \"s\")),\n })\n .withLogConsumer(seen.consume)\n .start();\n opened.push(box);\n // the router waits for the network of the side of the target, its eth1\n await join(box, targetSide);\n const ready = await seen.until([\"mbx-ready\"], 30_000, `router ${hop.name}`);\n await seen.until(hop.form === \"reset-both\" ? [\"resetter\"] : [\"ct-watch\"], 30_000, `router ${hop.name}`);\n // the injector of a fault at the router: FORWARD rules and netem in its namespace\n const injector = await new GenericContainer(image)\n .withNetworkMode(`container:${box.getId()}`)\n .withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\")\n .start();\n opened.push(injector);\n inChain[at] = {\n hop,\n box,\n injector,\n ip: { client: await ipOn(box, clientSide), target: await ipOn(box, targetSide) },\n peer: { client: \"\", target: endpointOf(at + 1) },\n devices: { client: \"\", target: \"\" },\n netns: await netnsOf(box),\n sysctls: { \"net.netfilter.nf_conntrack_tcp_timeout_established\": String(ready[\"idle\"]) },\n };\n continue;\n }\n const next = endpointOf(at + 1);\n let proxy = new GenericContainer(await imageOf(hop.image)).withNetwork(targetSide);\n if (hop.command !== undefined) proxy = proxy.withCommand([...hop.command]);\n if (hop.environment !== undefined) proxy = proxy.withEnvironment({ ...hop.environment });\n if (hop.files !== undefined)\n proxy = proxy.withCopyContentToContainer(\n Object.entries(hop.files).map(([path, content]) => ({ content: templated(content, next), target: path })),\n );\n if (hop.ready !== undefined) proxy = proxy.withWaitStrategy(Wait.forLogMessage(hop.ready));\n // the last lines of the output of the hop: a hop that does not start tells why\n const tail: string[] = [];\n const output = { lines: [] as string[], total: 0 };\n hopOutput.set(hop.name, output);\n proxy = proxy.withLogConsumer((stream) => {\n let rest = \"\";\n stream.on(\"data\", (chunk: Buffer | string) => {\n const lines = (rest + chunk.toString()).split(\"\\n\");\n rest = lines.pop() ?? \"\";\n for (const line of lines) {\n tail.push(line);\n if (tail.length > TAIL_LINES) tail.shift();\n output.lines.push(line);\n output.total += 1;\n if (output.lines.length > OUTPUT_LINES) output.lines.shift();\n }\n });\n });\n const box = await proxy.start().catch((error: unknown) => {\n throw new Error(`the hop ${hop.name} did not start: ${error instanceof Error ? error.message : String(error)}. Its last lines:\\n${tail.join(\"\\n\")}`);\n });\n opened.push(box);\n await join(box, clientSide);\n const injector = await new GenericContainer(image)\n .withNetworkMode(`container:${box.getId()}`)\n .withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\")\n .start();\n opened.push(injector);\n inChain[at] = {\n hop,\n box,\n injector,\n ip: { client: await ipOn(box, clientSide), target: await ipOn(box, targetSide) },\n peer: { client: \"\", target: next },\n devices: { client: \"\", target: \"\" },\n netns: await netnsOf(injector),\n sysctls: {},\n };\n }\n\n const client = await new GenericContainer(image).withNetwork(networks[0]!).start();\n opened.push(client);\n const admin = await new GenericContainer(image)\n .withNetworkMode(`container:${client.getId()}`)\n .withPrivilegedMode()\n .start();\n opened.push(admin);\n const injector = await new GenericContainer(image)\n .withNetworkMode(`container:${server.getId()}`)\n .withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\")\n .start();\n opened.push(injector);\n // a fabric joins the client and the target by a device of its own: Docker keeps eth0\n if (topology?.fabric !== undefined)\n fabric = await openFabric({\n fabric: topology.fabric,\n image,\n client,\n server,\n admin,\n injector,\n opened,\n output,\n });\n const device = fabric === undefined ? \"eth0\" : FABRIC_DEVICE;\n const clientIp = fabric === undefined ? await ipOn(client, networks[0]!) : FABRIC_CLIENT;\n // the peer of each hop on the side of the client: the element before it, on the network between them\n for (let at = 0; at < inChain.length; at += 1) {\n const before = at === 0 ? clientIp : inChain[at - 1]!.ip.target;\n inChain[at] = { ...inChain[at]!, peer: { ...inChain[at]!.peer, client: before } };\n }\n\n // a privileged sidecar for each proxy that needs one, for its sysctls and its routes\n const admins = new Map<number, StartedTestContainer>();\n const adminOf = async (element: number): Promise<StartedTestContainer> => {\n if (element === 0) return admin;\n const hop = inChain[element - 1]!;\n if (hop.hop.kind === \"router\") return hop.box;\n let found = admins.get(element);\n if (found === undefined) {\n found = await new GenericContainer(image)\n .withNetworkMode(`container:${hop.box.getId()}`)\n .withPrivilegedMode()\n .start();\n opened.push(found);\n admins.set(element, found);\n }\n return found;\n };\n for (const route of routesOf(hops)) {\n const where = await adminOf(route.from);\n const via = inChain[route.via - 1]!.ip.client;\n for (const network of route.networks)\n await output(where, [\"ip\", \"route\", \"replace\", await subnetOf(networks[network]!), \"via\", via]);\n }\n for (let at = 0; at < inChain.length; at += 1) {\n const hop = inChain[at]!;\n // the device toward each side, as the routes of the hop give it\n const toward = async (address: string) =>\n deviceOf(await output(hop.injector, [\"ip\", \"-o\", \"route\", \"get\", address.split(\":\")[0]!]));\n inChain[at] = { ...hop, devices: { client: await toward(hop.peer.client), target: await toward(hop.peer.target) } };\n if (hop.hop.sysctls === undefined) continue;\n // a router is privileged and sets its own sysctls. A proxy has a privileged sidecar for them\n const where = await adminOf(at + 1);\n const settings = Object.entries(hop.hop.sysctls).map(([key, value]) => `${key}=${value}`);\n await output(where, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n for (const key of Object.keys(hop.hop.sysctls)) hop.sysctls[key] = await output(where, [\"sysctl\", \"-n\", key]);\n }\n\n const netns = {\n client: await netnsOf(admin),\n target: await netnsOf(injector),\n ...(inChain.length === 0\n ? {}\n : { hops: Object.fromEntries(inChain.map((hop) => [hop.hop.name, hop.netns])) }),\n };\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\n \"/opt/harness/prober\",\n String(netns.client),\n String(netns.target),\n ...inChain.map((hop) => String(hop.netns)),\n ])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n const first = endpointAfter(hops, 0);\n const targetIp = fabric !== undefined ? FABRIC_TARGET : first === hops.length + 1 ? serverIp : inChain[first - 1]!.ip.client;\n const targetPort = first === hops.length + 1 ? target.port : (inChain[first - 1]!.hop as ProxyHop).port;\n const targetPeer = inChain.length === 0 ? clientIp : inChain.at(-1)!.ip.target;\n const placed: RunTopology | null =\n inChain.length === 0\n ? null\n : {\n targetPeer,\n hops: Object.fromEntries(\n inChain.map((hop) => [hop.hop.name, { netns: hop.netns, client: hop.peer.client, target: hop.peer.target }]),\n ),\n };\n const paused = runtime.container.getById(server.getId());\n let targetAdmin: StartedTestContainer | undefined;\n let signaller: StartedTestContainer | undefined;\n // the sidecars that signal the program of a hop, by the name of the hop\n const hopSignallers = new Map<string, StartedTestContainer>();\n const hopNamed = (name: string): HopIn => {\n const found = inChain.find((hop) => hop.hop.name === name);\n if (found === undefined) throw new Error(`the topology has no hop ${name}`);\n return found;\n };\n /**\n * This function gives the namespace and the peer of the rules of a fault at a place, and the\n * other arguments of the injector. At a proxy, the rules are INPUT and OUTPUT rules, which act\n * on its sockets. A router forwards past INPUT and OUTPUT, thus its rules are FORWARD rules on\n * its device toward the side (`--via`).\n */\n const hopPlace = (at: FaultPlace): HopPlace => {\n if (!isHopPlace(at)) throw new Error(`a lab of a topology has no part ${JSON.stringify(at)}: a group cell opens a group lab`);\n return at;\n };\n const placeOf = (place: FaultPlace): [StartedTestContainer, string, string[]] => {\n if (place === \"client\") return [admin, targetIp, []];\n if (place === \"target\") return [injector, targetPeer, []];\n const at = hopPlace(place);\n const hop = hopNamed(at.hop);\n const peer = at.toward === \"client\" ? hop.peer.client : hop.peer.target.split(\":\")[0]!;\n const via = hop.hop.kind === \"router\" ? [\"--via\", hop.devices[at.toward]] : [];\n return [hop.injector, peer, via];\n };\n /** This function gives the namespace and the device of netem at a place: an end, or the device of a hop toward a side. */\n const deviceAt = (place: FaultPlace): [StartedTestContainer, string] => {\n if (place === \"client\") return [admin, device];\n if (place === \"target\") return [injector, device];\n const at = hopPlace(place);\n const hop = hopNamed(at.hop);\n return [hop.injector, hop.devices[at.toward]];\n };\n const toxiproxy = (): HopIn & { hop: ProxyHop & { api: { port: number; proxy: string } } } => {\n const found = inChain.find((hop) => hop.hop.kind === \"proxy\" && hop.hop.api !== undefined);\n if (found === undefined) throw new Error(\"the topology has no hop with the API of Toxiproxy\");\n return found as HopIn & { hop: ProxyHop & { api: { port: number; proxy: string } } };\n };\n const stamped = async (where: StartedTestContainer, argv: string[]) => {\n const stamp = JSON.parse((await output(where, argv)).split(\"\\n\").at(-1)!) as { t0: number; t1: number };\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const proxies = inChain.filter((hop) => hop.hop.kind === \"proxy\");\n let hostAdmin: StartedTestContainer | undefined;\n const hostChanges: HostSetting[] = [];\n let hostDone: readonly HostSetting[] | undefined;\n restoreHost = async () => {\n if (hostDone !== undefined) return hostDone;\n const restored: HostSetting[] = [];\n for (const change of [...hostChanges].reverse()) {\n await output(hostAdmin!, [\"sysctl\", \"-q\", \"-w\", `${change.name}=${change.before}`]);\n const read = await output(hostAdmin!, [\"sysctl\", \"-n\", change.name]);\n if (read !== change.before) throw new Error(`${change.name} reads ${read} after the restore, not ${change.before}`);\n restored.unshift({ ...change, restored: read });\n }\n hostDone = restored;\n return restored;\n };\n\n return {\n serverIp,\n targetIp,\n targetPort,\n clientIp,\n netns,\n topology: placed,\n middlebox,\n server: serverLines.seen,\n kernel: records.seen,\n ...(fabric === undefined ? {} : { fabric }),\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values))\n read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n async targetSysctl(values) {\n const read: Record<string, string> = {};\n if (Object.keys(values).length === 0) return read;\n // privileged, and only when a cell asks for it: otherwise the namespace of the target stays as it is\n targetAdmin ??= await new GenericContainer(image)\n .withNetworkMode(`container:${server.getId()}`)\n .withPrivilegedMode()\n .start();\n opened.push(targetAdmin);\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n await output(targetAdmin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n for (const key of Object.keys(values))\n read[key] = await output(targetAdmin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n async namespaceSetup(commands) {\n for (const command of commands) {\n await output(admin, [...command]);\n await output(injector, [...command]);\n }\n },\n async hostSysctl(settings) {\n if (settings.length === 0) return;\n // privileged and on the network of the host, and only when a cell asks for it: a value of the host applies to each container\n if (hostAdmin === undefined) {\n hostAdmin = await new GenericContainer(image).withNetworkMode(\"host\").withPrivilegedMode().start();\n opened.push(hostAdmin);\n }\n for (const { name, value, guard } of settings) {\n if (guard !== undefined) {\n const reads = Number(await output(hostAdmin, [\"sysctl\", \"-n\", guard.name]));\n if (!(reads <= guard.atMost)) throw new Error(`${guard.name} of the host reads ${reads}, above ${guard.atMost}`);\n }\n const before = await output(hostAdmin, [\"sysctl\", \"-n\", name]);\n // recorded first: a write that fails half way still has its restore\n hostChanges.push({ name, before, set: value, restored: null });\n await output(hostAdmin, [\"sysctl\", \"-q\", \"-w\", `${name}=${value}`]);\n const set = await output(hostAdmin, [\"sysctl\", \"-n\", name]);\n if (set !== value) throw new Error(`${name} of the host reads ${set} after the write, not ${value}`);\n }\n },\n restoreHost: () => restoreHost(),\n async configure(values) {\n const read: Record<string, string> = {};\n if (Object.keys(values).length === 0) return read;\n const how = target.settings;\n if (how === undefined) throw new Error(`${target.image} names no way to set its settings`);\n for (const [name, value] of Object.entries(values)) {\n await output(server, [...how.set, name, value]);\n read[name] = (await output(server, [...how.get, name])).split(\"\\n\").at(-1) ?? \"\";\n }\n return read;\n },\n async fault(kind, at = \"target\", options = {}) {\n const [where, peer, via] = placeOf(at);\n return stamped(where, [\"/opt/harness/inject\", kind, options.peers?.join(\",\") ?? peer, ...optionArgs(options), ...via]);\n },\n async lift(kind, at = \"target\", options = {}) {\n const [where, peer, via] = placeOf(at);\n await output(where, [\"/opt/harness/inject\", LIFT[kind], options.peers?.join(\",\") ?? peer, ...optionArgs(options), ...via]);\n },\n async netem(spec, at = \"target\") {\n const [where, device] = deviceAt(at);\n const args =\n spec === null\n ? [\"/opt/harness/inject\", \"clear-netem\", device]\n : [\"/opt/harness/inject\", \"netem\", device, ...spec.split(/\\s+/)];\n return stamped(where, args);\n },\n async offload(on, at = \"target\") {\n // at a hop, the two devices: a router merges what it receives (GRO) and forwards it whole\n const devices = isHopPlace(at) ? Object.values(hopNamed(at.hop).devices) : [deviceAt(at)[1]];\n const [where] = deviceAt(at);\n for (const device of devices)\n await output(where, [\"/opt/harness/inject\", \"offload\", device, on ? \"on\" : \"off\"]);\n },\n async toxic(toxic) {\n const hop = toxiproxy();\n const api = `127.0.0.1:${hop.hop.api.port}`;\n const path = `/proxies/${hop.hop.api.proxy}/toxics`;\n return stamped(\n hop.injector,\n toxic === null\n ? [\"/opt/harness/inject\", \"http\", \"DELETE\", api, `${path}/fault`]\n : [\"/opt/harness/inject\", \"http\", \"POST\", api, path, toxicBody(toxic)],\n );\n },\n async serverClose() {\n if (target.close === undefined) throw new Error(`${target.image} names no way to close its clients`);\n await output(server, [...target.close]);\n },\n async exec(argv) {\n return output(server, [...argv]);\n },\n async sibling(siblingImage, argv, ready) {\n const started = await new GenericContainer(siblingImage)\n .withNetwork(last)\n .withWaitStrategy(Wait.forLogMessage(ready))\n .withCommand([...argv])\n .start();\n opened.push(started);\n return {\n ip: await ipOn(started, last),\n netns: await netnsOf(started),\n exec: (command) => output(started, [...command]),\n };\n },\n async agent(agentImage, argv, options = {}) {\n const Shared = shared(GenericContainer);\n const seen = lines<{ readonly ev: string }>();\n let started = new Shared(agentImage)\n .withNetworkMode(`container:${server.getId()}`)\n .withCommand([...argv])\n .withLogConsumer(seen.consume);\n if (options.pid === true) started = started.withPidMode(`container:${server.getId()}`);\n const container = await started.start();\n opened.push(container);\n return {\n lines: seen,\n exec: (args) => output(container, [...args]),\n stop: () =>\n container\n .stop(STOP)\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n async kill() {\n if (target.kill === undefined) throw new Error(`${target.image} names no way to kill its server`);\n await output(server, [...target.kill]);\n },\n async warm() {\n await output(admin, [\"ping\", \"-c\", \"2\", \"-W\", \"2\", targetIp]);\n await output(injector, [\"ping\", \"-c\", \"2\", \"-W\", \"2\", targetPeer]);\n for (const hop of proxies)\n await output(hop.injector, [\"ping\", \"-c\", \"2\", \"-W\", \"2\", hop.peer.target.split(\":\")[0]!]);\n },\n async setup(commands) {\n for (const argv of commands) await output(server, [...argv]);\n },\n async heal(at, when) {\n const [where, peer, via] = placeOf(at);\n return stamped(where, [\"/opt/harness/inject\", \"clear\", peer, \"--at\", String(Math.round(when)), ...via]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n await output(injector, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n for (const hop of proxies) await output(hop.injector, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n freeze: () => paused.pause().then(() => undefined),\n thaw: () => paused.unpause().then(() => undefined),\n async signal(signal, at) {\n if (target.program === undefined) throw new Error(`${target.image} names no server process to signal`);\n // only when a cell asks for it: otherwise no sidecar shares the process namespace of the target\n signaller ??= await withPid(\n new GenericContainer(image).withNetworkMode(`container:${server.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${server.getId()}`,\n ).start();\n if (!opened.includes(signaller)) opened.push(signaller);\n const when = at === undefined ? [] : [\"--at\", String(Math.round(at))];\n return stamped(signaller, [\"/opt/harness/inject\", \"signal\", target.program, signal, ...when]);\n },\n async event(event, undo = false, at) {\n const hop = hopNamed(event.hop);\n if (hop.hop.kind !== \"proxy\") throw new Error(`the hop ${event.hop} is a router: an event goes to a proxy`);\n const program = hop.hop.program;\n // only when a cell asks for it: otherwise no sidecar shares the process namespace of the hop.\n // SYS_PTRACE lets a write reach the root of the program through /proc/PID/root\n const sidecarOf = async (): Promise<StartedTestContainer> => {\n let sidecar = hopSignallers.get(event.hop);\n if (sidecar === undefined) {\n sidecar = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${hop.box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\", \"SYS_PTRACE\"),\n `container:${hop.box.getId()}`,\n ).start();\n hopSignallers.set(event.hop, sidecar);\n opened.push(sidecar);\n }\n return sidecar;\n };\n if (\"signal\" in event) {\n if (undo) return null;\n if (program === undefined) throw new Error(`the hop ${event.hop} names no program to signal`);\n const when = at === undefined ? [] : [\"--at\", String(Math.round(at))];\n return stamped(await sidecarOf(), [\"/opt/harness/inject\", \"signal\", program, event.signal, ...when]);\n }\n if (\"write\" in event) {\n const content = undo ? event.write.undo : event.write.content;\n if (content === undefined) return null;\n if (program === undefined) throw new Error(`the hop ${event.hop} names no program whose root a write reaches`);\n const output = hopOutput.get(event.hop);\n const before = output?.total ?? 0;\n const stamp = await stamped(await sidecarOf(), [\"/opt/harness/inject\", \"write\", program, event.write.path, content]);\n const confirm = event.write.confirm;\n if (confirm !== undefined) {\n // the hop confirms the change by a new line of its output, for example the log line of its reload\n const started = Date.now();\n const confirmed = (): boolean => {\n if (output === undefined) return false;\n const fresh = Math.min(output.total - before, output.lines.length);\n return output.lines.slice(output.lines.length - fresh).some((line) => line.includes(confirm));\n };\n while (!confirmed()) {\n if (Date.now() - started > CONFIRM_MS)\n throw new Error(`the hop ${event.hop} did not confirm the write of ${event.write.path}: no line \"${confirm}\" in ${CONFIRM_MS / 1000} s`);\n await sleep(50);\n }\n }\n return stamp;\n }\n const query = undo ? event.console.undo : event.console.query;\n if (query === undefined) return null;\n const { port, user, database } = event.console;\n return stamped(hop.injector, [\"/opt/harness/inject\", \"query\", `127.0.0.1:${port}`, user, database, query]);\n },\n async probe(args, files = []) {\n const events = lines<ProbeEvent>();\n const prober = new GenericContainer(clientImage)\n .withNetworkMode(`container:${client.getId()}`)\n .withCommand([...command, ...args])\n .withCopyContentToContainer(files.map((file) => ({ ...file })))\n .withLogConsumer(events.consume);\n const container = await (capabilities === undefined ? prober : prober.withAddedCapabilities(...capabilities)).start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n go: () => output(container, [\"touch\", \"/tmp/go\"]).then(() => undefined),\n freeze: () =>\n runtime.container\n .getById(container.getId())\n .pause()\n .then(() => undefined),\n thaw: () =>\n runtime.container\n .getById(container.getId())\n .unpause()\n .then(() => undefined),\n kill: () =>\n runtime.container\n .getById(container.getId())\n .kill({ signal: \"SIGKILL\" })\n .then(() => undefined),\n // a killed client has no container to stop\n stop: () =>\n container\n .stop(STOP)\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n async settle() {\n // the prober drains its ring each 20 ms, and it writes a clock line each second\n const after = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const started = Date.now();\n const look = () => {\n const line = records.seen.slice(after).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - started > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls, settings = {}, targetSysctls = {}) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) =>\n runtime.container.inspect(runtime.container.getById(container.getId()));\n const hopsOf = async (): Promise<ManifestHop[]> => {\n const out: ManifestHop[] = [];\n for (const hop of inChain) {\n const box = hop.hop;\n out.push({\n name: box.name,\n kind: box.kind,\n image: box.kind === \"router\" ? await routerImage() : await imageOf(box.image),\n id: (await inspect(hop.box)).Image,\n settings:\n box.kind === \"router\"\n ? {\n form: box.form,\n idle: String(valueIn(box.idle, \"s\")),\n pump: String(valueIn(box.pump ?? PUMP, \"s\")),\n slow: String(valueIn(LISTING, \"s\")),\n packages: (await output(hop.box, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort().join(\" \"),\n }\n : { ...box.settings, ...box.files },\n sysctls: hop.sysctls,\n });\n }\n return out;\n };\n return {\n kernel: await output(client, [\"uname\", \"-r\"]),\n architecture: await output(client, [\"uname\", \"-m\"]),\n ...(await (async () => {\n const configured = /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1];\n if (configured !== undefined) return { hz: configured, hzFrom: \"config\" as const };\n const measured = await measuredHz(admin);\n return measured === null ? { hz: null } : { hz: measured, hzFrom: \"measured\" as const };\n })()),\n boot_id: await output(client, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n substrate: substrateHere(fabric === undefined ? \"E1\" : \"E3\"),\n ...(fabric === undefined ? {} : { fabric: fabric.manifest() }),\n target: {\n image: targetImage,\n ...(target.subject === undefined ? {} : { subject: target.subject, base: target.image }),\n id: (await inspect(server)).Image,\n settings,\n sysctls: targetSysctls,\n ...(target.files === undefined\n ? {}\n : {\n files: Object.fromEntries(\n Object.entries(target.files).map(([path, content]) => [path, createHash(\"sha256\").update(content).digest(\"hex\")]),\n ),\n }),\n ...(serverLines.seen[0] === undefined ? {} : { first: serverLines.seen[0] }),\n ...buildOf(targetSourceOf(target)),\n },\n harness: {\n image,\n id: (await inspect(client)).Image,\n packages: (await output(client, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n ...harnessRecord(),\n },\n client: {\n kind: clientKind,\n image: clientImage,\n ...(capabilities === undefined ? {} : { capabilities }),\n ...(source === undefined ? {} : { source, ...buildOf(source) }),\n },\n netns,\n sysctls,\n ...(inChain.length === 0 ? {} : { hops: await hopsOf() }),\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, KernelRecord, Pair, Run } from \"./cell.ts\";\nimport { targetImageOf } from \"./image.ts\";\nimport type { Lab, Probe, Sibling } from \"./lab.ts\";\n\n/**\n * This module is the second server of a pair (`Cell.pair`). The lab of the cell has the primary, the\n * topology in front of it, the injector and the prober. This module adds one standby on the network\n * of the primary, and it does one run:\n *\n * 1. The client writes a stream of sequence numbers through the topology.\n * 2. The fault cuts the primary from the standby, or from each peer. The cut stays to the end.\n * 3. At the end of the hold, the injector stops each process of the primary with SIGKILL.\n * 4. The harness promotes the standby, and reads what it holds.\n * 5. The harness starts the old primary, and reads what its crash recovery gives.\n *\n * The standby has no way to the WAL of the old primary, because the primary stops under the cut. A\n * promotion cannot be undone, thus each run has its own environment (`Cell.fresh`).\n */\n\n/** This table holds one row for each write of the client. */\nconst TABLE = \"writes\";\n/** This time bounds each wait of the setup of the pair, in ms. */\nconst SETUP_MS = 60_000;\n/** This count is the acknowledged writes before the fault: the stream is steady. */\nconst STEADY = 20;\n/** This time is the wait after the stop of the primary, in ms: each writer sends its last write in it. */\nconst LAST_WRITE_MS = 2_000;\n/** This time bounds the wait for the last line of the client, in ms. */\nconst STOP_MS = 5_000;\n\n/** This text is the line of the log of a standby that serves reads (src/backend/postmaster/postmaster.c:3740). */\nexport const STANDBY_READY: string = \"database system is ready to accept read-only connections\";\n/** This text is the write of the client, with its sequence number. */\nexport const INSERT: string = `INSERT INTO ${TABLE} VALUES ($n)`;\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** This function gives the argv of one statement in psql, on the server in the same container. */\nexport const psql = (statement: string): string[] => [\"psql\", \"-h\", \"127.0.0.1\", \"-U\", \"postgres\", \"-At\", \"-c\", statement];\n\n/** This function gives the command of a standby: a base backup of the primary, then the server in recovery. */\nexport const standbyCommand = (primary: string): string[] => [\n \"sh\",\n \"-c\",\n `chown postgres:postgres \"$PGDATA\"; chmod 0700 \"$PGDATA\"; until gosu postgres pg_basebackup -h ${primary} -U postgres -D \"$PGDATA\" -X stream -c fast -R; do gosu postgres sh -c 'rm -rf \"$PGDATA\"/*'; sleep 0.5; done; exec gosu postgres postgres`,\n];\n\n/** This command starts the old primary again, after the stop of each of its processes. Its crash recovery runs before the wait ends. */\nexport const RESTART: readonly string[] = [\"sh\", \"-c\", 'exec gosu postgres pg_ctl -D \"$PGDATA\" -l /tmp/restart.log -w -t 60 start'];\n\n/** This function reads the output of a query for sequence numbers into a sorted list. */\nexport const numbersOf = (text: string): number[] =>\n text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\")\n .map(Number)\n .sort((a, b) => a - b);\n\n/** This function gives the arguments of the client of a run. */\nexport const pairArgs = (cell: Cell, lab: Pick<Lab, \"targetIp\" | \"targetPort\">): string[] => {\n const pair = cell.pair!;\n const hold = cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\");\n return [\n lab.targetIp,\n String(lab.targetPort),\n \"--mode\",\n \"stream\",\n \"--interval-ms\",\n String(valueIn(pair.interval, \"ms\")),\n \"--writers\",\n String(pair.writers),\n \"--query\",\n INSERT,\n \"--max-s\",\n String(Math.ceil(hold) + 60),\n ...(cell.driverOptions === undefined ? [] : [\"--options\", JSON.stringify(cell.driverOptions)]),\n ];\n};\n\n/** This function gives the peers of the cut of a pair: the standby, or the standby and the peer of the primary in the topology. */\nexport const peersOf = (pair: Pair, standby: string, lab: Pick<Lab, \"topology\" | \"clientIp\">): string[] =>\n pair.cuts === \"standby\" ? [standby] : [standby, lab.topology?.targetPeer ?? lab.clientIp];\n\n/** This function gives the instants of the cancels of a hold, in ns from the fault: equal parts of the hold. */\nexport const cancelsOf = (pair: Pair, holdNs: number): number[] => {\n const count = pair.cancels ?? 0;\n return Array.from({ length: count }, (_, at) => ((at + 1) * holdNs) / (count + 1));\n};\n\n/** This function asks until the primary reports the standby in a state of replication. */\nconst untilStreaming = async (lab: Lab, state: string): Promise<void> => {\n const started = Date.now();\n for (;;) {\n const seen = await lab.exec(psql(\"SELECT sync_state FROM pg_stat_replication WHERE state = 'streaming'\"));\n if (seen === state) return;\n if (Date.now() - started > SETUP_MS) throw new Error(`the standby did not stream as ${state} in ${SETUP_MS} ms: it reports \"${seen}\"`);\n await sleep(100);\n }\n};\n\n/**\n * This function opens the pair of an environment. The table comes first and the standby next: the\n * base backup has it. A synchronous standby is named last, thus no setup step waits for it.\n */\nexport const openStandby = async (lab: Lab, cell: Cell): Promise<Sibling> => {\n const pair = cell.pair!;\n await lab.exec([\"sh\", \"-c\", 'echo \"host replication all all trust\" >> \"$PGDATA/pg_hba.conf\"']);\n await lab.exec(psql(\"SELECT pg_reload_conf()\"));\n await lab.exec(psql(`CREATE TABLE ${TABLE} (n integer PRIMARY KEY)`));\n const standby = await lab.sibling(await targetImageOf(cell.target), standbyCommand(lab.serverIp), STANDBY_READY);\n await untilStreaming(lab, \"async\");\n if (pair.synchronous) {\n await lab.exec(psql(\"ALTER SYSTEM SET synchronous_standby_names = '*'\"));\n await lab.exec(psql(\"SELECT pg_reload_conf()\"));\n await untilStreaming(lab, \"sync\");\n }\n return standby;\n};\n\n/** This function waits for a count of acknowledged writes. */\nconst untilSteady = async (probe: Probe): Promise<void> => {\n const started = Date.now();\n while (probe.events.filter((event) => event.ev === \"ack\").length < STEADY) {\n if (Date.now() - started > SETUP_MS) throw new Error(`the client did not write ${STEADY} times in ${SETUP_MS} ms`);\n await sleep(10);\n }\n};\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1)\n if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/**\n * This function does one run of a pair. A dry run writes and stops, with no fault: the warm-up of the\n * environment. It removes its rows, thus the numbers of the run start on an empty table.\n */\nexport const pairOnce = async (lab: Lab, standby: Sibling, cell: Cell, environment: number, index: number, dry = false): Promise<Run> => {\n const pair = cell.pair!;\n await lab.forget();\n const from = lab.kernel.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const probe = await lab.probe(pairArgs(cell, lab));\n const holdNs = cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\") * 1e9;\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n try {\n await probe.until([\"ready\"], 15_000);\n await untilSteady(probe);\n if (!dry) {\n fault = await lab.fault(\"blackhole\", \"target\", { peers: peersOf(pair, standby.ip, lab) });\n const started = Date.now();\n for (const at of cancelsOf(pair, holdNs)) {\n await sleep(Math.max(0, at / 1e6 - (Date.now() - started)));\n await lab.exec(psql(\"SELECT count(pg_cancel_backend(pid)) FROM pg_stat_activity WHERE wait_event = 'SyncRep'\"));\n }\n heal = await lab.signal(\"KILL\", fault.t0 + holdNs);\n await sleep(LAST_WRITE_MS);\n // the injector lists its processes before its wait: a backend that started in the wait is here\n if (cell.target.kill !== undefined) await lab.exec(cell.target.kill);\n }\n // a client whose writers each failed is gone already, and its done line tells it\n await probe.go().catch(() => undefined);\n await probe.until([\"done\"], STOP_MS);\n } finally {\n await probe.stop();\n }\n if (dry) await lab.exec(psql(`TRUNCATE ${TABLE}`));\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const read = `SELECT n FROM ${TABLE} ORDER BY n`;\n let holds: readonly number[] | null = null;\n let oldHolds: readonly number[] = [];\n if (!dry) {\n await standby.exec(psql(\"SELECT pg_promote(true, 60)\"));\n holds = numbersOf(await standby.exec(psql(read)));\n await lab.exec([...RESTART]);\n oldHolds = numbersOf(await lab.exec(psql(read)));\n }\n return {\n environment,\n index,\n events: [...probe.events],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost,\n ...(lab.topology === null ? {} : { topology: lab.topology, middlebox: [] }),\n group: {\n members: { primary: { ip: lab.serverIp, netns: lab.netns.target }, standby: { ip: standby.ip, netns: standby.netns } },\n sentinels: {},\n primary: \"primary\",\n at: \"primary\",\n timeline: [],\n after: dry ? \"primary\" : \"standby\",\n holds,\n oldHolds,\n },\n };\n};\n","import type { BuildRecord } from \"./image.ts\";\nimport { PINNED } from \"./image.ts\";\nimport type { Manifest } from \"./lab.ts\";\n\n/**\n * This module tells if a manifest pins each program that a run operated. A record that does not pin\n * them is not a record. A later run cannot operate the same programs, thus nobody can reproduce\n * its numbers (SYS-101). Each image is pulled by its digest, or the harness builds it. A build\n * records its bases by digest, the sha256 of each lockfile, and the versions of the packages that\n * its manifests name. The commit of the code that operated is a field of the record of a cell, and\n * `commitProblems` examines it.\n */\n\n/** This pattern matches the id of an image: `sha256:` and 64 hex digits. */\nconst IMAGE_ID = /^sha256:[0-9a-f]{64}$/;\n/** This pattern matches the tag of a build of the harness: its name, then 12 hex digits of the sha256 of its context. */\nconst BUILD_TAG = /^[a-z0-9][a-z0-9._\\-/]*:[0-9a-f]{12}$/;\n/** This pattern matches a commit of git: 40 hex digits. */\nconst COMMIT = /^[0-9a-f]{40}$/;\n\n/** This function gives each problem of the record of a build. A problem is a base that no digest pins, or a tag of another form. */\nconst buildProblems = (what: string, build: BuildRecord): string[] => [\n ...(BUILD_TAG.test(build.tag) ? [] : [`${what}: the build has the tag ${build.tag}, which is not a tag of a build`]),\n ...build.bases.filter((base) => !PINNED.test(base)).map((base) => `${what}: the base ${base} is not pinned by digest`),\n];\n\n/**\n * This function gives each problem of an image of a manifest. A pulled image needs a digest. An\n * image that the harness builds needs its build record when the manifest can hold one (`build`).\n * Otherwise, it needs the tag of a build and the id of its image.\n */\nconst pinProblems = (what: string, image: string, id: string | undefined, build: BuildRecord | undefined, needsBuild: boolean): string[] => {\n if (PINNED.test(image)) return [];\n if (build !== undefined) return buildProblems(what, build);\n if (BUILD_TAG.test(image) && !needsBuild && id !== undefined && IMAGE_ID.test(id)) return [];\n return BUILD_TAG.test(image) && needsBuild\n ? [`${what}: the image ${image} is a build with no build record`]\n : [`${what}: the image ${image} has no digest`];\n};\n\n/**\n * This function gives each problem of a manifest that stops it from pinning the programs of its\n * run. An empty list means that the manifest pins each program.\n * - the target: an image by its digest, or the build of a subject with its build record and its base\n * by digest.\n * - the harness: the version of its package, and the build record of its image.\n * - the client: an image by its digest, or a build with its build record.\n * - each hop: an image by its digest, or the tag of a build and the id of its image.\n */\nexport const manifestProblems = (manifest: Manifest): string[] => [\n ...pinProblems(\"the target\", manifest.target.image, manifest.target.id, manifest.target.build, manifest.target.subject !== undefined),\n ...(manifest.target.subject !== undefined && (manifest.target.base === undefined || !PINNED.test(manifest.target.base))\n ? [`the target: the base ${manifest.target.base ?? \"(none)\"} of its subject is not pinned by digest`]\n : []),\n ...(manifest.harness.version === undefined ? [\"the harness: the manifest has no version of the harness\"] : []),\n ...(manifest.harness.build === undefined ? [\"the harness: the image has no build record\"] : buildProblems(\"the harness\", manifest.harness.build)),\n ...pinProblems(\"the client\", manifest.client.image, undefined, manifest.client.build, true),\n ...(manifest.hops ?? []).flatMap((hop) => pinProblems(`the hop ${hop.name}`, hop.image, hop.id, undefined, false)),\n];\n\n/** This function gives the problem of the commit of a record: no commit, or a text that is not a commit of git. */\nexport const commitProblems = (commit: string | undefined): string[] =>\n commit === undefined\n ? [\"the record has no commit of the code that operated\"]\n : COMMIT.test(commit)\n ? []\n : [`the record has the commit ${commit}, which is not 40 hex digits`];\n\n/** The code of a record is the commit of the checkout that operated, and if its tracked files had changes. */\nexport interface RecordCode {\n readonly commit: string;\n readonly dirty: boolean;\n}\n\n/** These are the parts of a record that tell if it pins the programs of its runs. */\nexport interface Pinnable {\n readonly code?: RecordCode | undefined;\n readonly manifests: readonly Manifest[];\n /** A local debug run marks its record so. No page reads such a record. */\n readonly debug?: boolean | undefined;\n}\n\n/** This problem is the problem of a checkout with changes: its commit does not hold the code that operated. */\nexport const DIRTY = \"the checkout has changes to tracked files that no commit holds\";\n\n/** This problem is the problem of a record of a local debug run. */\nexport const DEBUG = \"the record is of a local debug run, and no page reads it\";\n\n/**\n * This function gives each problem that stops a record from pinning the programs of its runs. A\n * record with a problem is not a record (SYS-101). The writer of the cells refuses it, and the read\n * of a schedule refuses it. A commit with changes to tracked files is not a pin.\n */\nexport const recordProblems = (record: Pinnable): string[] => [\n ...new Set([\n ...commitProblems(record.code?.commit),\n ...(record.code?.dirty === true ? [DIRTY] : []),\n ...record.manifests.flatMap((manifest) => manifestProblems(manifest)),\n ...(record.debug === true ? [DEBUG] : []),\n ]),\n];\n","import type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type {\n Cell,\n Group,\n GroupPlace,\n GroupRole,\n KernelRecord,\n ProbeEvent,\n Run,\n RunPart,\n SentinelEvent,\n} from \"./cell.ts\";\nimport type { Manifest } from \"./lab.ts\";\nimport { harnessImage, nodeClientImage } from \"./image.ts\";\nimport { STOP, containers, harnessRecord, lines, netnsOf, output, shippedClientRecord, withPid } from \"./lab.ts\";\n\n/**\n * This module is the lab of a replicated group: a primary and its replicas, and the Sentinels\n * that decide which member is the primary. It opens one environment for a group cell, and it does\n * the runs of the cell in it. Each member and each Sentinel is a container from the stock image of\n * the group, in its own network namespace. An injector sidecar shares its network and process\n * namespaces. The client of each run is ioredis in Sentinel mode. An observer subscribes to the\n * events of each Sentinel, and the prober watches the namespace of the client.\n */\n\n/** A stamp is the time of the injector around one commit, on CLOCK_MONOTONIC in nanoseconds. */\nexport interface Stamp {\n readonly t0: number;\n readonly t1: number;\n}\n\n/** A group network fault is a black hole between a part and its peers, or a reset of each segment from them. */\nexport type GroupNetworkFault = \"blackhole\" | \"rst\";\n\n/** A group client is the client container of one run of a group cell. */\nexport interface GroupClient {\n readonly events: readonly ProbeEvent[];\n until(kinds: readonly string[], within: number): Promise<ProbeEvent>;\n stop(): Promise<void>;\n}\n\n/** A group lab is one environment of a group cell. */\nexport interface GroupLab {\n readonly group: Group;\n readonly clientIp: string;\n readonly observerIp: string;\n readonly members: Readonly<Record<string, RunPart>>;\n readonly sentinels: Readonly<Record<string, RunPart>>;\n /** These are the namespaces that the prober watches: the client, and the Sentinels for a calibration. */\n readonly netns: { readonly client: number; readonly watched: readonly number[] };\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** These are all the lines of the observer of the Sentinels, in sequence. */\n readonly timeline: readonly SentinelEvent[];\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method waits until the group is whole and calm, and gives the name of its primary. */\n converge(within?: number): Promise<string>;\n /** This method removes each key from the group, and waits until each replica has the removal. */\n flush(primary: string): Promise<void>;\n /** This method makes each Sentinel forget the state of the group (`SENTINEL RESET`): an aborted failover then holds off no later failover. */\n reset(): Promise<void>;\n /** This method gives the sequence numbers that the group holds, from its primary. */\n holds(primary: string): Promise<number[]>;\n /** This method gives the part that has a role in the group, when `primary` is the primary. */\n partOf(role: GroupRole, primary: string): string;\n /** This method starts the client of a run, with the arguments of `client-sentinel.mjs`. */\n client(args: readonly string[]): Promise<GroupClient>;\n /** This method applies a network fault between a part and some of its peers, at once or at an instant of the VM. */\n fault(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes a network fault, at once or at an instant of the VM. */\n lift(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method sends a signal to the server process of a part, at once or at an instant of the VM. */\n signal(part: string, signal: \"KILL\" | \"STOP\" | \"CONT\", at?: number): Promise<Stamp>;\n /** This method starts the server of a member again, after a fin. */\n restart(member: string): Promise<void>;\n /** This method asks the first Sentinel for a failover of the group. */\n failover(coordinated: boolean): Promise<Stamp>;\n /** This method removes the TCP metrics of the client namespace: each run starts from a kernel that keeps nothing. */\n forget(): Promise<void>;\n /** This method waits for the next clock line of the prober, which gives the count of lost records. */\n settle(): Promise<number | null>;\n manifest(sysctls: Readonly<Record<string, string>>): Promise<Manifest>;\n close(): Promise<void>;\n}\n\n/** This function gives the configuration file of a member: its port, its settings, and the primary that a replica follows. */\nexport const memberConfig = (group: Group, primary: string | null): string =>\n [\n `port ${group.port}`,\n ...Object.entries(group.memberSettings).map(([key, value]) => `${key} ${value}`),\n ...(primary === null ? [] : [`replicaof ${primary} ${group.port}`]),\n \"\",\n ].join(\"\\n\");\n\n/** This function gives the configuration file of a Sentinel: its port, the group that it monitors, and the settings of the group. */\nexport const sentinelConfig = (group: Group, primary: string): string =>\n [\n `port ${group.sentinelPort}`,\n `sentinel monitor ${group.name} ${primary} ${group.port} ${group.quorum}`,\n ...Object.entries(group.sentinelSettings).map(([key, value]) => `sentinel ${key} ${group.name} ${value}`),\n \"\",\n ].join(\"\\n\");\n\n/**\n * This function gives the peers that a fault on a part cuts it from, by their addresses. `all` is\n * each other part and the client, `group` is the other parts, and `clients` and `to-clients` are\n * the client. `one` and `one-way` are the first other member. The observer is not a peer, thus the timeline of the\n * group stays whole.\n */\nexport const peersOf = (\n parts: { readonly members: Readonly<Record<string, RunPart>>; readonly sentinels: Readonly<Record<string, RunPart>> },\n client: string,\n part: string,\n cuts: NonNullable<GroupPlace[\"cuts\"]>,\n): string[] => {\n const others = [...Object.entries(parts.members), ...Object.entries(parts.sentinels)]\n .filter(([name]) => name !== part)\n .map(([, at]) => at.ip);\n if (cuts === \"clients\" || cuts === \"to-clients\") return [client];\n if (cuts === \"group\") return others;\n if (cuts === \"one\" || cuts === \"one-way\")\n return Object.entries(parts.members)\n .filter(([name]) => name !== part)\n .slice(0, 1)\n .map(([, at]) => at.ip);\n return [...others, client];\n};\n\n/** This function gives the direction of the rules of a cut: `one-way` and `to-clients` drop only the segments from the part. */\nconst directionOf = (cuts: NonNullable<GroupPlace[\"cuts\"]>): string[] => (cuts === \"one-way\" || cuts === \"to-clients\" ? [\"--direction\", \"out\"] : []);\n\n/** This function reads the flat reply of a command line client into its fields: name, value, name, value. */\nexport const fieldsOf = (text: string): Array<Record<string, string>> => {\n const out: Array<Record<string, string>> = [];\n const words = text.split(\"\\n\").map((line) => line.replace(/\\r$/, \"\"));\n let current: Record<string, string> | null = null;\n for (let at = 0; at + 1 < words.length; at += 2) {\n const [key, value] = [words[at]!, words[at + 1]!];\n // each entry of a list starts again at its name\n if (key === \"name\" || current === null) {\n current = {};\n out.push(current);\n }\n current[key] = value;\n }\n return out;\n};\n\n/** This function reads the INFO of a server into its fields. */\nexport const infoOf = (text: string): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const line of text.split(\"\\n\")) {\n const at = line.indexOf(\":\");\n if (line.startsWith(\"#\") || at === -1) continue;\n out[line.slice(0, at)] = line.slice(at + 1).trim();\n }\n return out;\n};\n\n/**\n * A view of the group is what its parts tell at one time. `healthy` tells if each Sentinel agrees\n * on one primary with no flag but `master`, and knows each replica and each other Sentinel. Each\n * replica must follow that primary with its link up, and the primary must have each replica online,\n * with no failover in progress.\n */\nexport interface GroupView {\n readonly primary: string | null;\n readonly healthy: boolean;\n readonly why: string;\n}\n\n/** This function judges the views of the Sentinels and of the members: the primary that they agree on, if the group is healthy. */\nexport const viewOf = (\n group: Group,\n ips: Readonly<Record<string, string>>,\n sentinels: ReadonlyArray<{ readonly master: Record<string, string>; readonly replicas: ReadonlyArray<Record<string, string>> }>,\n members: Readonly<Record<string, Record<string, string>>>,\n): GroupView => {\n const others = String(group.sentinels.length - 1);\n const replicas = group.members.length - 1;\n const addresses = new Set(sentinels.map((each) => each.master[\"ip\"]));\n if (addresses.size !== 1) return { primary: null, healthy: false, why: `the Sentinels name ${addresses.size} primaries` };\n const ip = [...addresses][0]!;\n const primary = Object.entries(ips).find(([, at]) => at === ip)?.[0] ?? null;\n if (primary === null) return { primary: null, healthy: false, why: `no member has the address ${ip}` };\n for (const [at, each] of sentinels.entries()) {\n if (each.master[\"flags\"] !== \"master\") return { primary, healthy: false, why: `Sentinel ${at} flags the primary ${each.master[\"flags\"]}` };\n if (each.master[\"num-other-sentinels\"] !== others) return { primary, healthy: false, why: `Sentinel ${at} knows ${each.master[\"num-other-sentinels\"]} other Sentinels` };\n const good = each.replicas.filter(\n (replica) => replica[\"flags\"] === \"slave\" && replica[\"master-link-status\"] === \"ok\" && replica[\"master-host\"] === ip,\n );\n if (good.length !== replicas || each.replicas.length !== replicas)\n return { primary, healthy: false, why: `Sentinel ${at} has ${good.length} healthy replicas of ${each.replicas.length}` };\n }\n const info = members[primary] ?? {};\n if (info[\"role\"] !== \"master\") return { primary, healthy: false, why: `${primary} reports the role ${info[\"role\"]}` };\n if (info[\"master_failover_state\"] !== undefined && info[\"master_failover_state\"] !== \"no-failover\")\n return { primary, healthy: false, why: `${primary} is in the failover state ${info[\"master_failover_state\"]}` };\n const online = Object.entries(info).filter(([key, value]) => /^slave\\d+$/.test(key) && value.includes(\"state=online\")).length;\n if (online !== replicas) return { primary, healthy: false, why: `${primary} has ${online} replicas online` };\n for (const name of group.members) {\n if (name === primary) continue;\n const each = members[name] ?? {};\n if (each[\"role\"] !== \"slave\" || each[\"master_host\"] !== ip || each[\"master_link_status\"] !== \"up\")\n return { primary, healthy: false, why: `${name} is not a replica of ${primary} with its link up` };\n }\n return { primary, healthy: true, why: \"healthy\" };\n};\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** This time is the longest that a group takes to converge before a run, or after it. */\nexport const CONVERGE_MS = 240_000;\n\n/**\n * This function opens one environment of a group cell:\n * - one new network, with each member, each Sentinel, the client and the observer on it.\n * - each member: the stock image, its server as the child of a shell, thus a fin can stop the\n * server and the container stays up. The first member is the primary, and the others follow it.\n * - each Sentinel: the stock image, its Sentinel as the child of a shell, which monitors the first member.\n * - an injector sidecar for each part, in its network and process namespaces.\n * - a client that holds its own network namespace, with a privileged sidecar for its sysctls.\n * - the observer of the Sentinels, in a namespace of its own.\n * - the prober, which watches the namespace of the client, and of each Sentinel for a calibration.\n */\nexport const openGroupLab = async (group: Group, options: { readonly watchSentinels?: boolean } = {}): Promise<GroupLab> => {\n const image = await harnessImage();\n const node = await nodeClientImage();\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n let network: StartedNetwork | undefined;\n const close = async () => {\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n await network?.stop().catch(() => undefined);\n };\n const ipOf = async (container: StartedTestContainer): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network!.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network!.getName()}`);\n return ip;\n };\n try {\n network = await new Network().start();\n const boxes = new Map<string, StartedTestContainer>();\n const injectors = new Map<string, StartedTestContainer>();\n const parts = { members: {} as Record<string, RunPart>, sentinels: {} as Record<string, RunPart> };\n /** This function starts one part: the stock image with its configuration, its program as the child of a shell, and its injector. */\n const start = async (name: string, program: string, file: string, content: string, ready: string) => {\n const box = await new GenericContainer(group.image)\n .withNetwork(network!)\n .withNetworkAliases(name)\n .withCopyContentToContainer([{ content, target: file }])\n .withCommand([\"sh\", \"-c\", `${program} ${file} & while :; do sleep 3600; done`])\n .withWaitStrategy(Wait.forLogMessage(ready))\n .start();\n opened.push(box);\n boxes.set(name, box);\n const injector = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${box.getId()}`,\n ).start();\n opened.push(injector);\n injectors.set(name, injector);\n return { ip: await ipOf(box), netns: await netnsOf(injector) };\n };\n const [first, ...rest] = group.members;\n if (first === undefined) throw new Error(\"a group has no member\");\n parts.members[first] = await start(first, group.programs.server, \"/data/server.conf\", memberConfig(group, null), group.ready.member);\n const primaryIp = parts.members[first].ip;\n for (const name of rest)\n parts.members[name] = await start(name, group.programs.server, \"/data/server.conf\", memberConfig(group, primaryIp), group.ready.member);\n for (const name of group.sentinels)\n parts.sentinels[name] = await start(name, group.programs.sentinel, \"/data/sentinel.conf\", sentinelConfig(group, primaryIp), group.ready.sentinel);\n\n const holder = await new GenericContainer(image).withNetwork(network).start();\n opened.push(holder);\n const admin = await new GenericContainer(image)\n .withNetworkMode(`container:${holder.getId()}`)\n .withPrivilegedMode()\n .start();\n opened.push(admin);\n const clientIp = await ipOf(holder);\n\n const sentinelAddresses = group.sentinels.map((name) => `${parts.sentinels[name]!.ip}:${group.sentinelPort}`);\n const timeline = lines<SentinelEvent>();\n const observer = await new GenericContainer(node)\n .withNetwork(network)\n .withCommand([\"node\", \"/opt/harness/node/observer.mjs\", sentinelAddresses.join(\",\")])\n .withLogConsumer(timeline.consume)\n .start();\n opened.push(observer);\n const observerIp = await ipOf(observer);\n for (const address of sentinelAddresses)\n await new Promise<void>((resolve, reject) => {\n const started = Date.now();\n const look = () => {\n if (timeline.seen.some((line) => line.ev === \"subscribed\" && line[\"sentinel\"] === address)) resolve();\n else if (Date.now() - started > 30_000) reject(new Error(`the observer never subscribed to ${address}`));\n else setTimeout(look, 50);\n };\n look();\n });\n\n const clientNetns = await netnsOf(admin);\n const watched = [clientNetns, ...(options.watchSentinels === true ? group.sentinels.map((name) => parts.sentinels[name]!.netns) : [])];\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\"/opt/harness/prober\", ...watched.map(String)])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n\n const box = (name: string): StartedTestContainer => {\n const found = boxes.get(name);\n if (found === undefined) throw new Error(`the group has no part ${name}`);\n return found;\n };\n const injectorOf = (name: string): StartedTestContainer => {\n const found = injectors.get(name);\n if (found === undefined) throw new Error(`the group has no part ${name}`);\n return found;\n };\n const cli = (name: string, args: readonly string[]): Promise<string> => {\n const port = group.sentinels.includes(name) ? group.sentinelPort : group.port;\n return output(box(name), [group.programs.cli, \"-p\", String(port), ...args]);\n };\n const stamped = async (where: StartedTestContainer, argv: string[]): Promise<Stamp> => {\n const stamp = JSON.parse((await output(where, argv)).split(\"\\n\").at(-1)!) as Stamp;\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const ips: Record<string, string> = Object.fromEntries(Object.entries(parts.members).map(([name, at]) => [name, at.ip]));\n const view = async (): Promise<GroupView> => {\n const sentinels = [];\n for (const name of group.sentinels) {\n const master = fieldsOf(await cli(name, [\"SENTINEL\", \"MASTER\", group.name]))[0] ?? {};\n const replicas = fieldsOf(await cli(name, [\"SENTINEL\", \"REPLICAS\", group.name]));\n sentinels.push({ master, replicas });\n }\n const members: Record<string, Record<string, string>> = {};\n for (const name of group.members) members[name] = infoOf(await cli(name, [\"INFO\", \"replication\"]));\n return viewOf(group, ips, sentinels, members);\n };\n const after = (at: number | undefined): string[] => (at === undefined ? [] : [\"--at\", String(Math.round(at))]);\n const roles = (role: GroupRole, primary: string): string => {\n if (role === \"primary\") return primary;\n if (role === \"sentinel\") return group.sentinels[0]!;\n const replica = group.members.find((name) => name !== primary);\n if (replica === undefined) throw new Error(\"the group has no replica\");\n return replica;\n };\n\n return {\n group,\n clientIp,\n observerIp,\n members: parts.members,\n sentinels: parts.sentinels,\n netns: { client: clientNetns, watched },\n kernel: records.seen,\n timeline: timeline.seen,\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values)) read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n async converge(within = CONVERGE_MS) {\n const started = Date.now();\n let calm = 0;\n let last: GroupView = { primary: null, healthy: false, why: \"no view yet\" };\n while (Date.now() - started < within) {\n last = await view().catch((error: unknown) => ({ primary: null, healthy: false, why: (error as Error).message }));\n // two healthy views in a row: one view can come in the middle of a change\n calm = last.healthy ? calm + 1 : 0;\n if (calm >= 2 && last.primary !== null) return last.primary;\n await sleep(1_000);\n }\n throw new Error(`the group did not converge in ${within} ms: ${last.why}`);\n },\n async flush(primary) {\n await cli(primary, [\"FLUSHALL\"]);\n const acked = Number(await cli(primary, [\"WAIT\", String(group.members.length - 1), \"5000\"]));\n if (acked !== group.members.length - 1) throw new Error(`${acked} replicas acknowledged the flush`);\n },\n async reset() {\n for (const name of group.sentinels) await cli(name, [\"SENTINEL\", \"RESET\", group.name]);\n },\n async holds(primary) {\n return holdsOf(await cli(primary, [\"--scan\", \"--pattern\", \"w:*\"]), await cli(primary, [\"LRANGE\", \"w\", \"0\", \"-1\"]));\n },\n partOf: roles,\n async client(args) {\n const events = lines<ProbeEvent>();\n const container = await new GenericContainer(node)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"node\", \"/opt/harness/node/client-sentinel.mjs\", ...args])\n .withLogConsumer(events.consume)\n .start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n // a TERM first: the client writes its done line, then stops\n stop: () =>\n container\n .stop({ timeout: 2 })\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n fault(kind, part, cuts, at) {\n const peers = peersOf(parts, clientIp, part, cuts).join(\",\");\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind, peers, ...directionOf(cuts), ...after(at)]);\n },\n lift(kind, part, cuts, at) {\n const peers = peersOf(parts, clientIp, part, cuts).join(\",\");\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind === \"rst\" ? \"clear-rst\" : \"clear\", peers, ...directionOf(cuts), ...after(at)]);\n },\n signal(part, signal, at) {\n const program = group.sentinels.includes(part) ? group.programs.sentinel : group.programs.server;\n return stamped(injectorOf(part), [\"/opt/harness/inject\", \"signal\", program, signal, ...after(at)]);\n },\n async restart(member) {\n await output(box(member), [\"sh\", \"-c\", `${group.programs.server} /data/server.conf --daemonize yes`]);\n const started = Date.now();\n while ((await cli(member, [\"PING\"]).catch(() => \"\")) !== \"PONG\") {\n if (Date.now() - started > 30_000) throw new Error(`${member} did not start again`);\n await sleep(200);\n }\n },\n failover(coordinated) {\n const sentinel = group.sentinels[0]!;\n return stamped(injectorOf(sentinel), [\n \"/opt/harness/inject\",\n \"resp\",\n `127.0.0.1:${group.sentinelPort}`,\n \"SENTINEL\",\n \"FAILOVER\",\n group.name,\n ...(coordinated ? [\"COORDINATED\"] : []),\n ]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n async settle() {\n const from = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const started = Date.now();\n const look = () => {\n const line = records.seen.slice(from).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - started > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) =>\n runtime.container.inspect(runtime.container.getById(container.getId()));\n const memberSettings = async (name: string) => {\n const read: Record<string, string> = {};\n // the reply is the name, then the value: an empty value is the end of the reply\n for (const key of Object.keys(group.memberSettings)) read[key] = (await cli(name, [\"CONFIG\", \"GET\", key])).split(\"\\n\")[1] ?? \"\";\n return read;\n };\n const sentinelSettings = async (name: string) => {\n const master = fieldsOf(await cli(name, [\"SENTINEL\", \"MASTER\", group.name]))[0] ?? {};\n const read: Record<string, string> = { quorum: master[\"quorum\"] ?? \"\" };\n for (const key of Object.keys(group.sentinelSettings)) read[key] = master[key] ?? \"\";\n return read;\n };\n const members = [];\n for (const name of group.members)\n members.push({ name, ip: parts.members[name]!.ip, id: (await inspect(box(name))).Image, settings: await memberSettings(name) });\n const sentinels = [];\n for (const name of group.sentinels)\n sentinels.push({ name, ip: parts.sentinels[name]!.ip, id: (await inspect(box(name))).Image, settings: await sentinelSettings(name) });\n return {\n kernel: await output(holder, [\"uname\", \"-r\"]),\n architecture: await output(holder, [\"uname\", \"-m\"]),\n hz: /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1] ?? null,\n boot_id: await output(holder, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n target: { image: group.image, id: members[0]!.id, settings: members[0]!.settings, sysctls: {} },\n harness: {\n image,\n id: (await inspect(holder)).Image,\n packages: (await output(holder, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n ...harnessRecord(),\n },\n client: shippedClientRecord(\"ioredis\", node),\n netns: { client: clientNetns, target: parts.members[first]!.netns },\n sysctls,\n group: { members, sentinels, observer: { image: node } },\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n\n// ---------------------------------------------------------------------------------------------\n// the runs of a group cell\n// ---------------------------------------------------------------------------------------------\n\n/** This count is the number of accepted writes that a run waits for before its fault: the stream is steady then. */\nconst STEADY = 20;\n/** This time is how long a run continues after its outcome, so that the record shows what came next. */\nconst TAIL_MS = 2_000;\n\n/** This function gives the address of a member, with the port of the group. */\nconst addressOf = (lab: GroupLab, member: string): string => `${lab.members[member]!.ip}:${lab.group.port}`;\n\n/** This function gives the latest time that a group cell waits for its outcome, in ms from the fault. */\nexport const deadlineOf = (cell: Cell): number => {\n const { prediction } = cell;\n const seconds =\n prediction.detects === true\n ? valueIn(prediction.high, \"s\")\n : prediction.detects === false && prediction.recovers !== undefined\n ? valueIn(prediction.recovers.high, \"s\")\n : valueIn(prediction.window, \"s\");\n return seconds * 1_000 + 10_000;\n};\n\n/**\n * This function gives the sequence numbers that a group holds, in order, from the output of its\n * command line. They are the keys `w:<n>` of a stream of SET, and the entries of the list `w` of a\n * stream of RPUSH. A list keeps each copy, thus a number can repeat.\n */\nexport const holdsOf = (keys: string, list: string): number[] =>\n [...keys.split(\"\\n\").map((key) => Number(key.trim().slice(2))), ...list.split(\"\\n\").map((entry) => Number(entry.trim()))]\n .filter((n) => Number.isInteger(n) && n > 0)\n .sort((a, b) => a - b);\n\n/** This function gives the arguments of the client of a group cell. */\nconst clientArgs = (cell: Cell, lab: GroupLab): string[] => {\n const sentinels = cell.group!.sentinels.map((name) => `${lab.sentinels[name]!.ip}:${cell.group!.sentinelPort}`);\n const driver = cell.probe.driver?.name === \"ioredis\" ? cell.probe.driver : undefined;\n return [\n \"--sentinels\",\n sentinels.join(\",\"),\n \"--name\",\n cell.group!.name,\n \"--interval-ms\",\n String(cell.probe.interval === undefined ? 50 : valueIn(cell.probe.interval, \"ms\")),\n \"--max-s\",\n String(Math.ceil(deadlineOf(cell) / 1_000 + 120)),\n ...(cell.driverOptions === undefined ? [] : [\"--options\", JSON.stringify(cell.driverOptions)]),\n ...(driver?.op === undefined ? [] : [\"--op\", driver.op]),\n ...(driver?.window === undefined ? [] : [\"--window\", String(driver.window)]),\n ];\n};\n\n/** This function waits until a condition on the lines of the client holds, or for `within` ms. It gives the first line that matches. */\nconst waitFor = (\n client: GroupClient,\n match: (event: ProbeEvent) => boolean,\n within: number,\n): Promise<ProbeEvent | undefined> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const found = client.events.find(match);\n if (found !== undefined || Date.now() - started > within) resolve(found);\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This function gives the latest subscription of the observer to each Sentinel, in some lines of the observer. */\nexport const subscriptionsOf = (timeline: readonly SentinelEvent[]): SentinelEvent[] => {\n const latest = new Map<string, SentinelEvent>();\n for (const line of timeline) if (line.ev === \"subscribed\") latest.set(String(line.sentinel), line);\n return [...latest.values()];\n};\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1)\n if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/**\n * This function does one run of a group cell:\n * - The group converges, and its keys go. The client connects through the Sentinels, and its\n * stream of writes gets steady.\n * - The fault occurs on its part, as the primary of this run makes the roles. A fault with a\n * hold lifts at its instant in the VM. A stall lifts at its length after the first write into it.\n * - The run waits for its outcome: the first write that a new primary accepts, or the first one\n * after the lift on the same primary. Then it continues for a moment.\n * - Each fault goes, the client stops, and the group converges again. The keys that it then holds\n * tell which writes it kept.\n */\nexport const groupOnce = async (lab: GroupLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const group = cell.group!;\n const primary = await lab.converge();\n await lab.flush(primary);\n await lab.forget();\n const from = lab.kernel.length;\n const timelineFrom = lab.timeline.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const client = await lab.client(clientArgs(cell, lab));\n const lands = cell.prediction.group?.lands ?? \"new\";\n const place = (cell.faultAt ?? { role: \"primary\" }) as GroupPlace;\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n let at: string | null = null;\n const undo: Array<() => Promise<unknown>> = [];\n try {\n await client.until([\"ready\"], 60_000);\n const steady = await waitFor(client, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not write ${STEADY} times in 30 s`);\n let healing: Promise<Run[\"heal\"]> | null = null;\n switch (cell.fault) {\n case \"blackhole\":\n case \"partition\":\n case \"rst\": {\n const kind = cell.fault === \"rst\" ? \"rst\" : \"blackhole\";\n const cuts = place.cuts ?? (cell.fault === \"partition\" ? \"group\" : \"all\");\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.fault(kind, part, cuts);\n undo.push(() => lab.lift(kind, part, cuts));\n if (cell.stall !== undefined) {\n // the first write into the fault arms the retransmissions: the stall counts from it\n const t1 = fault.t1;\n const sent = await waitFor(client, (event) => event.ev === \"sent\" && event.t > t1, 5_000);\n if (sent !== undefined) healing = lab.lift(kind, part, cuts, sent.t + valueIn(cell.stall, \"s\") * 1e9);\n } else if (cell.hold !== undefined) {\n healing = lab.lift(kind, part, cuts, fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n }\n break;\n }\n case \"freeze-process\": {\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.signal(part, \"STOP\");\n undo.push(() => lab.signal(part, \"CONT\"));\n if (cell.hold !== undefined) healing = lab.signal(part, \"CONT\", fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n break;\n }\n case \"fin\": {\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.signal(part, \"KILL\");\n if (group.members.includes(part)) undo.push(() => lab.restart(part));\n break;\n }\n case \"planned-failover\":\n fault = await lab.failover(cell.coordinated === true);\n break;\n default:\n throw new Error(`a group cell has no fault ${cell.fault}`);\n }\n // the injector holds the lift in the VM: its exec returns at the instant, and the stamps come with it\n const healed =\n healing === null\n ? Promise.resolve(null)\n : healing.then((stamp) => {\n heal = stamp;\n // the lift came: nothing is left to undo\n undo.length = 0;\n return stamp;\n });\n // a run that stops early lifts the fault itself, and the late lift then has nothing to remove\n healed.catch(() => undefined);\n const t0 = fault.t0;\n const old = addressOf(lab, primary);\n const deadline = deadlineOf(cell);\n const outcome =\n lands === \"new\"\n ? await waitFor(\n client,\n (event) => event.ev === \"ack\" && event.t > t0 && typeof event[\"at\"] === \"string\" && event[\"at\"] !== old,\n deadline,\n )\n : await (async () => {\n await healed;\n const after = (heal as Run[\"heal\"])?.t0 ?? t0;\n return waitFor(client, (event) => event.ev === \"ack\" && event.t > after, deadline);\n })();\n if (outcome !== undefined) await sleep(TAIL_MS);\n await healed;\n } finally {\n // each fault that is still on goes, and a killed server starts again\n for (const step of undo.reverse()) await step().catch(() => undefined);\n await client.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge().catch(() => null);\n const holds = after === null ? null : await lab.holds(after);\n // a failover that a Sentinel aborted holds off its next attempt for 2 × failover-timeout. The\n // next run must not inherit that hold-off: each Sentinel forgets the state of the group, and the\n // next converge waits until each one knows the group again\n if (lab.timeline.slice(timelineFrom).some((line) => line.ev === \"sentinel\" && String(line.event).startsWith(\"-failover-abort\")))\n await lab.reset();\n return {\n environment,\n index,\n events: [...client.events],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[primary]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: lab.sentinels,\n primary,\n at,\n // the subscription of the observer to each Sentinel came before the run: its address names\n // the socket of each Sentinel's writes, which a calibration reads\n timeline: [...subscriptionsOf(lab.timeline.slice(0, timelineFrom)), ...lab.timeline.slice(timelineFrom)],\n after,\n holds,\n },\n };\n};\n","import type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, GroupPlace, GroupRole, KernelRecord, ProbeEvent, ReplicaSet, Run, RunPart, SentinelEvent } from \"./cell.ts\";\nimport type { GroupClient, GroupNetworkFault, GroupView, Stamp } from \"./group.ts\";\nimport { CONVERGE_MS, deadlineOf } from \"./group.ts\";\nimport type { Manifest } from \"./lab.ts\";\nimport { harnessImage, mongoClientImage } from \"./image.ts\";\nimport { STOP, containers, harnessRecord, lines, netnsOf, output, shippedClientRecord, withPid } from \"./lab.ts\";\nimport { drillSpan } from \"./recovery.ts\";\nimport { substrateHere } from \"./substrate.ts\";\n\n/**\n * This module is the lab of a replica set: a replicated group with no external authority, whose\n * members elect their own primary. It opens one environment for a replica set cell, for the runs\n * of the cell. Each member is a container from the stock image of the set, in its own network\n * namespace. An injector sidecar shares its network and process namespaces.\n *\n * The client of each run is the MongoDB driver, which finds the primary with its own monitors. The\n * timeline comes from the log of each member and from the lines of the client. The prober watches\n * the namespace of the client.\n */\n\n/**\n * A member line is one log line of a member, as mongod writes it in JSON. `real` is its time on\n * the wall clock in ms, and `t` is its time on the monotonic clock. The run gives `t` from the\n * clock lines of its client.\n */\nexport interface MemberLine extends SentinelEvent {\n readonly ev: \"mongod\";\n readonly member: string;\n readonly real: number;\n readonly id: number;\n readonly c: string;\n readonly msg: string;\n readonly attr: Readonly<Record<string, unknown>>;\n}\n\n/** These are the components of the log of mongod that a run keeps: replication, its heartbeats, the elections, the rollbacks and the commands. */\nexport const KEPT: ReadonlySet<string> = new Set([\"REPL\", \"REPL_HB\", \"ELECTION\", \"ROLLBACK\", \"COMMAND\"]);\n\n/** This function reads one log line of a member, or gives null for a line of another component or a line that is not JSON. */\nexport const memberLineOf = (member: string, text: string): MemberLine | null => {\n if (!text.startsWith(\"{\")) return null;\n let line: { t?: { $date?: string }; c?: string; id?: number; msg?: string; attr?: Record<string, unknown> };\n try {\n line = JSON.parse(text) as typeof line;\n } catch {\n return null;\n }\n const real = Date.parse(line.t?.$date ?? \"\");\n if (!Number.isFinite(real) || !KEPT.has(line.c ?? \"\")) return null;\n return { ev: \"mongod\", t: 0, member, real, id: Number(line.id ?? 0), c: line.c ?? \"\", msg: line.msg ?? \"\", attr: line.attr ?? {} };\n};\n\n/**\n * This function gives the offset of the wall clock from the monotonic clock, in ns, from the clock\n * lines of a client. Each line pairs its stamp with the wall clock in whole ms, which truncates.\n * Thus each pair is the offset or less, and the largest pair is the nearest. It is null without a clock line.\n */\nexport const clockOffsetOf = (events: readonly ProbeEvent[]): number | null => {\n const offsets = events.filter((event) => event.ev === \"clocks\").map((event) => Number(event[\"real\"]) * 1e6 - event.t);\n return offsets.length === 0 ? null : Math.max(...offsets);\n};\n\n/** This function puts the log lines of the members on the monotonic clock, with the offset of a client. */\nexport const onMonotonic = (log: readonly MemberLine[], offset: number | null): MemberLine[] =>\n log.map((line) => ({ ...line, t: offset === null ? 0 : Math.round(line.real * 1e6 - offset) }));\n\n/** A cut is the peers that a network fault on a part cuts it from, by their addresses, and the direction of the rules. */\nexport interface Cut {\n readonly peers: readonly string[];\n readonly direction?: \"out\";\n}\n\n/**\n * This function gives the peers that a fault on a member of a replica set cuts it from. `all` is\n * each other member and the client, `group` is the other members, and `clients` is the client.\n * `one` is the first other member in the sequence of the set, and `one-way` is the same member for\n * the segments from the part only.\n */\nexport const cutOf = (\n set: ReplicaSet,\n members: Readonly<Record<string, RunPart>>,\n client: string,\n part: string,\n cuts: NonNullable<GroupPlace[\"cuts\"]>,\n): Cut => {\n const others = set.members.filter((name) => name !== part).map((name) => members[name]!.ip);\n if (cuts === \"clients\") return { peers: [client] };\n if (cuts === \"group\") return { peers: others };\n if (cuts === \"one\") return { peers: others.slice(0, 1) };\n if (cuts === \"one-way\") return { peers: others.slice(0, 1), direction: \"out\" };\n if (cuts === \"to-clients\") return { peers: [client], direction: \"out\" };\n return { peers: [...others, client] };\n};\n\n/** This function gives the command of the server of each member. The server is the child of a shell, thus a fin can stop it and the container stays up. */\nexport const memberCommand = (set: ReplicaSet): string =>\n `${set.programs.server} --replSet ${set.name} --bind_ip_all --port ${set.port} ${(set.args ?? []).join(\" \")}`.trim();\n\n/** This function gives the script of the shell that starts the set: each member by its address, and the settings of the set. */\nexport const initiateScript = (set: ReplicaSet, ips: Readonly<Record<string, string>>): string => {\n const config = {\n _id: set.name,\n members: set.members.map((name, at) => ({ _id: at, host: `${ips[name]}:${set.port}` })),\n settings: set.settings,\n };\n return `print(JSON.stringify(rs.initiate(${JSON.stringify(config)})))`;\n};\n\n/** This script prints the view of a member: itself, if it accepts writes, and the state of each member as it sees them. */\nexport const STATUS_SCRIPT: string =\n \"const s = rs.status(); const h = db.hello(); print(JSON.stringify({ me: h.me, writable: h.isWritablePrimary === true, \" +\n \"members: s.members.map((m) => ({ name: m.name, state: m.stateStr, health: m.health, optime: m.optimeDate ? m.optimeDate.getTime() : null })) }))\";\n\n/** A status is the view of one member, as `STATUS_SCRIPT` prints it. */\nexport interface Status {\n readonly me: string;\n readonly writable: boolean;\n readonly members: ReadonlyArray<{ readonly name: string; readonly state: string; readonly health: number; readonly optime: number | null }>;\n}\n\n/**\n * This function judges the view of a member: the primary of the set, and if the set is healthy.\n * The set is healthy when the member is the one primary and accepts writes. Each other member must\n * be a healthy secondary at the optime of the primary.\n */\nexport const statusViewOf = (set: ReplicaSet, ips: Readonly<Record<string, string>>, status: Status): GroupView => {\n const byAddress = new Map(set.members.map((name) => [`${ips[name]}:${set.port}`, name]));\n const primaries = status.members.filter((member) => member.state === \"PRIMARY\");\n if (primaries.length !== 1) return { primary: null, healthy: false, why: `the set has ${primaries.length} primaries` };\n const primary = byAddress.get(primaries[0]!.name) ?? null;\n if (primary === null) return { primary: null, healthy: false, why: `no member has the address ${primaries[0]!.name}` };\n if (status.me !== primaries[0]!.name || !status.writable) return { primary, healthy: false, why: `${primary} does not accept writes yet` };\n if (status.members.length !== set.members.length) return { primary, healthy: false, why: `the set has ${status.members.length} members` };\n for (const member of status.members) {\n if (member.health !== 1) return { primary, healthy: false, why: `${member.name} is not healthy` };\n if (member.state !== \"PRIMARY\" && member.state !== \"SECONDARY\") return { primary, healthy: false, why: `${member.name} is ${member.state}` };\n if (member.optime !== primaries[0]!.optime) return { primary, healthy: false, why: `${member.name} is behind the primary` };\n }\n return { primary, healthy: true, why: \"healthy\" };\n};\n\n/** A replica set lab is one environment of a replica set cell. */\nexport interface ReplicaSetLab {\n readonly set: ReplicaSet;\n readonly clientIp: string;\n readonly members: Readonly<Record<string, RunPart>>;\n readonly netns: { readonly client: number };\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** These are the log lines of the members that a run keeps, in the sequence of their arrival, with `t` at 0. */\n readonly log: readonly MemberLine[];\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method waits until the set is whole and calm, and gives the name of its primary. */\n converge(within?: number): Promise<string>;\n /** This method removes each write from the set, and waits until each member has the removal. */\n flush(primary: string): Promise<void>;\n /**\n * This method lets each secondary stand for election again (`rs.freeze(0)`). A step-down holds its\n * old primary out of the elections for `STEP_DOWN.seconds`. Without it, a run inherits that hold.\n */\n unfreeze(primary: string): Promise<void>;\n /** This method gives the sequence numbers that the set holds, from its primary. */\n holds(primary: string): Promise<number[]>;\n /** This method gives the member that has a role in the set, when `primary` is the primary. */\n partOf(role: GroupRole, primary: string): string;\n /** This method starts the client of a run, with the arguments of `client-mongo.mjs`. */\n client(args: readonly string[]): Promise<GroupClient>;\n /** This method applies a network fault between a member and some of its peers, at once or at an instant of the VM. */\n fault(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes a network fault, at once or at an instant of the VM. */\n lift(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method sends a signal to the server process of a member, at once or at an instant of the VM. */\n signal(part: string, signal: \"KILL\" | \"STOP\" | \"CONT\", at?: number): Promise<Stamp>;\n /** This method starts the server of a member again, after a fin. */\n restart(member: string): Promise<void>;\n /** This method runs a command in the box of a member, and gives its output. */\n exec(member: string, argv: string[]): Promise<string>;\n /** This method runs a script of the shell on a member, against its own server only, and gives its output. Another port reads a server with no set. */\n script(member: string, script: string, port?: number): Promise<string>;\n /** This method runs a command on the backup host of a drill, and gives its output. A lab without that host refuses it. */\n vault(argv: string[]): Promise<string>;\n /** This method sends replSetStepDown to the primary. */\n stepDown(primary: string): Promise<Stamp>;\n /** This method removes the TCP metrics of the client namespace: each run starts from a kernel that keeps nothing. */\n forget(): Promise<void>;\n /** This method waits for the next clock line of the prober, which gives the count of lost records. */\n settle(): Promise<number | null>;\n manifest(sysctls: Readonly<Record<string, string>>): Promise<Manifest>;\n close(): Promise<void>;\n}\n\n/** This function waits for a time, in ms. */\nexport const sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** These are the arguments of replSetStepDown: the time that the old primary cannot stand again, and the wait for a secondary to catch up. */\nexport const STEP_DOWN = { seconds: 60, catchUp: 10 } as const;\n\n/**\n * This function opens one environment of a replica set cell:\n * - one new network, with each member, the client and the sender of a step-down on it.\n * - each member: the stock image, its server as the child of a shell. A log consumer reads its\n * JSON log. The first member starts the set with the address of each member, and the lab\n * waits for a primary.\n * - an injector sidecar for each member, in its network and process namespaces.\n * - a client that holds its own network namespace, with a privileged sidecar for its sysctls.\n * - the prober, which watches the namespace of the client.\n * - a backup host for a recovery drill: the stock image, for its tools, with no server.\n */\nexport const openReplicaSetLab = async (set: ReplicaSet, backups = false): Promise<ReplicaSetLab> => {\n const image = await harnessImage();\n const mongo = await mongoClientImage();\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n let network: StartedNetwork | undefined;\n const close = async () => {\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n await network?.stop().catch(() => undefined);\n };\n const ipOf = async (container: StartedTestContainer): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network!.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network!.getName()}`);\n return ip;\n };\n try {\n network = await new Network().start();\n const boxes = new Map<string, StartedTestContainer>();\n const injectors = new Map<string, StartedTestContainer>();\n const members: Record<string, RunPart> = {};\n const log: MemberLine[] = [];\n for (const name of set.members) {\n let partial = \"\";\n const box = await new GenericContainer(set.image)\n .withNetwork(network)\n .withNetworkAliases(name)\n .withCommand([\"sh\", \"-c\", `${memberCommand(set)} & echo $! > /tmp/server.pid; while :; do sleep 3600; done`])\n .withWaitStrategy(Wait.forLogMessage(set.ready))\n .withLogConsumer((stream) =>\n stream.on(\"data\", (chunk: Buffer | string) => {\n partial += chunk.toString();\n const split = partial.split(\"\\n\");\n partial = split.pop() ?? \"\";\n for (const text of split) {\n const line = memberLineOf(name, text.trim());\n if (line !== null) log.push(line);\n }\n }),\n )\n .start();\n opened.push(box);\n boxes.set(name, box);\n const injector = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${box.getId()}`,\n ).start();\n opened.push(injector);\n injectors.set(name, injector);\n members[name] = { ip: await ipOf(box), netns: await netnsOf(injector) };\n }\n const ips: Record<string, string> = Object.fromEntries(Object.entries(members).map(([name, at]) => [name, at.ip]));\n\n const holder = await new GenericContainer(image).withNetwork(network).start();\n opened.push(holder);\n const admin = await new GenericContainer(image).withNetworkMode(`container:${holder.getId()}`).withPrivilegedMode().start();\n opened.push(admin);\n const clientIp = await ipOf(holder);\n // the sender of a step-down is a client of its own, on the network but not in the watched namespace\n const commander = await new GenericContainer(mongo)\n .withNetwork(network)\n .withCommand([\"sh\", \"-c\", \"while :; do sleep 3600; done\"])\n .start();\n opened.push(commander);\n const backupHost = backups\n ? await new GenericContainer(set.image).withNetwork(network).withCommand([\"sh\", \"-c\", \"while :; do sleep 3600; done\"]).start()\n : null;\n if (backupHost !== null) opened.push(backupHost);\n\n const clientNetns = await netnsOf(admin);\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\"/opt/harness/prober\", String(clientNetns)])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n\n const box = (name: string): StartedTestContainer => {\n const found = boxes.get(name);\n if (found === undefined) throw new Error(`the set has no member ${name}`);\n return found;\n };\n const injectorOf = (name: string): StartedTestContainer => {\n const found = injectors.get(name);\n if (found === undefined) throw new Error(`the set has no member ${name}`);\n return found;\n };\n /** This function starts a script of the shell on a member, against its own server only. */\n const shell = (name: string, script: string, port: number = set.port): Promise<string> =>\n output(box(name), [\n set.programs.shell,\n \"--quiet\",\n \"--norc\",\n `mongodb://127.0.0.1:${port}/?directConnection=true&serverSelectionTimeoutMS=3000`,\n \"--eval\",\n script,\n ]);\n const lastLine = (text: string): string => text.split(\"\\n\").filter((line) => line.trim() !== \"\").at(-1) ?? \"\";\n const stamped = async (where: StartedTestContainer, argv: string[]): Promise<Stamp> => {\n const stamp = JSON.parse(lastLine(await output(where, argv))) as Stamp;\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const after = (at: number | undefined): string[] => (at === undefined ? [] : [\"--at\", String(Math.round(at))]);\n let known: string = set.members[0]!;\n /** This function gives the view of the set: from the member that was the primary last, then from each other member. */\n const view = async (): Promise<GroupView> => {\n let last: GroupView = { primary: null, healthy: false, why: \"no member answered\" };\n for (const name of [known, ...set.members.filter((each) => each !== known)]) {\n const read = await shell(name, STATUS_SCRIPT)\n .then((text) => statusViewOf(set, ips, JSON.parse(lastLine(text)) as Status))\n .catch((error: unknown) => ({ primary: null, healthy: false, why: `${name}: ${(error as Error).message.slice(0, 200)}` }));\n if (read.primary !== null && read.primary === name) return read;\n last = read;\n }\n return last;\n };\n const converge = async (within = CONVERGE_MS): Promise<string> => {\n const started = Date.now();\n let calm = 0;\n let last: GroupView = { primary: null, healthy: false, why: \"no view yet\" };\n while (Date.now() - started < within) {\n last = await view();\n // two healthy views in a row: one view can come in the middle of a change\n calm = last.healthy ? calm + 1 : 0;\n if (last.primary !== null) known = last.primary;\n if (calm >= 2 && last.primary !== null) return last.primary;\n await sleep(1_000);\n }\n throw new Error(`the set did not converge in ${within} ms: ${last.why}`);\n };\n\n // the first member starts the set, with the address of each member as the client reaches it\n const initiated = await shell(set.members[0]!, initiateScript(set, ips));\n if (!lastLine(initiated).includes('\"ok\":1')) throw new Error(`rs.initiate failed: ${lastLine(initiated)}`);\n await converge();\n\n return {\n set,\n clientIp,\n members,\n netns: { client: clientNetns },\n kernel: records.seen,\n log,\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values)) read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n converge,\n async flush(primary) {\n const script =\n `const r = db.getSiblingDB(\"cells\").w.deleteMany({}, { writeConcern: { w: ${set.members.length}, wtimeout: 10000 } }); ` +\n \"print(JSON.stringify({ ok: r.acknowledged === true }))\";\n const reply = lastLine(await shell(primary, script));\n if (!reply.includes('\"ok\":true')) throw new Error(`the flush failed: ${reply}`);\n },\n async unfreeze(primary) {\n for (const name of set.members) {\n if (name === primary) continue;\n const reply = lastLine(await shell(name, \"print(JSON.stringify(rs.freeze(0)))\"));\n if (!reply.includes('\"ok\":1')) throw new Error(`${name} did not unfreeze: ${reply}`);\n }\n },\n async holds(primary) {\n const script = 'print(JSON.stringify(db.getSiblingDB(\"cells\").w.find({}, { n: 1, _id: 0 }).toArray().map((d) => d.n)))';\n const held = JSON.parse(lastLine(await shell(primary, script))) as unknown[];\n return held\n .map(Number)\n .filter((n) => Number.isInteger(n) && n > 0)\n .sort((a, b) => a - b);\n },\n partOf(role, primary) {\n if (role === \"primary\") return primary;\n if (role === \"sentinel\") throw new Error(\"a replica set has no Sentinel\");\n const secondary = set.members.find((name) => name !== primary);\n if (secondary === undefined) throw new Error(\"the set has no secondary\");\n return secondary;\n },\n async client(args) {\n const events = lines<ProbeEvent>();\n const container = await new GenericContainer(mongo)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"node\", \"/opt/harness/mongo/client-mongo.mjs\", ...args])\n .withLogConsumer(events.consume)\n .start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n // a TERM first: the client writes its done line, then stops\n stop: () =>\n container\n .stop({ timeout: 2 })\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n fault(kind, part, cuts, at) {\n const cut = cutOf(set, members, clientIp, part, cuts);\n const direction = cut.direction === undefined ? [] : [\"--direction\", cut.direction];\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind, cut.peers.join(\",\"), ...direction, ...after(at)]);\n },\n lift(kind, part, cuts, at) {\n const cut = cutOf(set, members, clientIp, part, cuts);\n const direction = cut.direction === undefined ? [] : [\"--direction\", cut.direction];\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind === \"rst\" ? \"clear-rst\" : \"clear\", cut.peers.join(\",\"), ...direction, ...after(at)]);\n },\n signal(part, signal, at) {\n return stamped(injectorOf(part), [\"/opt/harness/inject\", \"signal\", set.programs.server, signal, ...after(at)]);\n },\n async restart(member) {\n // the restarted server writes to the output of the container, thus its log consumer reads it\n await output(box(member), [\"sh\", \"-c\", `${memberCommand(set)} > /proc/1/fd/1 2>&1 & echo $! > /tmp/server.pid`]);\n const started = Date.now();\n while (!(await shell(member, \"print(db.hello().ok)\").catch(() => \"\")).includes(\"1\")) {\n if (Date.now() - started > 60_000) throw new Error(`${member} did not start again`);\n await sleep(500);\n }\n },\n exec(member, argv) {\n return output(box(member), argv);\n },\n script: shell,\n vault(argv) {\n if (backupHost === null) throw new Error(\"this lab has no backup host\");\n return output(backupHost, argv);\n },\n stepDown(primary) {\n return stamped(commander, [\n \"node\",\n \"/opt/harness/mongo/stepdown-mongo.mjs\",\n `${members[primary]!.ip}:${set.port}`,\n String(STEP_DOWN.seconds),\n String(STEP_DOWN.catchUp),\n ]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n async settle() {\n const from = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const started = Date.now();\n const look = () => {\n const line = records.seen.slice(from).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - started > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) => runtime.container.inspect(runtime.container.getById(container.getId()));\n const script = \"print(JSON.stringify({ version: db.version(), settings: rs.conf().settings }))\";\n const list = [];\n for (const name of set.members) {\n const read = JSON.parse(lastLine(await shell(name, script))) as { version: string; settings: Record<string, unknown> };\n const settings: Record<string, string> = { version: read.version };\n for (const key of Object.keys(set.settings)) settings[key] = String(read.settings[key] ?? \"\");\n list.push({ name, ip: members[name]!.ip, id: (await inspect(box(name))).Image, settings });\n }\n return {\n kernel: await output(holder, [\"uname\", \"-r\"]),\n architecture: await output(holder, [\"uname\", \"-m\"]),\n hz: /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1] ?? null,\n boot_id: await output(holder, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n substrate: substrateHere(\"E1\"),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n target: { image: set.image, id: list[0]!.id, settings: list[0]!.settings, sysctls: {} },\n harness: {\n image,\n id: (await inspect(holder)).Image,\n packages: (await output(holder, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n ...harnessRecord(),\n },\n client: shippedClientRecord(\"mongodb\", mongo),\n netns: { client: clientNetns, target: members[set.members[0]!]!.netns },\n sysctls,\n group: { members: list, sentinels: [], observer: { image: mongo } },\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n\n// ---------------------------------------------------------------------------------------------\n// the runs of a replica set cell\n// ---------------------------------------------------------------------------------------------\n\n/** This count is the number of accepted writes that a run waits for before its fault: the stream is steady then. */\nexport const STEADY = 20;\n/** This time is how long a run continues after its outcome, so that the record shows what came next. */\nexport const TAIL_MS = 2_000;\n\n/** This function gives how long a run of a cell continues after its lift, in ms: the tail, and the watch of the cell. */\nexport const afterLiftOf = (cell: Cell): number => TAIL_MS + (cell.watch === undefined ? 0 : valueIn(cell.watch, \"s\") * 1000);\n\n/** This function gives the arguments of the client of a replica set cell: each member, and the stream of writes. */\nexport const replicaSetArgs = (cell: Cell, members: Readonly<Record<string, RunPart>>): string[] => {\n const set = cell.replicaSet!;\n const hosts = set.members.map((name) => `${members[name]!.ip}:${set.port}`);\n return [\n members[set.members[0]!]!.ip,\n String(set.port),\n \"--mode\",\n \"stream\",\n \"--hosts\",\n hosts.join(\",\"),\n \"--set\",\n set.name,\n \"--interval-ms\",\n String(cell.probe.interval === undefined ? 50 : valueIn(cell.probe.interval, \"ms\")),\n \"--max-s\",\n String(Math.ceil(deadlineOf(cell) / 1_000 + (cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\")) + (cell.drill === undefined ? 0 : drillSpan(cell.drill)) + 120)),\n \"--w\",\n String(cell.writeConcern ?? \"majority\"),\n ...(cell.driverOptions === undefined ? [] : [\"--options\", JSON.stringify(cell.driverOptions)]),\n ];\n};\n\n/** This function waits until a condition on the lines of the client holds, or for `within` ms. It gives the first line that matches. */\nexport const waitFor = (client: GroupClient, match: (event: ProbeEvent) => boolean, within: number): Promise<ProbeEvent | undefined> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const found = client.events.find(match);\n if (found !== undefined || Date.now() - started > within) resolve(found);\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nexport const droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1) if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/**\n * This function does one run of a replica set cell:\n * - The set converges, and its writes go. The client finds the primary with its monitors, and its\n * stream of writes gets steady.\n * - The fault occurs on its member, as the primary of this run makes the roles. A fault with a\n * hold lifts at its instant in the VM. A stall lifts at its length after the first write into\n * it. A step-down is replSetStepDown to the primary.\n * - The run waits for its outcome: the first accepted write of a write sent after the commit of\n * the fault. It is on a new primary, or on any primary. Then the run waits for the end of the\n * hold, thus the record shows what the set did in the whole hold.\n * - Each fault goes, the client stops, and the set converges again. The writes that it then holds\n * tell which writes it kept. The log lines of the members go onto the monotonic clock.\n */\nexport const replicaSetOnce = async (lab: ReplicaSetLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const set = cell.replicaSet!;\n const primary = await lab.converge();\n await lab.flush(primary);\n // each secondary can win an election: no hold of a step-down in an earlier run is left\n await lab.unfreeze(primary);\n await lab.forget();\n const from = lab.kernel.length;\n const logFrom = lab.log.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const client = await lab.client(replicaSetArgs(cell, lab.members));\n const lands = cell.prediction.group?.lands ?? \"new\";\n const place = (cell.faultAt ?? { role: \"primary\" }) as GroupPlace;\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n let at: string | null = null;\n const undo: Array<() => Promise<unknown>> = [];\n try {\n await client.until([\"ready\"], 60_000);\n const steady = await waitFor(client, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not write ${STEADY} times in 30 s`);\n let healing: Promise<Run[\"heal\"]> | null = null;\n switch (cell.fault) {\n case \"blackhole\":\n case \"partition\":\n case \"rst\": {\n const kind = cell.fault === \"rst\" ? \"rst\" : \"blackhole\";\n const cuts = place.cuts ?? (cell.fault === \"partition\" ? \"group\" : \"all\");\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.fault(kind, part, cuts);\n undo.push(() => lab.lift(kind, part, cuts));\n if (cell.stall !== undefined) {\n // the first write into the fault arms the retransmissions: the stall counts from it. A\n // write that was in flight at the commit holds the stream, and then the stall counts from\n // the commit. The measurement then voids the run\n const t1 = fault.t1;\n const sent = await waitFor(client, (event) => event.ev === \"sent\" && event.t > t1, 5_000);\n healing = lab.lift(kind, part, cuts, (sent?.t ?? t1) + valueIn(cell.stall, \"s\") * 1e9);\n } else if (cell.hold !== undefined) {\n healing = lab.lift(kind, part, cuts, fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n }\n break;\n }\n case \"freeze-process\": {\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.signal(part, \"STOP\");\n undo.push(() => lab.signal(part, \"CONT\"));\n if (cell.hold !== undefined) healing = lab.signal(part, \"CONT\", fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n break;\n }\n case \"fin\": {\n const part = lab.partOf(place.role, primary);\n at = part;\n fault = await lab.signal(part, \"KILL\");\n undo.push(() => lab.restart(part));\n break;\n }\n case \"step-down\":\n at = primary;\n fault = await lab.stepDown(primary);\n break;\n default:\n throw new Error(`a replica set cell has no fault ${cell.fault}`);\n }\n // the injector holds the lift in the VM: its exec returns at the instant, and the stamps come with it\n const healed =\n healing === null\n ? Promise.resolve(null)\n : healing.then((stamp) => {\n heal = stamp;\n // the lift came: nothing is left to undo\n undo.length = 0;\n return stamp;\n });\n // a run that stops early lifts the fault itself, and the late lift then has nothing to remove\n healed.catch(() => undefined);\n const t1 = fault.t1;\n const old = `${lab.members[primary]!.ip}:${set.port}`;\n const sentAt = (n: number): number => client.events.find((event) => event.ev === \"sent\" && Number(event[\"n\"]) === n)?.t ?? -Infinity;\n const outcome = await waitFor(\n client,\n (event) => event.ev === \"ack\" && sentAt(Number(event[\"n\"])) > t1 && (lands === \"same\" || (typeof event[\"at\"] === \"string\" && event[\"at\"] !== old)),\n deadlineOf(cell),\n );\n if (outcome !== undefined) await sleep(TAIL_MS);\n // the whole hold: a prediction that no failover occurs reads the set in each moment of it\n if (healing !== null) {\n await healed.catch(() => undefined);\n await sleep(afterLiftOf(cell));\n }\n } finally {\n // each fault that is still on goes, and a killed server starts again\n for (const step of undo.reverse()) await step().catch(() => undefined);\n await client.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge().catch(() => null);\n const holds = after === null ? null : await lab.holds(after);\n return {\n environment,\n index,\n events: [...client.events],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[primary]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: {},\n primary,\n at,\n timeline: onMonotonic(lab.log.slice(logFrom), clockOffsetOf(client.events)),\n after,\n holds,\n },\n };\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, Drill, ProbeEvent, Run, RunBackup } from \"./cell.ts\";\nimport type { GroupClient, Stamp } from \"./group.ts\";\nimport { deadlineOf } from \"./group.ts\";\nimport type { OplogTime } from \"./recovery.ts\";\nimport { HASH_SCRIPT, hashOf, highestHeld, readOplog, seedScript, sliceQuery, standaloneCommand, stopScript } from \"./recovery.ts\";\nimport type { ReplicaSetLab } from \"./replset.ts\";\nimport { STEADY, TAIL_MS, clockOffsetOf, droppedSoFar, initiateScript, onMonotonic, replicaSetArgs, sleep, waitFor } from \"./replset.ts\";\n\n/**\n * This module does one run of a recovery drill on the lab of a replica set. A drill stops the store\n * during writes, removes its disk, and recovers from real backups, or by an election.\n *\n * A backup is a real `mongodump`, on a host of its own. The dump has the oplog of its own time, and\n * each slice has the oplog after the backup before it. The fault comes at the age of the newest\n * backup, on the clock of the VM. Thus a run measures the worst case of its interval by construction.\n *\n * A restore cannot have a client of the set: the client writes to any primary. So the restore writes\n * to a server with no set, on its own port. That server then stops, each member starts with an empty\n * set, and the old primary starts the set. Only that member has the data, thus it wins.\n *\n * The driver refuses a primary with an election id under the highest one that it saw, and a new\n * set starts its ids again. So a restore has two clients. The first one writes up to the fault, and\n * the second one starts after the restore, with the sequence numbers that follow the first.\n */\n\n/** This folder is the store of the backups, on the backup host. */\nconst VAULT = \"/backup\";\n/** This time is the longest wait for a server to answer, in ms. */\nconst STARTS_WITHIN = 60_000;\n\n/** This function waits until a check holds, or it stops the run after `within` ms. */\nconst until = async (what: string, check: () => Promise<boolean>, within: number): Promise<void> => {\n const started = Date.now();\n while (!(await check().catch(() => false))) {\n if (Date.now() - started > within) throw new Error(`${what} did not come in ${within} ms`);\n await sleep(500);\n }\n};\n\n/** This function gives the time that the client sent a write. Zero is no write. */\nconst writeOf = (events: readonly ProbeEvent[], n: number): RunBackup[\"last\"] => {\n const sent = n === 0 ? undefined : events.find((event) => event.ev === \"sent\" && Number(event[\"n\"]) === n);\n return sent === undefined ? null : { n, t: sent.t };\n};\n\n/** This function gives the size of a folder of the backup host. */\nconst sizeOf = async (lab: ReplicaSetLab, path: string): Promise<RunBackup[\"size\"]> => {\n const [bytes] = (await lab.vault([\"du\", \"-sb\", path])).split(/\\s+/);\n return { value: Number(bytes), unit: \"B\" };\n};\n\n/** This function takes the dump with its oplog, and each slice of the oplog at its interval. It gives each backup in sequence. */\nconst backupsOf = async (lab: ReplicaSetLab, drill: Drill, primary: string, writer: GroupClient): Promise<RunBackup[]> => {\n const host = `${lab.members[primary]!.ip}:${lab.set.port}`;\n const started = Date.now();\n await lab.vault([\"mongodump\", \"--host\", host, \"--oplog\", \"--out\", `${VAULT}/dump-0`]);\n const ended = Date.now();\n const oplog = readOplog(await lab.vault([\"bsondump\", \"--quiet\", `${VAULT}/dump-0/oplog.bson`]));\n const held = highestHeld(await lab.vault([\"bsondump\", \"--quiet\", `${VAULT}/dump-0/cells/w.bson`]));\n if (oplog.last === null) throw new Error(\"the oplog of the dump has no entry\");\n let highest = Math.max(oplog.highest ?? 0, held ?? 0);\n let from: OplogTime = oplog.last;\n const backups: RunBackup[] = [{ kind: \"dump\", started, ended, last: writeOf(writer.events, highest), size: await sizeOf(lab, `${VAULT}/dump-0`) }];\n const every = valueIn(drill.sliceEvery, \"s\") * 1_000;\n for (let slice = 1; slice <= drill.slices; slice += 1) {\n await sleep(Math.max(0, ended + slice * every - Date.now()));\n const out = `${VAULT}/slice-${slice}`;\n const begun = Date.now();\n await lab.vault([\"mongodump\", \"--host\", host, \"--db\", \"local\", \"--collection\", \"oplog.rs\", \"--query\", sliceQuery(from), \"--out\", out]);\n const finished = Date.now();\n const read = readOplog(await lab.vault([\"bsondump\", \"--quiet\", `${out}/local/oplog.rs.bson`]));\n highest = Math.max(highest, read.highest ?? 0);\n from = read.last ?? from;\n backups.push({ kind: \"slice\", started: begun, ended: finished, last: writeOf(writer.events, highest), size: await sizeOf(lab, out) });\n }\n return backups;\n};\n\n/**\n * This function stops the server of each member that the drill loses, and it removes each disk. A\n * restore loses each member, and an election loses the primary. The fault comes at the age of the\n * drill after the last write of the newest backup. A control has no later write, and an election\n * has no backup: their age counts from this point. The stamp is the one of the primary.\n */\nconst lose = async (lab: ReplicaSetLab, drill: Drill, primary: string, last: RunBackup[\"last\"]): Promise<Stamp> => {\n const parts = drill.recovery === \"restore\" ? [primary, ...lab.set.members.filter((name) => name !== primary)] : [primary];\n const age = valueIn(drill.age, \"s\");\n const at = last === null || drill.quiet === true ? undefined : last.t + age * 1e9;\n if (at === undefined) await sleep(age * 1_000);\n const stamps = await Promise.all(parts.map((part) => lab.signal(part, \"KILL\", at)));\n for (const part of parts) {\n await lab.exec(part, [\"sh\", \"-c\", stopScript(false)]);\n await lab.exec(part, [\"find\", \"/data/db\", \"-mindepth\", \"1\", \"-delete\"]);\n }\n return stamps[0]!;\n};\n\n/**\n * This function restores the old primary from the backups and starts the set again:\n * - The slices go after the oplog of the dump, in their sequence, thus one replay does the whole restore.\n * - The restore writes to a server of the old primary with no set, on its own port.\n * - Each member that lost its disk starts before the set, because `rs.initiate` asks each member.\n * - The old primary starts the set. It has the data, and the other members make their first sync from it.\n */\nconst restore = async (lab: ReplicaSetLab, drill: Drill, primary: string): Promise<{ started: number; ended: number }> => {\n const { set } = lab;\n const started = Date.now();\n const port = set.port + 1;\n const slices = Array.from({ length: drill.slices }, (_, at) => `${VAULT}/slice-${at + 1}/local/oplog.rs.bson`);\n if (slices.length > 0) await lab.vault([\"sh\", \"-c\", `cat ${slices.join(\" \")} >> ${VAULT}/dump-0/oplog.bson`]);\n await lab.exec(primary, [\"sh\", \"-c\", `${standaloneCommand(set, port)} > /proc/1/fd/1 2>&1 & echo $! > /tmp/server.pid`]);\n await until(\"the server of the restore\", async () => (await lab.script(primary, \"print(db.hello().ok)\", port)).includes(\"1\"), STARTS_WITHIN);\n await lab.vault([\"mongorestore\", \"--host\", `${lab.members[primary]!.ip}:${port}`, \"--oplogReplay\", `${VAULT}/dump-0`]);\n await lab.exec(primary, [\"sh\", \"-c\", stopScript(true)]);\n for (const name of set.members) if (name !== primary) await lab.restart(name);\n await lab.restart(primary);\n const ips = Object.fromEntries(Object.entries(lab.members).map(([name, at]) => [name, at.ip]));\n const initiated = await lab.script(primary, initiateScript(set, ips));\n if (!initiated.includes('\"ok\":1')) throw new Error(`rs.initiate failed after the restore: ${initiated}`);\n await until(\"the primary after the restore\", async () => (await lab.script(primary, \"print(db.hello().isWritablePrimary)\")).includes(\"true\"), STARTS_WITHIN);\n return { started, ended: Date.now() };\n};\n\n/**\n * This function does one run of a recovery drill:\n * - The set converges, and it loses its writes. The tenants get their data, and a hash reads it.\n * - The client writes until its stream is steady. A control stops it here.\n * - The backups go, each at its interval. The fault comes at the age of the newest backup.\n * - An election continues the same client. A restore stops the client, and it starts a second one.\n * - The set converges again. The writes that it then holds tell which writes it kept, and a second\n * hash tells if the tenants have the same data.\n */\nexport const drillOnce = async (lab: ReplicaSetLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const drill = cell.drill!;\n const { set } = lab;\n const primary = await lab.converge();\n await lab.flush(primary);\n await lab.unfreeze(primary);\n await lab.forget();\n await lab.vault([\"sh\", \"-c\", `rm -rf ${VAULT} && mkdir -p ${VAULT}`]);\n const seeded = await lab.script(primary, seedScript(drill, set.members.length));\n if (!seeded.includes('\"ok\":true')) throw new Error(`the seed failed: ${seeded}`);\n const before = hashOf(await lab.script(primary, HASH_SCRIPT));\n const tool = (await lab.vault([\"mongodump\", \"--version\"])).split(\"\\n\")[0]!.trim();\n const from = lab.kernel.length;\n const logFrom = lab.log.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const writer = await lab.client(replicaSetArgs(cell, lab.members));\n const restores = drill.recovery === \"restore\";\n let successor: GroupClient | null = null;\n let second: number | null = null;\n let fault: Run[\"fault\"] = null;\n let restored: { started: number; ended: number } | null = null;\n const backups: RunBackup[] = [];\n try {\n await writer.until([\"ready\"], 60_000);\n const steady = await waitFor(writer, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not write ${STEADY} times in 30 s`);\n if (drill.quiet === true) await writer.stop();\n if (restores) backups.push(...(await backupsOf(lab, drill, primary, writer)));\n const stamp = await lose(lab, drill, primary, backups.at(-1)?.last ?? null);\n fault = stamp;\n if (restores) {\n await writer.stop();\n restored = await restore(lab, drill, primary);\n second = Math.max(0, ...writer.events.filter((event) => event.ev === \"sent\").map((event) => Number(event[\"n\"]))) + 1;\n successor = await lab.client([...replicaSetArgs(cell, lab.members), \"--from\", String(second)]);\n const answered = await waitFor(successor, (event) => event.ev === \"ack\", deadlineOf(cell));\n if (answered !== undefined) await sleep(TAIL_MS);\n } else {\n const old = `${lab.members[primary]!.ip}:${set.port}`;\n const sentAt = (n: number): number => writer.events.find((event) => event.ev === \"sent\" && Number(event[\"n\"]) === n)?.t ?? -Infinity;\n const answered = await waitFor(\n writer,\n (event) => event.ev === \"ack\" && sentAt(Number(event[\"n\"])) > stamp.t1 && typeof event[\"at\"] === \"string\" && event[\"at\"] !== old,\n deadlineOf(cell),\n );\n if (answered !== undefined) await sleep(TAIL_MS);\n await lab.restart(primary);\n }\n } finally {\n await writer.stop();\n await successor?.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge().catch(() => null);\n const holds = after === null ? null : await lab.holds(after);\n const hash = after === null ? null : hashOf(await lab.script(after, HASH_SCRIPT));\n const events = [...writer.events, ...(successor?.events ?? [])].sort((a, b) => a.t - b.t);\n return {\n environment,\n index,\n events,\n fault,\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[primary]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: {},\n primary,\n at: primary,\n timeline: onMonotonic(lab.log.slice(logFrom), clockOffsetOf(events)),\n after,\n holds,\n drill: { tool, seed: \"generated\", backups, before, after: hash, restored, second },\n },\n };\n};\n","import type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, Cluster, GroupPlace, GroupRole, KernelRecord, ProbeEvent, Run, RunPart, SentinelEvent } from \"./cell.ts\";\nimport type { GroupClient, GroupNetworkFault, GroupView, Stamp } from \"./group.ts\";\nimport { CONVERGE_MS, deadlineOf } from \"./group.ts\";\nimport { amqpClientImage, harnessImage } from \"./image.ts\";\nimport type { Manifest } from \"./lab.ts\";\nimport { STOP, containers, harnessRecord, lines, netnsOf, output, shippedClientRecord, withPid } from \"./lab.ts\";\nimport type { Cut } from \"./replset.ts\";\nimport { clockOffsetOf } from \"./replset.ts\";\nimport { substrateHere } from \"./substrate.ts\";\n\n/**\n * This module is the lab of a cluster of RabbitMQ with one quorum queue. The members of the queue\n * elect its leader by Raft, one member on each node. It opens one environment for a cluster cell,\n * for the runs of the cell. Each node is a container from the stock image of the cluster, in its own\n * network namespace. An injector sidecar shares its network and process namespaces.\n *\n * The client of each run is amqplib. It publishes a stream of sequence numbers with confirms through\n * one node, and it connects to the next node when its connection ends. The timeline comes from\n * the log of each node and from the lines of the client. The prober watches the namespace of the client.\n */\n\n/**\n * A node line is one log line of a node, as RabbitMQ writes it to its console. `real` is its time on\n * the wall clock in ms, with its microseconds. `t` is its time on the monotonic clock: the run gives\n * it from the clock lines of its client.\n */\nexport interface NodeLine extends SentinelEvent {\n readonly ev: \"rabbit\";\n readonly member: string;\n readonly real: number;\n readonly level: string;\n readonly msg: string;\n}\n\n/** This form is a line of the console log of RabbitMQ 4.3: the time with its offset, the level, the process and the message. */\nconst LINE = /^(\\d{4}-\\d\\d-\\d\\d) (\\d\\d:\\d\\d:\\d\\d)\\.(\\d{3})(\\d*)([+-]\\d\\d:\\d\\d) \\[(\\w+)\\] <[^>]*> (.*)$/;\n\n/** This form is an escape of ANSI: RabbitMQ colors each line of its console by its level. */\nconst ANSI = new RegExp(String.fromCharCode(27) + \"\\\\[[0-9;]*m\", \"g\");\n\n/** This function gives a line of the console without its colors. */\nexport const plainOf = (text: string): string => text.replace(ANSI, \"\").trim();\n\n/** This text is the name of a quorum queue in the log of Ra: its friendly name. */\nexport const logNameOf = (queue: string): string => `queue '${queue}' in vhost '/'`;\n\n/**\n * This function reads one log line of a node, or gives null for a line that a run does not keep. A\n * run keeps each line of the queue, each warning and each error, and each line of the maintenance\n * mode of a drain.\n */\nexport const nodeLineOf = (member: string, text: string, queue: string): NodeLine | null => {\n const found = LINE.exec(plainOf(text));\n if (found === null) return null;\n const [, day, time, ms, us, offset, level, msg] = found as unknown as [string, string, string, string, string, string, string, string];\n const kept = msg.includes(logNameOf(queue)) || level === \"warning\" || level === \"error\" || msg.includes(\"maintenance\");\n if (!kept) return null;\n const real = Date.parse(`${day}T${time}.${ms}${offset}`) + (us === \"\" ? 0 : Number(`0.${us}`));\n if (!Number.isFinite(real)) return null;\n return { ev: \"rabbit\", t: 0, member, real, level, msg };\n};\n\n/** This function puts the log lines of the nodes on the monotonic clock, with the offset of a client. */\nexport const nodesOnMonotonic = (log: readonly NodeLine[], offset: number | null): NodeLine[] =>\n log.map((line) => ({ ...line, t: offset === null ? 0 : Math.round(line.real * 1e6 - offset) }));\n\n/**\n * This function reads the JSON output of a tool of RabbitMQ (`--formatter json`). The tools print a\n * value over one line or over more than one, thus it reads from the first bracket to the end.\n */\nexport const toolJsonOf = (text: string): unknown => {\n const at = text.search(/[[{]/);\n if (at === -1) throw new Error(`no JSON in the output: ${text.slice(0, 200)}`);\n return JSON.parse(text.slice(at));\n};\n\n/** This function gives the name of a node in the Erlang distribution: `rabbit@<name>`. */\nexport const nodeNameOf = (member: string): string => `rabbit@${member}`;\n\n/**\n * This function gives the file of rabbitmq.conf of each node. The nodes form the cluster from the list\n * of their names, and the user guest connects from each address. The lines of the cluster come last.\n */\nexport const clusterConf = (cluster: Cluster): string =>\n [\n \"cluster_formation.peer_discovery_backend = classic_config\",\n ...cluster.members.map((name, at) => `cluster_formation.classic_config.nodes.${at + 1} = ${nodeNameOf(name)}`),\n \"loopback_users.guest = false\",\n ...cluster.conf,\n \"\",\n ].join(\"\\n\");\n\n/**\n * This function gives the command of each node. It writes the cookie of the server and of the tools.\n * Then it starts the server as the child of a shell. A fin can then stop the server, and the container\n * stays up.\n */\nexport const nodeCommand = (cluster: Cluster): string =>\n [\n \"for f in /var/lib/rabbitmq/.erlang.cookie /root/.erlang.cookie; do cp /tmp/cookie $f; chmod 400 $f; done\",\n \"chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie\",\n // a command in the background ends with its &, and the shell takes no ; after it\n `${cluster.programs.start} & while :; do sleep 3600; done`,\n ].join(\"; \");\n\n/** A status row is one member of the queue in the output of `rabbitmq-queues quorum_status`. */\nexport interface StatusRow {\n readonly \"Node Name\": string;\n readonly \"Raft State\": string;\n readonly Term: number | string;\n readonly \"Commit Index\": number | string;\n}\n\n/**\n * This function judges the status of the queue: its leader, and if the queue is healthy. A healthy\n * queue has one leader and a follower on each other node. Each follower is in the term of the leader,\n * at the commit index of the leader.\n */\nexport const clusterViewOf = (cluster: Cluster, rows: readonly StatusRow[]): GroupView => {\n const byNode = new Map(cluster.members.map((name) => [nodeNameOf(name), name]));\n const leaders = rows.filter((row) => row[\"Raft State\"] === \"leader\");\n if (leaders.length !== 1) return { primary: null, healthy: false, why: `the queue has ${leaders.length} leaders` };\n const leader = leaders[0]!;\n const primary = byNode.get(leader[\"Node Name\"]) ?? null;\n if (primary === null) return { primary: null, healthy: false, why: `no node has the name ${leader[\"Node Name\"]}` };\n if (rows.length !== cluster.members.length) return { primary, healthy: false, why: `the queue has ${rows.length} members` };\n for (const row of rows) {\n if (row !== leader && row[\"Raft State\"] !== \"follower\") return { primary, healthy: false, why: `${row[\"Node Name\"]} is ${row[\"Raft State\"]}` };\n if (row.Term !== leader.Term) return { primary, healthy: false, why: `${row[\"Node Name\"]} is in term ${row.Term}` };\n if (row[\"Commit Index\"] !== leader[\"Commit Index\"]) return { primary, healthy: false, why: `${row[\"Node Name\"]} is behind the leader` };\n }\n return { primary, healthy: true, why: \"healthy\" };\n};\n\n/**\n * This function gives the peers that a fault on a node cuts it from. `all` is each other node and the\n * client, `group` is the other nodes, and `clients` is the client. `one` is the first other node in\n * the sequence of the cluster, and `one-way` is the same node for the segments from the part only.\n * `to-clients` is the client, for the segments from the part only.\n */\nexport const clusterCutOf = (\n cluster: Cluster,\n members: Readonly<Record<string, RunPart>>,\n client: string,\n part: string,\n cuts: NonNullable<GroupPlace[\"cuts\"]>,\n): Cut => {\n const others = cluster.members.filter((name) => name !== part).map((name) => members[name]!.ip);\n if (cuts === \"clients\") return { peers: [client] };\n if (cuts === \"group\") return { peers: others };\n if (cuts === \"one\") return { peers: others.slice(0, 1) };\n if (cuts === \"one-way\") return { peers: others.slice(0, 1), direction: \"out\" };\n if (cuts === \"to-clients\") return { peers: [client], direction: \"out\" };\n return { peers: [...others, client] };\n};\n\n/** A wall stamp is the wall clock in ns around a command of a node: the run puts it on the monotonic clock. */\nexport interface WallStamp {\n readonly wall0: number;\n readonly wall1: number;\n}\n\n/** A cluster lab is one environment of a cluster cell. */\nexport interface ClusterLab {\n readonly cluster: Cluster;\n readonly clientIp: string;\n readonly members: Readonly<Record<string, RunPart>>;\n readonly netns: { readonly client: number };\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** These are the log lines of the nodes that a run keeps, in the sequence of their arrival, with `t` at 0. */\n readonly log: readonly NodeLine[];\n /** These are the last raw lines of the console of each node, for the diagnosis of a lab: at most RAW_TAIL of each. */\n readonly raw: Readonly<Record<string, readonly string[]>>;\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method waits until the queue is whole and calm, and gives the name of the node of its leader. */\n converge(within?: number): Promise<string>;\n /** This method removes each message from the queue. */\n flush(leader: string): Promise<void>;\n /** This method gives the sequence numbers that the queue holds, through the node of its leader. The queue is empty after it. */\n holds(leader: string): Promise<number[]>;\n /** This method gives the node that has a role, when `leader` is the node of the leader. The role is the leader, or a follower. */\n partOf(role: GroupRole, leader: string): string;\n /** This method starts the client of a run, with the arguments of `client-cluster.mjs`. */\n client(args: readonly string[]): Promise<GroupClient>;\n /** This method applies a network fault between a node and some of its peers, at once or at an instant of the VM. */\n fault(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes a network fault, at once or at an instant of the VM. */\n lift(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method sends a signal to the server process of a node, at once or at an instant of the VM. */\n signal(part: string, signal: \"KILL\" | \"STOP\" | \"CONT\", at?: number): Promise<Stamp>;\n /** This method starts the server of a node again, after a fin. */\n restart(member: string): Promise<void>;\n /** This method moves the leadership of the queue from the node of `leader` to the node `to`: `rabbitmq-queues transfer_leadership`. */\n stepDown(leader: string, to: string): Promise<WallStamp>;\n /** This method puts a node in maintenance mode (`rabbitmq-upgrade drain`). */\n drain(member: string): Promise<WallStamp>;\n /** This method ends the maintenance mode of a node (`rabbitmq-upgrade revive`). */\n revive(member: string): Promise<void>;\n /** This method removes the TCP metrics of the client namespace: each run starts from a kernel that keeps nothing. */\n forget(): Promise<void>;\n /** This method waits for the next clock line of the prober, which gives the count of lost records. */\n settle(): Promise<number | null>;\n manifest(sysctls: Readonly<Record<string, string>>): Promise<Manifest>;\n close(): Promise<void>;\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** This count is the number of raw lines of the console of each node that a lab keeps. */\nexport const RAW_TAIL = 400;\n\n/**\n * This function opens one environment of a cluster cell:\n * - one new network, with each node, the client and the admin on it.\n * - each node: the stock image, its server as the child of a shell, with its hostname as the name of\n * the node. A log consumer reads its console. The nodes form the cluster from the list of their\n * names, and the lab waits until each node runs in it.\n * - the admin declares the quorum queue on the first node, thus its member there is the first leader.\n * - an injector sidecar for each node, in its network and process namespaces.\n * - a client that holds its own network namespace, with a privileged sidecar for its sysctls.\n * - the prober, which watches the namespace of the client.\n */\nexport const openClusterLab = async (cluster: Cluster): Promise<ClusterLab> => {\n const image = await harnessImage();\n const amqp = await amqpClientImage();\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n let network: StartedNetwork | undefined;\n const close = async () => {\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n await network?.stop().catch(() => undefined);\n };\n const ipOf = async (container: StartedTestContainer): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network!.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network!.getName()}`);\n return ip;\n };\n try {\n network = await new Network().start();\n const boxes = new Map<string, StartedTestContainer>();\n const injectors = new Map<string, StartedTestContainer>();\n const members: Record<string, RunPart> = {};\n const log: NodeLine[] = [];\n const raw: Record<string, string[]> = {};\n for (const name of cluster.members) {\n let partial = \"\";\n const box = await new GenericContainer(cluster.image)\n .withNetwork(network)\n .withNetworkAliases(name)\n .withHostname(name)\n .withCopyContentToContainer([\n { content: clusterConf(cluster), target: \"/etc/rabbitmq/conf.d/90-harness.conf\" },\n { content: cluster.cookie, target: \"/tmp/cookie\" },\n ])\n .withCommand([\"sh\", \"-c\", nodeCommand(cluster)])\n .withWaitStrategy(Wait.forLogMessage(cluster.ready))\n .withStartupTimeout(180_000)\n .withLogConsumer((stream) =>\n stream.on(\"data\", (chunk: Buffer | string) => {\n partial += chunk.toString();\n const split = partial.split(\"\\n\");\n partial = split.pop() ?? \"\";\n for (const text of split) {\n const tail = (raw[name] ??= []);\n tail.push(text);\n if (tail.length > RAW_TAIL) tail.shift();\n const line = nodeLineOf(name, text.trim(), cluster.queue);\n if (line !== null) log.push(line);\n }\n }),\n )\n .start();\n opened.push(box);\n boxes.set(name, box);\n const injector = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${box.getId()}`,\n ).start();\n opened.push(injector);\n injectors.set(name, injector);\n members[name] = { ip: await ipOf(box), netns: await netnsOf(injector) };\n }\n\n const holder = await new GenericContainer(image).withNetwork(network).start();\n opened.push(holder);\n const admin = await new GenericContainer(image).withNetworkMode(`container:${holder.getId()}`).withPrivilegedMode().start();\n opened.push(admin);\n const clientIp = await ipOf(holder);\n // the admin of the queue is a client of its own, on the network but not in the watched namespace\n const commander = await new GenericContainer(amqp)\n .withNetwork(network)\n .withCommand([\"sh\", \"-c\", \"while :; do sleep 3600; done\"])\n .start();\n opened.push(commander);\n\n const clientNetns = await netnsOf(admin);\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\"/opt/harness/prober\", String(clientNetns)])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n\n const box = (name: string): StartedTestContainer => {\n const found = boxes.get(name);\n if (found === undefined) throw new Error(`the cluster has no node ${name}`);\n return found;\n };\n const injectorOf = (name: string): StartedTestContainer => {\n const found = injectors.get(name);\n if (found === undefined) throw new Error(`the cluster has no node ${name}`);\n return found;\n };\n const lastLine = (text: string): string => text.split(\"\\n\").filter((line) => line.trim() !== \"\").at(-1) ?? \"\";\n const stamped = async (where: StartedTestContainer, argv: string[]): Promise<Stamp> => {\n const stamp = JSON.parse(lastLine(await output(where, argv))) as Stamp;\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const after = (at: number | undefined): string[] => (at === undefined ? [] : [\"--at\", String(Math.round(at))]);\n /** This function runs a command of the tools of RabbitMQ on a node, between two stamps of its wall clock. */\n const walled = async (name: string, command: string): Promise<WallStamp> => {\n const text = await output(box(name), [\"sh\", \"-c\", `date +%s%N; ${command} >&2; date +%s%N`]);\n const stamps = text\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => /^\\d{18,}$/.test(line))\n .map(Number);\n if (stamps.length < 2) throw new Error(`${name}: no stamps around ${command}: ${text.slice(0, 300)}`);\n return { wall0: stamps[0]!, wall1: stamps.at(-1)! };\n };\n const status = async (name: string): Promise<GroupView> => {\n const text = await output(box(name), [\"rabbitmq-queues\", \"-q\", \"quorum_status\", cluster.queue, \"--formatter\", \"json\"]);\n return clusterViewOf(cluster, toolJsonOf(text) as StatusRow[]);\n };\n let known: string = cluster.members[0]!;\n /** This function gives the view of the queue: from the node that had the leader last, then from each other node. */\n const view = async (): Promise<GroupView> => {\n let last: GroupView = { primary: null, healthy: false, why: \"no node answered\" };\n for (const name of [known, ...cluster.members.filter((each) => each !== known)]) {\n const read = await status(name).catch((error: unknown) => ({ primary: null, healthy: false, why: `${name}: ${(error as Error).message.slice(0, 200)}` }));\n if (read.primary !== null) return read;\n last = read;\n }\n return last;\n };\n const converge = async (within = CONVERGE_MS): Promise<string> => {\n const started = Date.now();\n let calm = 0;\n let last: GroupView = { primary: null, healthy: false, why: \"no view yet\" };\n while (Date.now() - started < within) {\n last = await view();\n // two healthy views in a row: one view can come in the middle of a change\n calm = last.healthy ? calm + 1 : 0;\n if (last.primary !== null) known = last.primary;\n if (calm >= 2 && last.primary !== null) return last.primary;\n await sleep(1_000);\n }\n throw new Error(`the queue did not converge in ${within} ms: ${last.why}`);\n };\n\n // each node runs in the cluster, and then the first node declares the queue\n const started = Date.now();\n for (;;) {\n const text = await output(box(cluster.members[0]!), [\"rabbitmq-diagnostics\", \"-q\", \"cluster_status\", \"--formatter\", \"json\"]).catch(() => \"{}\");\n const running = ((text.trim() === \"\" ? {} : toolJsonOf(text)) as { running_nodes?: string[] }).running_nodes ?? [];\n if (cluster.members.every((name) => running.includes(nodeNameOf(name)))) break;\n if (Date.now() - started > 120_000) throw new Error(`the cluster did not form in 120 s: ${running.join(\", \")} run`);\n await sleep(1_000);\n }\n const declared = lastLine(await output(commander, [\"node\", \"/opt/harness/amqp/admin-cluster.mjs\", `${members[cluster.members[0]!]!.ip}:${cluster.port}`, \"declare\", cluster.queue]));\n if (!declared.includes('\"ok\":true')) throw new Error(`the declare of the queue failed: ${declared}`);\n await converge();\n\n return {\n cluster,\n clientIp,\n members,\n netns: { client: clientNetns },\n kernel: records.seen,\n log,\n raw,\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values)) read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n converge,\n async flush(leader) {\n await output(box(leader), [\"rabbitmqctl\", \"-q\", \"purge_queue\", cluster.queue]);\n },\n async holds(leader) {\n const reply = lastLine(await output(commander, [\"node\", \"/opt/harness/amqp/admin-cluster.mjs\", `${members[leader]!.ip}:${cluster.port}`, \"holds\", cluster.queue]));\n const held = (JSON.parse(reply) as { held?: unknown[] }).held;\n if (held === undefined) throw new Error(`the read of the queue failed: ${reply}`);\n return held.map(Number).filter((n) => Number.isInteger(n) && n > 0);\n },\n partOf(role, leader) {\n if (role === \"primary\") return leader;\n if (role === \"sentinel\") throw new Error(\"a cluster has no Sentinel\");\n const follower = cluster.members.find((name) => name !== leader);\n if (follower === undefined) throw new Error(\"the cluster has no follower\");\n return follower;\n },\n async client(args) {\n const events = lines<ProbeEvent>();\n const container = await new GenericContainer(amqp)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"node\", \"/opt/harness/amqp/client-cluster.mjs\", ...args])\n .withLogConsumer(events.consume)\n .start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n // a TERM first: the client writes its done line, then stops\n stop: () =>\n container\n .stop({ timeout: 2 })\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n fault(kind, part, cuts, at) {\n const cut = clusterCutOf(cluster, members, clientIp, part, cuts);\n const direction = cut.direction === undefined ? [] : [\"--direction\", cut.direction];\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind, cut.peers.join(\",\"), ...direction, ...after(at)]);\n },\n lift(kind, part, cuts, at) {\n const cut = clusterCutOf(cluster, members, clientIp, part, cuts);\n const direction = cut.direction === undefined ? [] : [\"--direction\", cut.direction];\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind === \"rst\" ? \"clear-rst\" : \"clear\", cut.peers.join(\",\"), ...direction, ...after(at)]);\n },\n signal(part, signal, at) {\n return stamped(injectorOf(part), [\"/opt/harness/inject\", \"signal\", cluster.programs.server, signal, ...after(at)]);\n },\n async restart(member) {\n // the restarted server writes to the output of the container, thus its log consumer reads it\n await output(box(member), [\"sh\", \"-c\", `${cluster.programs.start} > /proc/1/fd/1 2>&1 &`]);\n const begun = Date.now();\n while (!(await output(box(member), [\"rabbitmq-diagnostics\", \"-q\", \"check_running\"]).then(() => true).catch(() => false))) {\n if (Date.now() - begun > 120_000) throw new Error(`${member} did not start again`);\n await sleep(1_000);\n }\n },\n stepDown(leader, to) {\n return walled(leader, `rabbitmq-queues -q transfer_leadership ${cluster.queue} ${nodeNameOf(to)}`);\n },\n drain(member) {\n return walled(member, \"rabbitmq-upgrade -q drain\");\n },\n async revive(member) {\n await output(box(member), [\"rabbitmq-upgrade\", \"-q\", \"revive\"]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n async settle() {\n const from = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const begun = Date.now();\n const look = () => {\n const line = records.seen.slice(from).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - begun > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) => runtime.container.inspect(runtime.container.getById(container.getId()));\n const list = [];\n for (const name of cluster.members) {\n const version = lastLine(await output(box(name), [\"rabbitmqctl\", \"-q\", \"version\"]).catch(() => \"\"));\n list.push({ name, ip: members[name]!.ip, id: (await inspect(box(name))).Image, settings: { version, conf: cluster.conf.join(\"; \") } });\n }\n return {\n kernel: await output(holder, [\"uname\", \"-r\"]),\n architecture: await output(holder, [\"uname\", \"-m\"]),\n hz: /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1] ?? null,\n boot_id: await output(holder, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n substrate: substrateHere(\"E1\"),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n target: { image: cluster.image, id: list[0]!.id, settings: list[0]!.settings, sysctls: {} },\n harness: {\n image,\n id: (await inspect(holder)).Image,\n packages: (await output(holder, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n ...harnessRecord(),\n },\n client: shippedClientRecord(\"amqp\", amqp),\n netns: { client: clientNetns, target: members[cluster.members[0]!]!.netns },\n sysctls,\n group: { members: list, sentinels: [], observer: { image: amqp } },\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n\n// ---------------------------------------------------------------------------------------------\n// the runs of a cluster cell\n// ---------------------------------------------------------------------------------------------\n\n/** This count is the number of confirmed publishes that a run waits for before its fault: the stream is steady then. */\nconst STEADY = 20;\n/** This time is how long a run continues after its outcome, so that the record shows what came next. */\nconst TAIL_MS = 2_000;\n\n/**\n * This function gives the hosts of the client, in the sequence of its connects: its node first, then\n * each other node. The node of a follower is the last follower in the sequence of the cluster. A fault\n * on one member (`one`, `one-way`) cuts the first follower, thus not the node of the client.\n */\nexport const clusterHostsOf = (cell: Cell, members: Readonly<Record<string, RunPart>>, leader: string): string[] => {\n const cluster = cell.cluster!;\n const first = cell.clientAt === \"leader\" ? leader : cluster.members.filter((name) => name !== leader).at(-1)!;\n return [first, ...cluster.members.filter((name) => name !== first)].map((name) => `${members[name]!.ip}:${cluster.port}`);\n};\n\n/** This form is the NOTICE of a leader of the queue that starts to give its leadership away: to await_condition, for a transfer. */\nexport const GIVES_AWAY: RegExp = /: leader -> await_condition in term/;\n/** This form is the INFO of a follower whose monitor of the leader goes down (ra_server_proc.erl:871). A drain stops the leader so. */\nexport const MONITOR_DOWN: RegExp = /Leader monitor down/;\n\n/** This function gives the arguments of the client of a cluster cell: its hosts, the queue, and the stream of publishes. */\nexport const clusterArgs = (cell: Cell, members: Readonly<Record<string, RunPart>>, leader: string): string[] => [\n clusterHostsOf(cell, members, leader).join(\",\"),\n \"--queue\",\n cell.cluster!.queue,\n \"--interval-ms\",\n String(cell.probe.interval === undefined ? 50 : valueIn(cell.probe.interval, \"ms\")),\n \"--max-s\",\n String(Math.ceil(deadlineOf(cell) / 1_000 + (cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\")) + 120)),\n ...(cell.driverOptions === undefined ? [] : [\"--options\", JSON.stringify(cell.driverOptions)]),\n];\n\n/** This function waits until a condition on the lines of the client holds, or for `within` ms. It gives the first line that matches. */\nconst waitFor = (client: GroupClient, match: (event: ProbeEvent) => boolean, within: number): Promise<ProbeEvent | undefined> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const found = client.events.find(match);\n if (found !== undefined || Date.now() - started > within) resolve(found);\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1) if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/** This function puts a wall stamp on the monotonic clock, with the clock lines of the client. Without one it gives null. */\nexport const monotonicOf = (stamp: WallStamp, events: readonly ProbeEvent[]): Stamp | null => {\n const offset = clockOffsetOf(events);\n return offset === null ? null : { t0: Math.round(stamp.wall0 - offset), t1: Math.round(stamp.wall1 - offset) };\n};\n\n/**\n * This function gives the instant of a change of the leader that a command of the tools starts, as the\n * stamps of a fault. The command starts an Erlang VM first, thus its stamps hold more than the change.\n * A line of the log marks the start of the change. For a step-down it is the NOTICE of the old leader\n * (ra_server_proc.erl:1336-1345), and for a drain the INFO of a follower. Its time on the monotonic\n * clock is the stamp. Without that line, the stamps of the command are the stamps.\n */\nconst stampOf = async (\n lab: ClusterLab,\n client: GroupClient,\n logFrom: number,\n marks: (line: NodeLine) => boolean,\n wall: WallStamp,\n): Promise<{ readonly stamp: Stamp | null; readonly line: NodeLine | null }> => {\n const started = Date.now();\n while (Date.now() - started < 5_000) {\n const lines = nodesOnMonotonic(lab.log.slice(logFrom), clockOffsetOf(client.events));\n const line = lines.find(marks);\n if (line !== undefined && line.t > 0) return { stamp: { t0: line.t, t1: line.t }, line };\n await sleep(100);\n }\n return { stamp: monotonicOf(wall, client.events), line: null };\n};\n\n/**\n * This function puts the stamp of a fault from a line of the log on the monotonic clock again. It uses\n * the offset of all the clock lines of the client, as the timeline of the run does. Thus the line of the\n * stamp is at the stamp. The offset of the clock lines at the fault can be up to 1 ms smaller.\n */\nexport const restamped = (line: NodeLine, events: readonly ProbeEvent[]): Stamp | null => {\n const [on] = nodesOnMonotonic([line], clockOffsetOf(events));\n return on === undefined || on.t <= 0 ? null : { t0: on.t, t1: on.t };\n};\n\n/**\n * This function does one run of a cluster cell:\n * - The queue converges, and it is empty. The client connects through its node, and its stream of\n * publishes gets steady.\n * - The fault occurs on its node, as the leader of this run makes the roles. A fault with a hold\n * lifts at its instant in the VM. A step-down moves the leadership to a follower, and a drain puts\n * the node in maintenance mode. The stamp of each of them is a line of the log (`stampOf`).\n * - The run waits for its outcome: the first confirm of a publish sent after the commit of the fault.\n * Then it waits for the end of the hold, thus the record shows what the cluster did in the whole hold.\n * - Each fault goes, the client stops, and the queue converges again. The sequence numbers that it\n * then holds tell which publishes it kept. The log lines of the nodes go onto the monotonic clock.\n */\nexport const clusterOnce = async (lab: ClusterLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const leader = await lab.converge();\n await lab.flush(leader);\n await lab.forget();\n const from = lab.kernel.length;\n const logFrom = lab.log.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const client = await lab.client(clusterArgs(cell, lab.members, leader));\n const place = (cell.faultAt ?? { role: \"primary\" }) as GroupPlace;\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n let at: string | null = null;\n let wall: WallStamp | null = null;\n // the line of the log that gives the stamp of a step-down or of a drain\n let stampLine: NodeLine | null = null;\n const undo: Array<() => Promise<unknown>> = [];\n try {\n await client.until([\"ready\"], 60_000);\n const steady = await waitFor(client, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not publish ${STEADY} times in 30 s`);\n let healing: Promise<Run[\"heal\"]> | null = null;\n switch (cell.fault) {\n case \"blackhole\":\n case \"partition\":\n case \"rst\": {\n const kind = cell.fault === \"rst\" ? \"rst\" : \"blackhole\";\n const cuts = place.cuts ?? (cell.fault === \"partition\" ? \"group\" : \"all\");\n const part = lab.partOf(place.role, leader);\n at = part;\n fault = await lab.fault(kind, part, cuts);\n undo.push(() => lab.lift(kind, part, cuts));\n if (cell.hold !== undefined) healing = lab.lift(kind, part, cuts, fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n break;\n }\n case \"freeze-process\": {\n const part = lab.partOf(place.role, leader);\n at = part;\n fault = await lab.signal(part, \"STOP\");\n undo.push(() => lab.signal(part, \"CONT\"));\n if (cell.hold !== undefined) healing = lab.signal(part, \"CONT\", fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n break;\n }\n case \"fin\": {\n const part = lab.partOf(place.role, leader);\n at = part;\n fault = await lab.signal(part, \"KILL\");\n undo.push(() => lab.restart(part));\n break;\n }\n case \"step-down\": {\n at = leader;\n wall = await lab.stepDown(leader, lab.partOf(\"replica\", leader));\n ({ stamp: fault, line: stampLine } = await stampOf(lab, client, logFrom, (line) => line.member === leader && GIVES_AWAY.test(line.msg), wall));\n break;\n }\n case \"drain\": {\n const part = lab.partOf(place.role, leader);\n at = part;\n wall = await lab.drain(part);\n undo.push(() => lab.revive(part));\n // a drain stops the member of the leader (rabbit_quorum_queue.erl:2787-2838): a follower sees its monitor go down\n ({ stamp: fault, line: stampLine } = await stampOf(lab, client, logFrom, (line) => line.member !== part && MONITOR_DOWN.test(line.msg), wall));\n break;\n }\n default:\n throw new Error(`a cluster cell has no fault ${cell.fault}`);\n }\n if (fault === null) throw new Error(\"the client wrote no clock line: the stamps of the command have no place on the monotonic clock\");\n // the injector holds the lift in the VM: its exec returns at the instant, and the stamps come with it\n const healed =\n healing === null\n ? Promise.resolve(null)\n : healing.then((stamp) => {\n heal = stamp;\n // the lift came: nothing is left to undo\n undo.length = 0;\n return stamp;\n });\n // a run that stops early lifts the fault itself, and the late lift then has nothing to remove\n healed.catch(() => undefined);\n const t1 = fault.t1;\n const sentAt = (n: number): number => client.events.find((event) => event.ev === \"sent\" && Number(event[\"n\"]) === n)?.t ?? -Infinity;\n const outcome = await waitFor(client, (event) => event.ev === \"ack\" && sentAt(Number(event[\"n\"])) > t1, deadlineOf(cell));\n if (outcome !== undefined) await sleep(TAIL_MS);\n // the whole hold: a prediction that reads the cluster in each moment of it\n if (healing !== null) {\n await healed.catch(() => undefined);\n await sleep(TAIL_MS);\n }\n } finally {\n // each fault that is still on goes, and a killed server starts again\n for (const step of undo.reverse()) await step().catch(() => undefined);\n await client.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge().catch(() => null);\n const holds = after === null ? null : await lab.holds(after);\n return {\n environment,\n index,\n events: [...client.events],\n fault: stampLine === null ? fault : (restamped(stampLine, client.events) ?? fault),\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[at ?? leader]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: {},\n primary: leader,\n at,\n timeline: nodesOnMonotonic(lab.log.slice(logFrom), clockOffsetOf(client.events)),\n after,\n holds,\n },\n };\n};\n","import type { StartedNetwork, StartedTestContainer } from \"testcontainers\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cell, GroupPlace, Kafka, KernelRecord, ProbeEvent, Run, RunPart } from \"./cell.ts\";\nimport type { GroupClient, GroupNetworkFault, GroupView, Stamp } from \"./group.ts\";\nimport { CONVERGE_MS, deadlineOf } from \"./group.ts\";\nimport { harnessImage, kafkaClientImage } from \"./image.ts\";\nimport type { Manifest } from \"./lab.ts\";\nimport { STOP, containers, lines, netnsOf, output, withPid } from \"./lab.ts\";\nimport { isFenceLine, namesGroup, pauseReady } from \"./pause.ts\";\nimport type { Cut } from \"./replset.ts\";\n\n/**\n * This module is the lab of a group of Kafka brokers in KRaft mode with one controller. It opens one\n * environment for a Kafka cell, for the runs of the cell. Each node is a container from the stock\n * image, in its own network namespace, and an injector sidecar shares its network and process\n * namespaces. The image starts by its own command, and each setting comes from the environment.\n *\n * Each run makes one new topic, thus each run starts with an empty log and its client counts from 1.\n * The client is the producer of kafka-clients. The commander holds the admin, on the network but\n * not in the namespace that the prober watches. The record of a run is the lines of the client and\n * the whole partition, read to its high watermark after the group converged.\n */\n\n/** This path is the class path of the Kafka image: the JVM expands the star itself. */\nconst CLASS_PATH = \"/opt/harness/kafka/classes:/opt/harness/kafka/lib/*\";\n\n/** This option is the heap of the client and of the admin. It has no source: the two hold a producer or a read of one partition. */\nconst CLIENT_HEAP = \"-Xmx256m\";\n\n/** This function gives the node id of a name. A broker has its place in the list from 1, and the controller has the id after them. */\nexport const nodeIdOf = (kafka: Kafka, name: string): number => {\n const at = kafka.brokers.indexOf(name);\n if (at !== -1) return at + 1;\n if (name === kafka.controller) return kafka.brokers.length + 1;\n throw new Error(`the Kafka group has no node ${name}`);\n};\n\n/**\n * This function gives the variable of a server property for the image. The wrapper of the image\n * reverses this map (KafkaDockerWrapper.scala:188-203). After the prefix `KAFKA_`, `___` is a\n * hyphen, `__` is an underscore and `_` is a dot.\n */\nexport const envOf = (property: string): string =>\n `KAFKA_${property.replace(/_/g, \"__\").replace(/-/g, \"___\").replace(/\\./g, \"_\").toUpperCase()}`;\n\n/** This function gives the variables of each node: the listener names, the voters, the log and the settings of the group. */\nconst commonEnv = (kafka: Kafka): Record<string, string> => ({\n CLUSTER_ID: kafka.clusterId,\n KAFKA_HEAP_OPTS: kafka.heap,\n KAFKA_CONTROLLER_QUORUM_VOTERS: `${nodeIdOf(kafka, kafka.controller)}@${kafka.controller}:${kafka.controllerPort}`,\n KAFKA_CONTROLLER_LISTENER_NAMES: \"CONTROLLER\",\n KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: \"CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT\",\n // the wrapper writes the server properties from these variables alone (KafkaDockerWrapper.scala:147)\n KAFKA_LOG_DIRS: \"/var/lib/kafka/data\",\n ...Object.fromEntries(Object.entries(kafka.settings).map(([property, value]) => [envOf(property), value])),\n});\n\n/** This function gives the environment of a broker. */\nexport const brokerEnv = (kafka: Kafka, name: string): Record<string, string> => ({\n ...commonEnv(kafka),\n KAFKA_PROCESS_ROLES: \"broker\",\n KAFKA_NODE_ID: String(nodeIdOf(kafka, name)),\n KAFKA_LISTENERS: `PLAINTEXT://0.0.0.0:${kafka.port}`,\n KAFKA_ADVERTISED_LISTENERS: `PLAINTEXT://${name}:${kafka.port}`,\n KAFKA_INTER_BROKER_LISTENER_NAME: \"PLAINTEXT\",\n});\n\n/** This function gives the environment of the controller. The start script of the image stops on an advertised listener here (configure:43-48). */\nexport const controllerEnv = (kafka: Kafka): Record<string, string> => ({\n ...commonEnv(kafka),\n KAFKA_PROCESS_ROLES: \"controller\",\n KAFKA_NODE_ID: String(nodeIdOf(kafka, kafka.controller)),\n KAFKA_LISTENERS: `CONTROLLER://0.0.0.0:${kafka.controllerPort}`,\n});\n\n/** A partition view is the output of the command `view` of the admin. Without a topic it has only the brokers. */\nexport interface PartitionView {\n readonly brokers: readonly number[];\n readonly leader?: number | null;\n readonly isr?: readonly number[];\n readonly replicas?: readonly number[];\n}\n\n/**\n * This function judges a view of a partition: its leader, and if the group is healthy. A healthy\n * group has each broker not fenced, one leader, and each broker in the in-sync replicas.\n */\nexport const kafkaViewOf = (kafka: Kafka, view: PartitionView): GroupView => {\n const primary = view.leader === undefined || view.leader === null ? null : (kafka.brokers[view.leader - 1] ?? null);\n const all = kafka.brokers.length;\n if (view.brokers.length !== all) return { primary, healthy: false, why: `${view.brokers.length} brokers are not fenced` };\n if (primary === null) return { primary, healthy: false, why: \"the partition has no leader\" };\n if (view.replicas?.length !== all) return { primary, healthy: false, why: `the partition has ${view.replicas?.length ?? 0} replicas` };\n if (view.isr?.length !== all) return { primary, healthy: false, why: `the partition has ${view.isr?.length ?? 0} in-sync replicas` };\n return { primary, healthy: true, why: \"healthy\" };\n};\n\n/**\n * This function gives the peers that a fault on a broker cuts it from. Only `group` has a law: the\n * other brokers and the controller, and the client keeps its route to the broker.\n */\nexport const kafkaCutOf = (\n kafka: Kafka,\n members: Readonly<Record<string, RunPart>>,\n controller: RunPart,\n part: string,\n cuts: NonNullable<GroupPlace[\"cuts\"]>,\n): Cut => {\n if (cuts !== \"group\") throw new Error(`a Kafka cell has no cut ${cuts}`);\n return { peers: [...kafka.brokers.filter((name) => name !== part).map((name) => members[name]!.ip), controller.ip] };\n};\n\n/** This function gives the addresses that the client and the admin bootstrap from. */\nexport const bootstrapOf = (kafka: Kafka): string => kafka.brokers.map((name) => `${name}:${kafka.port}`).join(\",\");\n\n/** This function gives the name of the topic of a run. A warm-up has the index -1. */\nexport const topicOf = (environment: number, index: number): string => `cells-e${environment}-r${index + 1}`;\n\n/** A Kafka member is one member of a consumer group. A signal goes from a sidecar in its process namespace. */\nexport interface KafkaMember extends GroupClient {\n /** This method sends a signal to the process of the member, at once or at an instant of the VM. The injector stamps it. */\n signal(signal: \"STOP\" | \"CONT\", at?: number): Promise<Stamp>;\n}\n\n/** A Kafka lab is one environment of a Kafka cell. */\nexport interface KafkaLab {\n readonly kafka: Kafka;\n readonly clientIp: string;\n readonly members: Readonly<Record<string, RunPart>>;\n readonly controller: RunPart;\n readonly netns: { readonly client: number };\n /** These are all the records that the prober wrote, in sequence. */\n readonly kernel: readonly KernelRecord[];\n /** These are the last raw lines of the console of each node, for the diagnosis of a lab: at most RAW_TAIL of each. */\n readonly raw: Readonly<Record<string, readonly string[]>>;\n /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */\n sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;\n /** This method waits until each broker is not fenced. */\n brokersUp(within?: number): Promise<void>;\n /** These are the log lines of the brokers that tell that a member left a group (`isFenceLine`), in sequence. */\n readonly fences: readonly string[];\n /** This method makes the topic of a run, with one partition or more. */\n create(topic: string, partitions?: number): Promise<void>;\n /** This method writes `count` records in each partition of a topic, each acknowledged by each in-sync replica. */\n fill(topic: string, partitions: number, count: number): Promise<void>;\n /** This method starts one member of a consumer group, with the arguments of `ConsumerKafka` after the bootstrap. */\n consumer(args: readonly string[]): Promise<KafkaMember>;\n /** This method waits until the partition is whole and calm, and gives the name of the broker of its leader. */\n converge(topic: string, within?: number): Promise<string>;\n /** This method gives the sequence numbers that the partition holds, one entry for each copy. */\n holds(topic: string): Promise<number[]>;\n /** This method starts the client of a run, with the arguments of `ClientKafka`. */\n client(args: readonly string[]): Promise<GroupClient>;\n /** This method applies a network fault between a broker and some of its peers, at once or at an instant of the VM. */\n fault(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes a network fault, at once or at an instant of the VM. */\n lift(kind: GroupNetworkFault, part: string, cuts: NonNullable<GroupPlace[\"cuts\"]>, at?: number): Promise<Stamp>;\n /** This method removes the TCP metrics of the client namespace: each run starts from a kernel that keeps nothing. */\n forget(): Promise<void>;\n /** This method waits for the next clock line of the prober, which gives the count of lost records. */\n settle(): Promise<number | null>;\n manifest(sysctls: Readonly<Record<string, string>>): Promise<Manifest>;\n close(): Promise<void>;\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** This count is the number of raw lines of the console of each node that a lab keeps. */\nexport const RAW_TAIL = 400;\n\n/**\n * This function opens one environment of a Kafka cell:\n * - one new network, with each node, the client and the commander on it.\n * - the controller first, then each broker: the stock image with its own command. The brokers\n * register with the controller, thus they need it first.\n * - an injector sidecar for each node, in its network and process namespaces.\n * - a client that holds its own network namespace, with a privileged sidecar for its sysctls.\n * - the prober, which watches the namespace of the client.\n */\nexport const openKafkaLab = async (kafka: Kafka): Promise<KafkaLab> => {\n const image = await harnessImage();\n const clientImage = await kafkaClientImage();\n const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();\n const runtime = await getContainerRuntimeClient();\n const opened: StartedTestContainer[] = [];\n let network: StartedNetwork | undefined;\n const close = async () => {\n for (const container of opened.reverse()) await container.stop(STOP).catch(() => undefined);\n await network?.stop().catch(() => undefined);\n };\n const ipOf = async (container: StartedTestContainer): Promise<string> => {\n const info = await runtime.container.inspect(runtime.container.getById(container.getId()));\n const ip = info.NetworkSettings.Networks[network!.getName()]?.IPAddress;\n if (ip === undefined || ip === \"\") throw new Error(`${container.getName()} has no address on ${network!.getName()}`);\n return ip;\n };\n try {\n network = await new Network().start();\n const started = network;\n const boxes = new Map<string, StartedTestContainer>();\n const injectors = new Map<string, StartedTestContainer>();\n const parts: Record<string, RunPart> = {};\n const raw: Record<string, string[]> = {};\n const fences: string[] = [];\n const openNode = async (name: string, environment: Record<string, string>): Promise<void> => {\n let partial = \"\";\n const box = await new GenericContainer(kafka.image)\n .withNetwork(started)\n .withNetworkAliases(name)\n .withHostname(name)\n .withEnvironment(environment)\n .withWaitStrategy(Wait.forLogMessage(kafka.ready))\n .withStartupTimeout(180_000)\n .withLogConsumer((stream) =>\n stream.on(\"data\", (chunk: Buffer | string) => {\n partial += chunk.toString();\n const split = partial.split(\"\\n\");\n partial = split.pop() ?? \"\";\n for (const text of split) {\n const tail = (raw[name] ??= []);\n tail.push(text);\n if (tail.length > RAW_TAIL) tail.shift();\n if (isFenceLine(text)) fences.push(text);\n }\n }),\n )\n .start();\n opened.push(box);\n boxes.set(name, box);\n const injector = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${box.getId()}`,\n ).start();\n opened.push(injector);\n injectors.set(name, injector);\n parts[name] = { ip: await ipOf(box), netns: await netnsOf(injector) };\n };\n await openNode(kafka.controller, controllerEnv(kafka));\n for (const name of kafka.brokers) await openNode(name, brokerEnv(kafka, name));\n const members: Record<string, RunPart> = Object.fromEntries(kafka.brokers.map((name) => [name, parts[name]!]));\n const controller = parts[kafka.controller]!;\n\n const holder = await new GenericContainer(image).withNetwork(network).start();\n opened.push(holder);\n const admin = await new GenericContainer(image).withNetworkMode(`container:${holder.getId()}`).withPrivilegedMode().start();\n opened.push(admin);\n const clientIp = await ipOf(holder);\n const commander = await new GenericContainer(clientImage)\n .withNetwork(network)\n .withCommand([\"sh\", \"-c\", \"while :; do sleep 3600; done\"])\n .start();\n opened.push(commander);\n\n const clientNetns = await netnsOf(admin);\n const records = lines<KernelRecord>();\n const prober = await new GenericContainer(image)\n .withPrivilegedMode()\n .withNetworkMode(\"none\")\n .withCommand([\"/opt/harness/prober\", String(clientNetns)])\n .withLogConsumer(records.consume)\n .start();\n opened.push(prober);\n const begun = await records.until([\"begin\", \"fail\"], 30_000, \"prober\");\n if (begun.ev === \"fail\") throw new Error(`the prober failed: ${String(begun[\"why\"])}`);\n\n const box = (name: string): StartedTestContainer => {\n const found = boxes.get(name);\n if (found === undefined) throw new Error(`the group has no node ${name}`);\n return found;\n };\n const injectorOf = (name: string): StartedTestContainer => {\n const found = injectors.get(name);\n if (found === undefined) throw new Error(`the group has no node ${name}`);\n return found;\n };\n const lastLine = (text: string): string => text.split(\"\\n\").filter((line) => line.trim() !== \"\").at(-1) ?? \"\";\n const stamped = async (where: StartedTestContainer, argv: string[]): Promise<Stamp> => {\n const stamp = JSON.parse(lastLine(await output(where, argv))) as Stamp;\n return { t0: stamp.t0, t1: stamp.t1 };\n };\n const after = (at: number | undefined): string[] => (at === undefined ? [] : [\"--at\", String(Math.round(at))]);\n const bootstrap = bootstrapOf(kafka);\n const tool = async (...argv: string[]): Promise<string> =>\n lastLine(await output(commander, [\"java\", CLIENT_HEAP, \"-cp\", CLASS_PATH, \"AdminKafka\", bootstrap, ...argv]));\n const view = async (topic?: string): Promise<PartitionView> =>\n JSON.parse(await tool(\"view\", ...(topic === undefined ? [] : [topic]))) as PartitionView;\n\n return {\n kafka,\n clientIp,\n members,\n controller,\n netns: { client: clientNetns },\n kernel: records.seen,\n raw,\n fences,\n async sysctl(values) {\n const settings = Object.entries(values).map(([key, value]) => `${key}=${value}`);\n if (settings.length > 0) await output(admin, [\"sysctl\", \"-q\", \"-w\", ...settings]);\n const read: Record<string, string> = {};\n for (const key of Object.keys(values)) read[key] = await output(admin, [\"sysctl\", \"-n\", key]);\n return read;\n },\n async brokersUp(within = CONVERGE_MS) {\n const begin = Date.now();\n let last = \"no view yet\";\n while (Date.now() - begin < within) {\n const read = await view().catch((error: unknown) => (error as Error).message.slice(0, 200));\n if (typeof read !== \"string\" && read.brokers.length === kafka.brokers.length) return;\n last = typeof read === \"string\" ? read : `${read.brokers.length} brokers are not fenced`;\n await sleep(1_000);\n }\n throw new Error(`the brokers did not come up in ${within} ms: ${last}`);\n },\n async create(topic, partitions = 1) {\n const ids = kafka.brokers.map((name) => nodeIdOf(kafka, name)).join(\",\");\n const reply = await tool(\"create\", topic, String(kafka.minInsync), ids, String(partitions));\n if (!reply.includes('\"ok\":true')) throw new Error(`the create of the topic failed: ${reply}`);\n },\n async fill(topic, partitions, count) {\n const reply = await tool(\"fill\", topic, String(partitions), String(count));\n if (!reply.includes('\"ok\":true')) throw new Error(`the fill of the topic failed: ${reply}`);\n },\n async consumer(args) {\n const events = lines<ProbeEvent>();\n // sh stays as process 1, because a signal from inside a process namespace to its process 1 has no effect\n const container = await new GenericContainer(clientImage)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"sh\", \"-c\", 'java \"$@\"; :', \"consumer\", CLIENT_HEAP, \"-cp\", CLASS_PATH, \"ConsumerKafka\", bootstrap, ...args])\n .withLogConsumer(events.consume)\n .start();\n const signaller = await withPid(\n new GenericContainer(image).withNetworkMode(`container:${holder.getId()}`).withAddedCapabilities(\"NET_ADMIN\", \"NET_RAW\"),\n `container:${container.getId()}`,\n ).start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n signal: (signal, at) => stamped(signaller, [\"/opt/harness/inject\", \"signal\", \"java\", signal, ...after(at)]),\n // process 1 is sh and it ignores a TERM, thus this stop ends with a KILL, and it writes no done line\n stop: async () => {\n await container.stop({ timeout: 2 }).catch(() => undefined);\n await signaller.stop(STOP).catch(() => undefined);\n },\n };\n },\n async converge(topic, within = CONVERGE_MS) {\n const begin = Date.now();\n let calm = 0;\n let last: GroupView = { primary: null, healthy: false, why: \"no view yet\" };\n while (Date.now() - begin < within) {\n last = await view(topic).then(\n (read) => kafkaViewOf(kafka, read),\n (error: unknown) => ({ primary: null, healthy: false, why: (error as Error).message.slice(0, 200) }),\n );\n // two healthy views in a row: one view can come in the middle of a change, and the\n // high watermark moves with the fetch after the one that put a broker back in sync\n calm = last.healthy ? calm + 1 : 0;\n if (calm >= 2 && last.primary !== null) return last.primary;\n await sleep(1_000);\n }\n throw new Error(`the partition did not converge in ${within} ms: ${last.why}`);\n },\n async holds(topic) {\n const reply = await tool(\"holds\", topic);\n const { held } = JSON.parse(reply) as { held?: unknown[] };\n if (held === undefined) throw new Error(`the read of the partition failed: ${reply}`);\n return held.map(Number).filter((n) => Number.isInteger(n) && n > 0);\n },\n async client(args) {\n const events = lines<ProbeEvent>();\n const container = await new GenericContainer(clientImage)\n .withNetworkMode(`container:${holder.getId()}`)\n .withCommand([\"java\", CLIENT_HEAP, \"-cp\", CLASS_PATH, \"ClientKafka\", bootstrap, ...args])\n .withLogConsumer(events.consume)\n .start();\n return {\n events: events.seen,\n until: (kinds, within) => events.until(kinds, within, \"client\"),\n // a TERM first: the client writes its done line, then stops\n stop: () =>\n container\n .stop({ timeout: 2 })\n .then(() => undefined)\n .catch(() => undefined),\n };\n },\n fault(kind, part, cuts, at) {\n const cut = kafkaCutOf(kafka, members, controller, part, cuts);\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind, cut.peers.join(\",\"), ...after(at)]);\n },\n lift(kind, part, cuts, at) {\n const cut = kafkaCutOf(kafka, members, controller, part, cuts);\n return stamped(injectorOf(part), [\"/opt/harness/inject\", kind === \"rst\" ? \"clear-rst\" : \"clear\", cut.peers.join(\",\"), ...after(at)]);\n },\n async forget() {\n await output(admin, [\"ip\", \"tcp_metrics\", \"flush\", \"all\"]);\n },\n async settle() {\n const from = records.seen.length;\n const clock = await new Promise<KernelRecord | null>((resolve) => {\n const begin = Date.now();\n const look = () => {\n const line = records.seen.slice(from).find((record) => record.ev === \"clock\");\n if (line !== undefined) resolve(line);\n else if (Date.now() - begin > 5_000) resolve(null);\n else setTimeout(look, 50);\n };\n look();\n });\n return clock === null ? null : Number(clock[\"lost\"] ?? 0);\n },\n async manifest(sysctls) {\n const config = await output(admin, [\"zcat\", \"/proc/config.gz\"]).catch(() => \"\");\n const inspect = async (container: StartedTestContainer) => runtime.container.inspect(runtime.container.getById(container.getId()));\n const settings = {\n settings: Object.entries(kafka.settings)\n .map(([property, value]) => `${property}=${value}`)\n .join(\"; \"),\n heap: kafka.heap,\n \"min.insync.replicas\": String(kafka.minInsync),\n };\n const list = async (names: readonly string[]) => {\n const out = [];\n for (const name of names) {\n const version = lastLine(await output(box(name), [\"/opt/kafka/bin/kafka-topics.sh\", \"--version\"]).catch(() => \"\"));\n out.push({ name, ip: parts[name]!.ip, id: (await inspect(box(name))).Image, settings: { version, ...settings } });\n }\n return out;\n };\n const brokers = await list(kafka.brokers);\n return {\n kernel: await output(holder, [\"uname\", \"-r\"]),\n architecture: await output(holder, [\"uname\", \"-m\"]),\n hz: /^CONFIG_HZ=(\\d+)$/m.exec(config)?.[1] ?? null,\n boot_id: await output(holder, [\"cat\", \"/proc/sys/kernel/random/boot_id\"]),\n docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,\n target: { image: kafka.image, id: brokers[0]!.id, settings: brokers[0]!.settings, sysctls: {} },\n harness: {\n image,\n id: (await inspect(holder)).Image,\n packages: (await output(holder, [\"apk\", \"info\", \"-v\"])).split(\"\\n\").sort(),\n },\n client: { kind: \"image\", image: clientImage },\n netns: { client: clientNetns, target: members[kafka.brokers[0]!]!.netns },\n sysctls,\n group: { members: brokers, sentinels: await list([kafka.controller]), observer: { image: clientImage } },\n };\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n};\n\n// ---------------------------------------------------------------------------------------------\n// the runs of a Kafka cell\n// ---------------------------------------------------------------------------------------------\n\n/** This count is the number of acknowledged writes that a run waits for before its fault: the stream is steady then. */\nconst STEADY = 20;\n\n/**\n * This time is how long a run continues after its lift. The record then shows the step-down of the\n * leader and the writes after it. It has no source. It is above the largest step-down of the\n * law, which is approximately 2 s after the lift.\n */\nexport const KAFKA_TAIL_MS = 10_000;\n\n/** This function gives the arguments of the client of a Kafka cell: the topic, the writers, the stream of writes and the settings. */\nexport const kafkaArgs = (cell: Cell, topic: string): string[] => [\n \"--topic\",\n topic,\n \"--writers\",\n String(cell.kafka!.writers),\n \"--interval-ms\",\n String(cell.probe.interval === undefined ? 50 : valueIn(cell.probe.interval, \"ms\")),\n \"--max-s\",\n String(Math.ceil(deadlineOf(cell) / 1_000 + (cell.hold === undefined ? 0 : valueIn(cell.hold, \"s\")) + 120)),\n ...Object.entries(cell.driverOptions ?? {}).flatMap(([name, value]) => [\"--set\", `${name}=${String(value)}`]),\n];\n\n/** This function waits until a condition on the lines of the client holds, or for `within` ms. It gives the first line that matches. */\nconst waitFor = (client: GroupClient, match: (event: ProbeEvent) => boolean, within: number): Promise<ProbeEvent | undefined> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const found = client.events.find(match);\n if (found !== undefined || Date.now() - started > within) resolve(found);\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This function gives the count of lost records in the latest clock line of the prober. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1) if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/**\n * This function does one run of a Kafka cell:\n * - Each broker is up, the topic of the run exists, and its partition is whole. The client starts,\n * and its stream of writes gets steady.\n * - The fault cuts the leader from the other brokers and the controller, and it lifts at its instant\n * in the VM. The client keeps its route to the leader, thus only the group knows of the cut.\n * - The run waits for the lift and for the tail after it.\n * - Each fault goes, the client stops, and the partition converges again. The admin then reads\n * the whole partition, thus the record tells which writes the group kept.\n */\nexport const kafkaOnce = async (lab: KafkaLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n if (cell.fault !== \"partition\") throw new Error(`a Kafka cell has no fault ${cell.fault}`);\n if (cell.hold === undefined) throw new Error(\"a Kafka cell needs a hold: its law reads it\");\n const place = (cell.faultAt ?? { role: \"primary\" }) as GroupPlace;\n if (place.role !== \"primary\") throw new Error(`a Kafka cell has no fault on the ${place.role}`);\n const cuts = place.cuts ?? \"group\";\n const topic = topicOf(environment, index);\n await lab.brokersUp();\n await lab.create(topic);\n const leader = await lab.converge(topic);\n await lab.forget();\n const from = lab.kernel.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const client = await lab.client(kafkaArgs(cell, topic));\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n const undo: Array<() => Promise<unknown>> = [];\n try {\n await client.until([\"ready\"], 60_000);\n const steady = await waitFor(client, (event) => event.ev === \"ack\" && Number(event[\"n\"]) >= STEADY, 30_000);\n if (steady === undefined) throw new Error(`the client did not write ${STEADY} times in 30 s`);\n fault = await lab.fault(\"blackhole\", leader, cuts);\n undo.push(() => lab.lift(\"blackhole\", leader, cuts));\n // the injector holds the lift in the VM: its exec returns at the instant, and the stamps come with it\n heal = await lab.lift(\"blackhole\", leader, cuts, fault.t0 + valueIn(cell.hold, \"s\") * 1e9);\n // the lift came: nothing is left to undo\n undo.length = 0;\n await sleep(KAFKA_TAIL_MS);\n } finally {\n // a fault that is still on goes\n for (const step of undo.reverse()) await step().catch(() => undefined);\n await client.stop();\n }\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n const after = await lab.converge(topic).catch(() => null);\n const holds = after === null ? null : await lab.holds(topic);\n return {\n environment,\n index,\n events: [...client.events],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[leader]!.netns,\n lost,\n group: {\n members: lab.members,\n sentinels: { [lab.kafka.controller]: lab.controller },\n primary: leader,\n at: leader,\n timeline: [],\n after,\n holds,\n },\n };\n};\n\n/** This count is the partitions of the topic of a run of a paused consumer: one for each member. */\nconst PAUSE_PARTITIONS = 2;\n\n/** This time bounds the wait for one partition for each member and for two commits, in ms. It has no source: it is far above two batches and one rebalance. */\nconst PAUSE_READY_MS = 90_000;\n\n/** This time bounds the wait for the next batch of the first member, in ms. It has no source: it is far above one batch. */\nconst PAUSE_BATCH_MS = 30_000;\n\n/**\n * This function does one run of a paused consumer:\n * - The topic of the run has two partitions, each with records that a run does not finish.\n * - Two members join one group, and the run waits until each member holds one partition and the\n * first member has two commits on its partition.\n * - A SIGSTOP stops the first member while it holds its next batch, and a SIGCONT ends the stop\n * after the hold of the cell. The run then waits for the tail.\n *\n * The fault is null when the members did not get one partition each. The measure then voids the run.\n * The law reads no kernel record, thus a lost record does not void this run.\n */\nexport const kafkaPauseOnce = async (lab: KafkaLab, cell: Cell, environment: number, index: number): Promise<Run> => {\n const pause = cell.kafka?.pause;\n if (pause === undefined) throw new Error(\"a run of a paused consumer needs `Kafka.pause`\");\n if (cell.fault !== \"freeze-process\") throw new Error(`a paused consumer has no fault ${cell.fault}`);\n if (cell.hold === undefined) throw new Error(\"a paused consumer needs a hold: its law reads it\");\n const hold = valueIn(cell.hold, \"s\");\n const topic = topicOf(environment, index);\n const group = `pause-e${environment}-r${index + 1}`;\n await lab.brokersUp();\n await lab.create(topic, PAUSE_PARTITIONS);\n const leader = await lab.converge(topic);\n await lab.fill(topic, PAUSE_PARTITIONS, pause.fill);\n await lab.forget();\n const from = lab.kernel.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const common = [\n \"--topic\",\n topic,\n \"--group\",\n group,\n \"--protocol\",\n pause.protocol,\n \"--max-s\",\n String(Math.ceil(hold + 180)),\n ...Object.entries(cell.driverOptions ?? {}).flatMap(([name, value]) => [\"--set\", `${name}=${String(value)}`]),\n ];\n const members: KafkaMember[] = [];\n let fault: Run[\"fault\"] = null;\n let heal: Run[\"heal\"] = null;\n let otherEvents: readonly ProbeEvent[] = [];\n let firstEvents: readonly ProbeEvent[] = [];\n try {\n const first = await lab.consumer([...common, \"--process-ms\", String(valueIn(pause.process, \"ms\")), \"--after-pause\", pause.afterPause]);\n members.push(first);\n const other = await lab.consumer([...common, \"--process-ms\", \"0\", \"--after-pause\", \"commit\"]);\n members.push(other);\n firstEvents = first.events;\n otherEvents = other.events;\n const begun = Date.now();\n while (Date.now() - begun < PAUSE_READY_MS && !pauseReady(first.events, other.events)) await sleep(100);\n if (pauseReady(first.events, other.events)) {\n const seen = first.events.at(-1)?.t ?? 0;\n const batch = await waitFor(first, (event) => event.ev === \"processing\" && event.t > seen, PAUSE_BATCH_MS);\n if (batch !== undefined) {\n fault = await first.signal(\"STOP\", batch.t + valueIn(pause.stopAfter, \"s\") * 1e9);\n // the injector holds the signal in the VM: its exec returns at the instant, and the stamps come with it\n heal = await first.signal(\"CONT\", fault.t0 + hold * 1e9);\n await sleep(KAFKA_TAIL_MS);\n }\n }\n } finally {\n for (const member of members) await member.stop();\n }\n const settled = await lab.settle();\n return {\n environment,\n index,\n events: [...firstEvents],\n fault,\n ...(heal === null ? {} : { heal }),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.members[leader]!.netns,\n lost: settled === null ? null : settled - lostBefore,\n pause: { other: [...otherEvents], fences: lab.fences.filter((line) => namesGroup(line, group)), group },\n };\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport { schedule } from \"@mark1russell7/rigor-chaos\";\nimport type { Cell, FaultPlace, KernelRecord, LineCount, ProbeEvent, Run } from \"./cell.ts\";\nimport { isHopPlace, latestEndOf, requestFirst } from \"./cell.ts\";\nimport { drillOnce } from \"./drill.ts\";\nimport { countOf, longestOf, settled as driverSettled } from \"./driver.ts\";\nimport { laterMove } from \"./fabric.ts\";\nimport { groupOnce, openGroupLab } from \"./group.ts\";\nimport type { FaultOptions, Lab, Manifest, Probe } from \"./lab.ts\";\nimport { openLab } from \"./lab.ts\";\nimport { LOAD_PATH, SCHEDULE_PATH, loadPlanOf } from \"./load.ts\";\nimport type { Measured } from \"./observe.ts\";\nimport { jitterOf, measure, socketOf } from \"./observe.ts\";\nimport { openReplicaSetLab, replicaSetOnce } from \"./replset.ts\";\nimport { clusterOnce, openClusterLab } from \"./cluster.ts\";\nimport { kafkaOnce, kafkaPauseOnce, openKafkaLab } from \"./kafka.ts\";\nimport { openStandby, pairOnce } from \"./standby.ts\";\nimport { readCpu, stealShare } from \"./substrate.ts\";\nimport type { Verdict } from \"./verdict.ts\";\nimport { STEPS, noiseOf, verdictOf } from \"./verdict.ts\";\n\n/** A cell result is a cell with its manifests, its runs, their measurements and its verdict. */\nexport interface CellResult {\n readonly cell: Cell;\n readonly manifests: readonly Manifest[];\n readonly runs: readonly Run[];\n /** These are the warm-up runs, one for each environment before its counted runs. The verdict does not count them. */\n readonly warmups: readonly Run[];\n readonly measured: readonly Measured[];\n readonly verdict: Verdict;\n /** These times are when its first environment opened and its last environment closed, on the wall clock. */\n readonly at: { readonly started: string; readonly ended: string };\n}\n\n/**\n * This function measures and judges the raw records of a cell, with the code of the harness at\n * this time. `runCell` uses it during a cell. A holder of the raw records of a cell can use it\n * again later. Thus the records get a new analysis after a change to observe.ts or to the verdict.\n */\nexport const judge = (\n cell: Cell,\n runs: readonly Run[],\n): { measured: Measured[]; verdict: Verdict } => {\n // a warm-up run is a record, not a sample: the verdict never counts it\n const measured = runs.filter((run) => run.warmup !== true).map((run) => measure(cell, run));\n return { measured, verdict: verdictOf(cell.prediction, measured, noiseOf(cell)) };\n};\n\n/** This function gives the count of lost records in the latest clock line of the prober, since it began. */\nconst droppedSoFar = (records: readonly KernelRecord[]): number => {\n for (let at = records.length - 1; at >= 0; at -= 1)\n if (records[at]!.ev === \"clock\") return Number(records[at]![\"lost\"] ?? 0);\n return 0;\n};\n\n/** This function gives the argv of the client for a cell, with a deadline far after all that it waits for. */\nconst probeArgs = (cell: Cell, lab: Lab): string[] => {\n const { prediction, probe } = cell;\n const longest =\n (prediction.detects === true && prediction.driver !== undefined\n ? longestOf(cell)\n : prediction.detects\n ? latestEndOf(prediction)\n : valueIn(prediction.window, \"s\")) + (cell.idleBefore === undefined ? 0 : valueIn(cell.idleBefore, \"s\"));\n const args = [lab.targetIp, String(lab.targetPort), \"--mode\", probe.mode];\n if (probe.ws !== undefined) {\n // a WebSocket client gets each of its settings as a flag, and it has no default\n const { ws } = probe;\n const reconnects = prediction.detects !== false ? (prediction.reconnects?.waits ?? []) : [];\n const waits = reconnects.reduce((sum, wait) => sum + valueIn(wait.high, \"s\"), 0);\n args.push(\"--websocket\", ws.socket);\n args.push(\"--heartbeat\", ws.heartbeat === null ? \"off\" : \"on\");\n if (ws.heartbeat !== null)\n args.push(\n \"--heartbeat-interval-ms\",\n String(valueIn(ws.heartbeat.interval, \"ms\")),\n \"--heartbeat-timeout-ms\",\n String(valueIn(ws.heartbeat.timeout, \"ms\")),\n \"--heartbeat-misses\",\n String(ws.heartbeat.misses),\n );\n args.push(\"--reconnect\", ws.reconnect === null ? \"off\" : \"on\");\n if (ws.reconnect !== null)\n args.push(\n \"--reconnect-initial-ms\",\n String(valueIn(ws.reconnect.initialDelay, \"ms\")),\n \"--reconnect-multiplier\",\n String(ws.reconnect.multiplier),\n \"--reconnect-max-ms\",\n String(valueIn(ws.reconnect.maxDelay, \"ms\")),\n \"--reconnect-attempts\",\n String(ws.reconnect.attempts),\n \"--reconnect-jitter\",\n String(ws.reconnect.jitter),\n );\n args.push(\"--request-timeout-ms\", String(valueIn(ws.requestTimeout, \"ms\")));\n args.push(\"--connection-timeout-ms\", String(valueIn(ws.connectionTimeout, \"ms\")));\n if (ws.hold !== undefined) args.push(\"--hold-ms\", String(valueIn(ws.hold, \"ms\")));\n args.push(\"--max-s\", String(Math.ceil((longest + waits) * 2 + 10)));\n return args;\n }\n if (probe.http !== undefined) {\n // an HTTP client sets its socket options from its own settings, and sends its own requests\n const { http } = probe;\n const gap = http.gap === undefined ? 0 : valueIn(http.gap, \"s\");\n args.push(\"--method\", http.method);\n if (http.gap !== undefined) args.push(\"--gap-ms\", String(valueIn(http.gap, \"ms\")));\n if (http.hold !== undefined) args.push(\"--hold-ms\", String(valueIn(http.hold, \"ms\")));\n if (http.bytes !== undefined) args.push(\"--bytes\", String(http.bytes));\n for (const [name, value] of Object.entries(http.options ?? {})) args.push(`--${name}`, String(value));\n // the client waits after its second request, thus its own close comes after the window\n args.push(\"--linger-ms\", String(LINGER_MS));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + gap + 10)));\n return args;\n }\n if (probe.request !== undefined) args.push(\"--request\", probe.request);\n if (probe.count !== undefined) args.push(\"--count\", String(probe.count));\n if (probe.interval !== undefined) args.push(\"--interval-ms\", String(valueIn(probe.interval, \"ms\")));\n if (probe.driver?.name === \"mongodb\") {\n // the MongoDB driver: its replica set, its operation, its write concern and its own options\n args.push(\"--set\", probe.driver.set);\n if (probe.driver.op !== undefined) args.push(\"--op\", probe.driver.op);\n if (cell.writeConcern !== undefined) args.push(\"--w\", String(cell.writeConcern));\n if (cell.before === true) args.push(\"--before\");\n if (cell.driverOptions !== undefined) args.push(\"--options\", JSON.stringify(cell.driverOptions));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n }\n if (probe.driver?.name === \"pg\" || probe.driver?.name === \"hikari\" || probe.driver?.name === \"amqp\") {\n // node-postgres or HikariCP: its query, and the options of its pool. amqplib: the options of its connection\n if (probe.driver.name !== \"amqp\" && probe.driver.query !== undefined) args.push(\"--query\", probe.driver.query);\n if (probe.driver.name !== \"amqp\" && probe.driver.inflight !== undefined) args.push(\"--inflight-query\", probe.driver.inflight);\n if (probe.driver.name === \"hikari\" && probe.driver.burst !== undefined)\n args.push(\"--burst\", String(probe.driver.burst.count), \"--burst-gap-ms\", String(Math.round(valueIn(probe.driver.burst.gap, \"ms\"))));\n if (cell.before === true) args.push(\"--before\");\n if (cell.driverOptions !== undefined) args.push(\"--options\", JSON.stringify(cell.driverOptions));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n }\n if (probe.driver?.name === \"grpc\") {\n // grpc-js: its channel options and the deadline of a call, and the hold of the reply in flight\n if (probe.driver.hold !== undefined) args.push(\"--hold-ms\", String(valueIn(probe.driver.hold, \"ms\")));\n if (probe.driver.op !== undefined) args.push(\"--op\", probe.driver.op);\n if (cell.before === true) args.push(\"--before\");\n if (cell.driverOptions !== undefined) args.push(\"--options\", JSON.stringify(cell.driverOptions));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n }\n if (probe.driver !== undefined) {\n // a driver sets its socket options from its own options: the keepAlive of ioredis\n args.push(\"--keepalive-ms\", String(valueIn(probe.driver.keepAlive, \"ms\")));\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n }\n if (probe.keepalive) args.push(\"--keepalive\");\n if (probe.userTimeout !== undefined)\n args.push(\"--user-timeout-ms\", String(valueIn(probe.userTimeout, \"ms\")));\n if (probe.plan !== undefined) args.push(\"--schedule\", SCHEDULE_PATH);\n if (probe.streams !== undefined) args.push(\"--plan\", LOAD_PATH);\n args.push(\"--max-s\", String(Math.ceil(longest * 2 + 10)));\n return args;\n};\n\n/**\n * This function waits for an error on the socket of the observer, or for its end of file\n * (CLOSE_WAIT, state 8). The prober records both. A cell whose observer is the server, or a proxy\n * of a topology, waits for that. A target with its own detector can also drop the connection\n * itself (`dropped`). The promise resolves after `within` ms at the latest.\n */\nconst observerError = (\n cell: Cell,\n partial: () => Run,\n within: number,\n dropped: () => boolean = () => false,\n): Promise<void> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const run = partial();\n const at = socketOf(cell, run);\n const seen =\n at !== undefined &&\n run.kernel.some(\n (record) =>\n record.netns === at.netns &&\n record.cookie === at.cookie &&\n ((record.ev === \"error\" && (record.err ?? 0) !== 0) ||\n (record.ev === \"state\" && (record as { readonly new?: number }).new === 8)),\n );\n if (seen || dropped() || Date.now() - started > within) resolve();\n else setTimeout(look, 50);\n };\n look();\n });\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * This time is the pause between the client's first reply and the fault. It is more than Linux's\n * TCP_DELACK_MAX of 200 ms. Thus the delayed ACK of the reply is out before the fault.\n */\nexport const QUIET_MS = 250;\n\n/**\n * This time is how long an HTTP client waits after its second request, before it exits. The exit\n * closes its sockets, thus that close comes after the window of the cell.\n */\nexport const LINGER_MS = 1000;\n\n/** These are the lines that end the workload of an HTTP client: the end of its second request, its deadline, or its failure. */\nconst HTTP_DONE = [\"done\", \"deadline\", \"fail\"];\n\n/**\n * This function waits for the request that an in-flight client sends on the signal: its second\n * send, after the PING that made it ready. Its stamp is when the request first met the fault.\n */\nconst requestSent = (probe: Probe, within: number): Promise<ProbeEvent> =>\n new Promise((resolve, reject) => {\n const started = Date.now();\n const look = () => {\n const sent = probe.events.filter((event) => event.ev === \"sent\")[1];\n if (sent !== undefined) resolve(sent);\n else if (Date.now() - started > within)\n reject(new Error(`the client sent no request within ${within} ms of being told to`));\n else setTimeout(look, 1);\n };\n look();\n });\n\n/** This time is how long a run of a driver cell continues after its outcome, so that the record shows what came next. */\nconst TAIL_MS = 1_000;\n/** This time lets the last lines of a route monitor reach the harness after a stall ends. */\nconst MONITOR_MS = 200;\n\n/** This function waits for the outcome of a run of a driver cell, or for `within` ms. The outcome is the end of its band and of each later band. */\nconst driverOutcome = async (cell: Cell, current: () => Run, within: number): Promise<void> => {\n const started = Date.now();\n while (Date.now() - started < within) {\n if (driverSettled(cell, current())) return;\n await sleep(250);\n }\n};\n\n/** This function gives the longest wait of a run of a driver cell for its outcome, in ms. */\nconst driverWithin = (cell: Cell): number => (longestOf(cell) * 1.2 + 10) * 1_000;\n\n/**\n * This function does one run of a cell whose fault holds before the client starts (`Cell.before`).\n * The fault is a network fault at its place. The client then starts into it, and the run waits for\n * each band of the driver. Then the fault lifts.\n */\nconst beforeOnce = async (lab: Lab, cell: Cell, environment: number, index: number): Promise<Run> => {\n if (cell.fault !== \"rst\" && cell.fault !== \"blackhole\" && cell.fault !== \"unreachable\")\n throw new Error(`${cell.name}: a fault before the client starts is a network fault, not ${cell.fault}`);\n await lab.forget();\n const from = lab.kernel.length;\n const middleboxFrom = lab.middlebox.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const faultAt: FaultPlace = cell.faultAt ?? \"target\";\n const kind = cell.fault === \"unreachable\" ? \"reject\" : cell.fault;\n const options: FaultOptions = cell.fault === \"unreachable\" ? { code: cell.icmp ?? \"host\" } : {};\n const fault = await lab.fault(kind, faultAt, options);\n let probe: Probe | undefined;\n try {\n probe = await lab.probe(probeArgs(cell, lab));\n const started = probe;\n // the topology too: a band can be on the socket that a hop opens toward the target\n const current = (): Run => ({\n environment,\n index,\n events: started.events,\n fault,\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost: 0,\n ...(lab.topology === null ? {} : { topology: lab.topology }),\n });\n await driverOutcome(cell, current, driverWithin(cell));\n await sleep(TAIL_MS);\n } finally {\n await lab.lift(kind, faultAt, options);\n await probe?.stop();\n }\n const settled = await lab.settle();\n return {\n environment,\n index,\n events: [...(probe?.events ?? [])],\n fault,\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost: settled === null ? null : settled - lostBefore,\n ...(lab.topology === null ? {} : { topology: lab.topology, middlebox: lab.middlebox.slice(middleboxFrom) }),\n };\n};\n/** This function waits for the first ping of the heartbeat of the client at the instant `after` or later: its first ping into a stall. */\nconst pingSent = (probe: Probe, after: number, within: number): Promise<ProbeEvent> =>\n new Promise((resolve, reject) => {\n const started = Date.now();\n const look = () => {\n const ping = probe.events.find((event) => event.ev === \"ping\" && event.t >= after);\n if (ping !== undefined) resolve(ping);\n else if (Date.now() - started > within) reject(new Error(`the client sent no ping into the stall within ${within} ms`));\n else setTimeout(look, 1);\n };\n look();\n });\n\n/**\n * This function waits until the client wrote `count` lines `dial`, one before each connection\n * that it tries, or until its deadline. It resolves after `within` ms at the latest.\n */\nconst dials = (probe: Probe, count: number, within: number): Promise<void> =>\n new Promise((resolve) => {\n const started = Date.now();\n const look = () => {\n const tried = probe.events.filter((event) => event.ev === \"dial\").length;\n const ended = probe.events.some((event) => event.ev === \"deadline\");\n if (tried >= count || ended || Date.now() - started > within) resolve();\n else setTimeout(look, 20);\n };\n look();\n });\n\n/** This time is the most that a run waits for the lines of the target after the end of its client. */\nconst LINES_MS = 5_000;\n\n/**\n * This function waits for the lines of a run's counts. The lines of the target come on their own\n * stream, thus they can come after the last line of the client. A line above a count comes in the\n * pause after the wait, thus it is in the run that wrote it.\n */\nconst linesCounted = async (lab: Lab, from: number, counts: readonly LineCount[]): Promise<void> => {\n const started = Date.now();\n const short = () => counts.some((each) => countOf(lab.server.slice(from), each.match) < each.count);\n while (short() && Date.now() - started < LINES_MS) await sleep(20);\n await sleep(QUIET_MS);\n};\n\n/** This function gives the netem specification of a cell: its latency, then the netem of its fault when it has one. */\nconst netemSpec = (cell: Cell, fault: string | undefined): string | null => {\n const parts = [\n ...(cell.latency === undefined ? [] : [`delay ${valueIn(cell.latency, \"ms\")}ms`]),\n ...(fault === undefined ? [] : [fault]),\n ];\n return parts.length === 0 ? null : parts.join(\" \");\n};\n\n/**\n * This function does one run. The client connects and gets its reply, the fault occurs, and an\n * in-flight client sends into it. The harness then waits for the observer to see the fault, or for\n * the silent window to end. The observer is the client, or the socket of the target for a cell on\n * the server side. It can also be a socket of a proxy of a topology.\n *\n * A stall stops by itself, at its length after the send of the request, and the\n * run waits for the reply. Then the harness removes the fault, thus the environment can serve the\n * next run. The run keeps the records of the prober from its start to its end. The frozen process\n * is the peer of the observer: the target, or the client for the server.\n *\n * A dry run does all of this but the fault: the warm-up of a cell whose fault ends its environment.\n */\nconst once = async (\n lab: Lab,\n cell: Cell,\n environment: number,\n index: number,\n dry = false,\n): Promise<Run> => {\n if (cell.before === true) return beforeOnce(lab, cell, environment, index);\n // a silence of the run before moved the routes: each run starts on the preferred path, with each session up\n await lab.fabric?.ready();\n const sessions = await lab.fabric?.sessions();\n const routesFrom = lab.fabric?.routes.length ?? 0;\n // each run starts from kernels that keep nothing from the runs before it\n await lab.forget();\n const from = lab.kernel.length;\n const middleboxFrom = lab.middlebox.length;\n const serverFrom = lab.server.length;\n const lostBefore = droppedSoFar(lab.kernel);\n const plan = cell.probe.plan === undefined ? undefined : schedule(cell.probe.plan.profile, cell.probe.plan.options);\n // the client load reads one plan with the schedule and the requests of each of its streams\n const load = cell.probe.streams === undefined ? undefined : loadPlanOf(cell.probe.streams);\n const files = [\n ...(plan === undefined ? [] : [{ content: JSON.stringify(plan), target: SCHEDULE_PATH }]),\n ...(load === undefined ? [] : [{ content: load.content, target: LOAD_PATH }]),\n ];\n const probe = await lab.probe(probeArgs(cell, lab), files.length === 0 ? undefined : files);\n const server = cell.observer === \"server\";\n const peer = server\n ? { freeze: () => probe.freeze(), thaw: () => probe.thaw() }\n : { freeze: () => lab.freeze(), thaw: () => lab.thaw() };\n // a client that stopped before the signal to send tells why in its last lines\n const go = () =>\n probe.go().catch((error: unknown) => {\n const last = probe.events.slice(-3).map((event) => JSON.stringify(event));\n throw new Error(`${(error as Error).message}; the client's last lines: ${last.join(\" \")}`);\n });\n const placed = {\n ...(lab.topology === null ? {} : { topology: lab.topology }),\n ...(plan === undefined ? {} : { schedule: plan }),\n ...(load === undefined ? {} : { streams: load.streams }),\n };\n const fabricOf = () => {\n if (lab.fabric === undefined) throw new Error(`${cell.name} silences a router of a lab with no fabric`);\n return lab.fabric;\n };\n /** This function gives the run as the records show it so far: the waits read it. */\n const partial = (): Run => ({\n environment,\n index,\n events: probe.events,\n fault: null,\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost: 0,\n ...placed,\n });\n let fault: Run[\"fault\"] = null;\n let heal: { t0: number; t1: number } | null = null;\n // a target with a named process freezes by SIGSTOP, with stamps, and a hold thaws it at its instant\n const signalled = !server && cell.target.program !== undefined;\n let thawing: Promise<{ t0: number; t1: number }> | null = null;\n try {\n await probe.until([\"ready\"], 15_000);\n if (dry) {\n if (cell.probe.mode !== \"idle\") await go();\n await sleep(500);\n } else {\n // the in-flight data of a run on the server side is the reply of the server. The request goes\n // out first, and the fault occurs while the server holds it (the timeout of BLPOP). A fin with\n // a request in flight kills the server while it holds the request, so it goes first too. So\n // does the request of an event at a hop that comes while the request is in flight\n const replyInFlight =\n cell.probe.mode === \"inflight\" &&\n ((server && cell.fault !== \"mtu-blackhole\") || cell.fault === \"fin\" || requestFirst(cell));\n if (replyInFlight) {\n // the client sends one sample after the file appears. The request reaches the server well\n // in the pause, and the reply waits for the timeout of the request\n await go();\n await sleep(200);\n } else {\n // The client acknowledges its first reply with a delayed ACK, 40 to 200 ms later\n // (TCP_DELACK_MIN to TCP_DELACK_MAX). A fault that comes first meets that ACK, not the\n // request or the idle time that the cell measures. So the fault waits until the ACK is out.\n await sleep(QUIET_MS);\n }\n const faultAt: FaultPlace = cell.faultAt ?? (server ? \"client\" : \"target\");\n // the direction of a simplex drop, relative to the namespace of the rule: in the target, or at\n // a proxy toward the client, the segments to the server come in; in the client, they go out\n const towardServerComesIn =\n faultAt === \"target\" || (isHopPlace(faultAt) && faultAt.toward === \"client\");\n const direction: FaultOptions[\"direction\"] =\n cell.drops === undefined\n ? undefined\n : (cell.drops === \"to-server\") === towardServerComesIn\n ? \"in\"\n : \"out\";\n const options: FaultOptions = {\n ...(direction === undefined ? {} : { direction }),\n ...(cell.icmp === undefined ? {} : { code: cell.icmp }),\n ...(cell.mtu === undefined ? {} : { above: cell.mtu }),\n };\n // a toxic of a cell whose fault is another one goes first: a slow close, then the close\n const toxicFirst = cell.toxic !== undefined && cell.fault !== \"toxic\";\n if (toxicFirst) await lab.toxic(cell.toxic!);\n // netem at the target shares its qdisc with the latency of the cell. At a hop, it is alone\n const netemAt: FaultPlace = cell.faultAt ?? \"target\";\n const netemOn = (fault: string | undefined) =>\n netemAt === \"target\" ? lab.netem(netemSpec(cell, fault), \"target\") : lab.netem(fault ?? null, netemAt);\n // an MTU drop goes where the long reply arrives: the namespace of the client\n const apply = async (): Promise<Run[\"fault\"]> => {\n switch (cell.fault) {\n case \"freeze-process\": {\n if (signalled) {\n const stamp = await lab.signal(\"STOP\");\n if (cell.hold !== undefined) {\n thawing = lab.signal(\"CONT\", stamp.t0 + valueIn(cell.hold, \"s\") * 1e9).then((thawed) => {\n heal = thawed;\n return thawed;\n });\n thawing.catch(() => undefined);\n }\n return stamp;\n }\n await peer.freeze();\n return null;\n }\n case \"fin\":\n await (server ? probe.kill() : lab.kill());\n return null;\n case \"unreachable\":\n return lab.fault(\"reject\", faultAt, { code: cell.icmp ?? \"host\" });\n case \"simplex\":\n return lab.fault(\"blackhole\", faultAt, options);\n case \"mtu-blackhole\":\n return lab.fault(\"mtu\", cell.faultAt ?? \"client\", { above: cell.mtu ?? 1200 });\n case \"netem\":\n return netemOn(cell.netem);\n case \"rst\":\n return lab.fault(\"rst\", faultAt);\n // the router or the proxy of the topology is the fault, or a calibration has none, or the\n // server holds the reply by itself: nothing to inject\n case \"middlebox-forget\":\n case \"proxy-idle\":\n case \"app-stall\":\n case \"none\":\n return null;\n case \"toxic\":\n if (cell.toxic === undefined) throw new Error(`${cell.name} names no toxic`);\n return lab.toxic(cell.toxic);\n case \"server-close\":\n await lab.serverClose();\n return null;\n case \"silence\":\n return fabricOf().silence();\n case \"hop-event\": {\n if (cell.event === undefined) throw new Error(`${cell.name} names no event`);\n const stamp = await lab.event(cell.event);\n // a stopped proxy thaws at the end of its hold, from inside the VM, as a frozen target does\n if (\"signal\" in cell.event && cell.event.signal === \"STOP\" && cell.hold !== undefined && stamp !== null) {\n const thaw = { hop: cell.event.hop, signal: \"CONT\" } as const;\n thawing = lab.event(thaw, false, stamp.t0 + valueIn(cell.hold, \"s\") * 1e9).then((thawed) => {\n if (thawed === null) throw new Error(`the hop ${thaw.hop} gave no stamp for CONT`);\n heal = thawed;\n return thawed;\n });\n thawing.catch(() => undefined);\n }\n return stamp;\n }\n default:\n // a stall is a black hole that stops by itself\n return lab.fault(\"blackhole\", faultAt);\n }\n };\n const lift = async (): Promise<void> => {\n switch (cell.fault) {\n case \"freeze-process\":\n if (signalled) {\n if (thawing !== null) await thawing.catch(() => lab.signal(\"CONT\"));\n else await lab.signal(\"CONT\");\n return undefined;\n }\n return peer.thaw();\n case \"fin\":\n case \"middlebox-forget\":\n case \"proxy-idle\":\n case \"server-close\":\n case \"app-stall\":\n case \"none\":\n return undefined;\n case \"hop-event\":\n // a stopped proxy thaws, at once if its hold did not thaw it\n if (cell.event !== undefined && \"signal\" in cell.event && cell.event.signal === \"STOP\") {\n const thaw = { hop: cell.event.hop, signal: \"CONT\" } as const;\n if (thawing !== null) await thawing.catch(() => lab.event(thaw));\n else await lab.event(thaw);\n return undefined;\n }\n // the undo of a query on the console, for example RESUME after PAUSE\n if (cell.event !== undefined) await lab.event(cell.event, true);\n return undefined;\n case \"unreachable\":\n return lab.lift(\"reject\", faultAt, { code: cell.icmp ?? \"host\" });\n case \"simplex\":\n return lab.lift(\"blackhole\", faultAt, options);\n case \"mtu-blackhole\":\n return lab.lift(\"mtu\", cell.faultAt ?? \"client\", { above: cell.mtu ?? 1200 });\n case \"netem\":\n await netemOn(undefined);\n return undefined;\n case \"rst\":\n return lab.lift(\"rst\", faultAt);\n case \"toxic\":\n await lab.toxic(null);\n return undefined;\n case \"silence\":\n await fabricOf().clear();\n return undefined;\n default:\n return heal === null ? lab.lift(\"blackhole\", faultAt) : undefined;\n }\n };\n fault = await apply();\n try {\n // an idle time before the request: a router forgets the flow in it, or a keepalive keeps it\n if (cell.idleBefore !== undefined && cell.probe.mode !== \"idle\")\n await sleep(valueIn(cell.idleBefore, \"ms\"));\n // a client in a gap sends its second request by itself, a gap after its first reply\n if ((cell.probe.mode === \"inflight\" || cell.probe.mode === \"stream\" || cell.probe.mode === \"schedule\") && !replyInFlight) await go();\n const { prediction } = cell;\n const http = cell.probe.http !== undefined;\n if (prediction.detects !== null && prediction.driver !== undefined) {\n // a driver cell: each of its bands ends, or its silent window passes from the fault\n if (prediction.detects) {\n await driverOutcome(cell, () => ({ ...partial(), fault }), driverWithin(cell));\n } else {\n await sleep(valueIn(prediction.window, \"s\") * 1_000);\n }\n await sleep(TAIL_MS);\n } else if (cell.probe.mode === \"gap\") {\n // the run ends when the second request does: its outcome is a part of the record\n const gap = cell.probe.http?.gap === undefined ? 0 : valueIn(cell.probe.http.gap, \"s\");\n const window = valueIn(prediction.detects ? prediction.high : prediction.window, \"s\");\n await probe.until(HTTP_DONE, (gap + window) * 2_000 + 10_000).catch(() => undefined);\n if (prediction.detects === null && prediction.counts !== undefined) await linesCounted(lab, serverFrom, prediction.counts);\n } else if (cell.fault === \"stall\") {\n if (cell.stall === undefined) throw new Error(`${cell.name} says no stall's length`);\n // the injector holds the end in the VM until the length of the stall after the send. An idle\n // client sends only the pings of its heartbeat: the stall counts from its first ping into it\n const window = valueIn(prediction.detects ? prediction.high : prediction.window, \"s\");\n const sent =\n cell.probe.mode === \"idle\"\n ? await pingSent(probe, fault?.t1 ?? 0, window * 1_000)\n : await requestSent(probe, 5_000);\n heal = await lab.heal(faultAt, sent.t + valueIn(cell.stall, \"s\") * 1e9);\n await probe.until([\"data\", \"error\", \"eof\", \"drop\"], window * 1_000).catch(() => undefined);\n } else if (cell.fault === \"silence\") {\n // the routers end this stall: the later move of the two leaves is its end. The verdict of a\n // stall reads it, thus a move outside the band of the cell makes the run void\n const window = valueIn(prediction.detects ? prediction.high : prediction.window, \"s\");\n await requestSent(probe, 5_000);\n await probe.until([\"data\", \"error\", \"eof\", \"drop\"], window * 1_000).catch(() => undefined);\n await sleep(MONITOR_MS);\n const moved = laterMove(fabricOf().routes.slice(routesFrom), fault?.t0 ?? 0);\n heal = moved === null ? null : { t0: moved, t1: moved };\n } else if (prediction.detects === null) {\n // a distribution: the stream ends by itself, or the connection does\n const window = valueIn(prediction.window, \"s\") * 1_000;\n await probe.until([\"done\", \"error\", \"eof\", \"deadline\"], window).catch(() => undefined);\n } else if (prediction.detects) {\n // a band whose reference can come late ends later: the run waits for its latest end\n const within = latestEndOf(prediction) * 2_000 + 10_000;\n if (cell.observer !== undefined && cell.observer !== \"client\") {\n // a target with its own detector writes a drop line when it drops the connection itself\n await observerError(cell, partial, within, () => lab.server.slice(serverFrom).some((line) => line.ev === \"drop\"));\n } else if (http && cell.probe.mode !== \"idle\") {\n // an HTTP client can send the request again on a new connection: its outcome ends the run\n await probe.until(HTTP_DONE, within).catch(() => undefined);\n } else {\n // an HTTP client writes `closed` when its pool closes an idle connection by itself, and\n // a program with its own detector writes `drop` when it drops the connection\n await probe.until([\"error\", \"eof\", \"deadline\", \"drop\", ...(http ? [\"closed\"] : [])], within).catch(() => undefined);\n }\n } else {\n await sleep(valueIn(prediction.window, \"s\") * 1_000);\n }\n } finally {\n await lift();\n if (toxicFirst) await lab.toxic(null);\n }\n // a thawed target answers the request that it held: the client sees the late reply. An idle\n // client sent no request\n if (cell.fault === \"freeze-process\" && !server && cell.probe.mode !== \"idle\" && cell.probe.mode !== \"schedule\")\n await probe.until([\"data\"], 5_000).catch(() => undefined);\n // the client tries its new connections after the fault lifted: one `dial` line for each try.\n // A measurement-only cell can give the waits too: the end of its connection has no band\n const expected = cell.prediction.detects !== false ? cell.prediction.reconnects : undefined;\n if (expected !== undefined) {\n const waits = expected.waits.reduce((sum, wait) => sum + valueIn(wait.high, \"s\"), 0);\n await dials(probe, 1 + expected.waits.length, waits * 2_000 + 5_000);\n }\n }\n } finally {\n await probe.stop();\n }\n // the prober drains its ring each 20 ms. Its next clock line closes the records of the run\n const settled = await lab.settle();\n const lost = settled === null ? null : settled - lostBefore;\n return {\n environment,\n index,\n events: [...probe.events],\n fault,\n ...(cell.fault === \"stall\" || cell.fault === \"silence\" || thawing !== null ? { heal } : {}),\n kernel: lab.kernel.slice(from),\n netns: lab.netns.client,\n targetNetns: lab.netns.target,\n lost,\n ...placed,\n ...(lab.topology === null ? {} : { middlebox: lab.middlebox.slice(middleboxFrom) }),\n ...(cell.target.lines === true ? { server: lab.server.slice(serverFrom) } : {}),\n ...(lab.fabric === undefined || sessions === undefined\n ? {}\n : { fabric: { routes: lab.fabric.routes.slice(routesFrom), established: { before: sessions, after: await lab.fabric.sessions() } } }),\n };\n};\n\n/** This function divides a count of runs across environments, as equally as possible. */\nexport const spread = (runs: number, environments: number): number[] =>\n Array.from(\n { length: environments },\n (_, at) => Math.floor(runs / environments) + (at < runs % environments ? 1 : 0),\n ).filter((count) => count > 0);\n\n/**\n * This function tells if the fault of a cell ends its environment. A server that stopped cannot serve\n * the next run. Also, a cell can say that its fault changes the environment (`fresh`).\n */\nconst endsEnvironment = (cell: Cell): boolean =>\n cell.fresh === true || (cell.fault === \"fin\" && (cell.observer === undefined || cell.observer === \"client\"));\n\n/** This function says one line for a run. */\nconst line = (cell: Cell, run: Run, read: Measured): string =>\n `${cell.name}: env ${run.environment} ${run.warmup === true ? \"warm-up\" : `run ${run.index}`} ${read.outcome.kind}` +\n `${read.elapsed === null ? \"\" : ` ${read.elapsed.value} s`}` +\n `${read.void === null ? \"\" : ` (void: ${read.void})`}`;\n\n/** This function adds to a run the share of the CPU that the host took while the run operated. */\nconst withSteal = async (work: () => Promise<Run>): Promise<Run> => {\n const before = readCpu();\n const run = await work();\n const after = readCpu();\n const steal = before === null || after === null ? null : stealShare(before, after);\n return steal === null ? run : { ...run, steal };\n};\n\n/**\n * This function does the part of the runs of a cell in one environment, and records its manifest.\n * A warm-up goes first, and the verdict does not count it. On a loaded machine, a new environment is\n * sometimes slow at first: its first exec, its first client, its first fault. The warm-up\n * of a cell whose fault ends the environment is a dry run, without the fault.\n */\nconst inEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n if (cell.group !== undefined) return inGroupEnvironment(cell, environment, count, say);\n if (cell.replicaSet !== undefined) return inReplicaSetEnvironment(cell, environment, count, say);\n if (cell.cluster !== undefined) return inClusterEnvironment(cell, environment, count, say);\n if (cell.kafka !== undefined) return inKafkaEnvironment(cell, environment, count, say);\n if (cell.pair !== undefined) return inPairEnvironment(cell, environment, count, say);\n const lab = await openLab(cell.target, cell.client ?? cell.probe.driver?.name ?? \"tcp\", cell.topology);\n try {\n // the settings of the target first: Redis applies tcp-keepalive to a client when it accepts it\n const settings = await lab.configure(cell.targetSettings ?? {});\n const targetSysctls = await lab.targetSysctl(cell.targetSysctls ?? {});\n if (cell.targetSetup !== undefined) await lab.setup(cell.targetSetup);\n // netem and a length match act on segments only when TSO, GSO and GRO are off on the two ends,\n // and on the hop that the fault is at\n if (cell.fault === \"mtu-blackhole\" || cell.fault === \"netem\") {\n await lab.offload(false, \"target\");\n await lab.offload(false, \"client\");\n if (isHopPlace(cell.faultAt)) await lab.offload(false, cell.faultAt);\n }\n // a latency is on the path before the client connects, thus its round trip and RTO include it\n const latency = netemSpec(cell, undefined);\n if (latency !== null) await lab.netem(latency, \"target\");\n // the first connection must not wait for ARP: under a delay, that is a longer first round trip\n await lab.warm();\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls), settings, targetSysctls);\n // after the first connection: a rule that starts conntrack must not count the packets of the warm-up\n const missing = await lab\n .namespaceSetup(cell.namespaceSetup ?? [])\n .then(() => lab.hostSysctl(cell.hostSysctls ?? []))\n .then(\n () => undefined,\n (error: unknown) => (error instanceof Error ? error.message : String(error)),\n );\n // each run records the jitter of its program, which sets the window of its pairings\n const timed = (run: Run): Run => ({ ...run, jitter: jitterOf(cell, run), ...(missing === undefined ? {} : { missing }) });\n const warmed = timed(await withSteal(() => once(lab, cell, environment, -1, endsEnvironment(cell))));\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = timed(await withSteal(() => once(lab, cell, environment, index)));\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n const host = await lab.restoreHost();\n return { manifest: host.length === 0 ? manifest : { ...manifest, host }, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a group cell in one environment. The warm-up is a\n * whole run with its fault, because no fault of a group ends its environment. A server that a\n * fin stopped starts again, and the group converges before each run.\n */\nconst inGroupEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openGroupLab(cell.group!, { watchSentinels: cell.calibrates === \"sentinels\" });\n try {\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const warmed = await groupOnce(lab, cell, environment, -1);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await groupOnce(lab, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a replica set cell in one environment. The warm-up\n * is a whole run with its fault, as for a group under Sentinels. The set converges before each run.\n */\nconst inReplicaSetEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openReplicaSetLab(cell.replicaSet!, cell.drill !== undefined);\n const once = cell.drill === undefined ? replicaSetOnce : drillOnce;\n try {\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const warmed = await once(lab, cell, environment, -1);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await once(lab, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a pair cell in one environment. The warm-up is a dry\n * run. The run promotes the standby, thus a pair cell has an environment for each run.\n */\nconst inPairEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openLab(cell.target, cell.client ?? cell.probe.driver?.name ?? \"tcp\", cell.topology);\n try {\n await lab.warm();\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const standby = await openStandby(lab, cell);\n const warmed = await pairOnce(lab, standby, cell, environment, -1, true);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await pairOnce(lab, standby, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a cluster cell in one environment. The warm-up is a\n * whole run with its fault, as for a replica set. The queue converges before each run.\n */\nconst inClusterEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openClusterLab(cell.cluster!);\n try {\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const warmed = await clusterOnce(lab, cell, environment, -1);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await clusterOnce(lab, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the part of the runs of a Kafka cell in one environment. The warm-up is a whole\n * run with its fault, as for a cluster. Each run makes its own topic.\n */\nconst inKafkaEnvironment = async (\n cell: Cell,\n environment: number,\n count: number,\n say: (line: string) => void,\n): Promise<{ manifest: Manifest; runs: Run[]; warmup: Run }> => {\n const lab = await openKafkaLab(cell.kafka!);\n const once = cell.kafka!.pause === undefined ? kafkaOnce : kafkaPauseOnce;\n try {\n const manifest = await lab.manifest(await lab.sysctl(cell.sysctls));\n const warmed = await once(lab, cell, environment, -1);\n const warmup: Run = { ...warmed, warmup: true };\n say(line(cell, warmup, measure(cell, warmup)));\n const runs: Run[] = [];\n for (let index = 0; index < count; index += 1) {\n const run = await once(lab, cell, environment, index);\n runs.push(run);\n say(line(cell, run, measure(cell, run)));\n }\n return { manifest, runs, warmup };\n } finally {\n await lab.close();\n }\n};\n\n/**\n * This function does the runs of a cell. They go across new environments, and each environment records\n * its manifest. Then the verdict judges the runs. A median across the edge of the band extends\n * the cell from 11 runs to 22, and then to 44, each extension in new environments. With a\n * concurrency of more than one, that many environments operate at the same time, each with its\n * own prober. The runs then go across at least as many environments.\n *\n * Each environment does a warm-up first, and the result keeps it apart from the counted runs.\n */\nexport const runCell = async (\n cell: Cell,\n say: (line: string) => void = () => {},\n): Promise<CellResult> => {\n const started = new Date().toISOString();\n const manifests: Manifest[] = [];\n const runs: Run[] = [];\n const warmups: Run[] = [];\n const concurrency = Math.max(1, cell.concurrency ?? 1);\n let target: number = cell.runs;\n let next = 0;\n for (;;) {\n const counts = spread(target - runs.length, Math.max(cell.environments, concurrency));\n for (let at = 0; at < counts.length; at += concurrency) {\n const batch = counts.slice(at, at + concurrency).map((count) => ({ count, env: next++ }));\n const done = await Promise.all(\n batch.map(({ count, env }) => inEnvironment(cell, env, count, say)),\n );\n for (const each of done) {\n manifests.push(each.manifest);\n // each run carries the HZ of its environment, which the rule of a late timer reads\n const hz = each.manifest.hz === null ? undefined : Number(each.manifest.hz);\n const withHz = (run: Run): Run => (hz === undefined ? run : { ...run, hz });\n runs.push(...each.runs.map(withHz));\n warmups.push(withHz(each.warmup));\n }\n }\n const { measured, verdict } = judge(cell, runs);\n const larger = STEPS.find((step) => step > runs.length);\n if (verdict.decision !== \"extend\" || larger === undefined) {\n const at = { started, ended: new Date().toISOString() };\n return { cell, manifests, runs, warmups, measured, verdict, at };\n }\n target = larger;\n }\n};\n"],"mappings":"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"}