@obolnetwork/obol-sdk 2.11.12 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/src/index.js +446 -134
- package/dist/browser/src/index.js.map +1 -1
- package/dist/cjs/src/blsUtils.js +3826 -0
- package/dist/cjs/src/blsUtils.js.map +1 -0
- package/dist/cjs/src/index.js +530 -222
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/cjs/src/verification/lockWorker.js +3828 -0
- package/dist/cjs/src/verification/lockWorker.js.map +1 -0
- package/dist/cjs/src/verification/parallelPool.js +3992 -0
- package/dist/cjs/src/verification/parallelPool.js.map +1 -0
- package/dist/esm/src/blsUtils.js +17 -0
- package/dist/esm/src/blsUtils.js.map +1 -0
- package/dist/esm/src/chunk-267HIPEB.js +4355 -0
- package/dist/esm/src/chunk-267HIPEB.js.map +1 -0
- package/dist/esm/src/chunk-OYZHSNKR.js +186 -0
- package/dist/esm/src/chunk-OYZHSNKR.js.map +1 -0
- package/dist/esm/src/index.js +835 -5000
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/verification/lockWorker.js +50 -0
- package/dist/esm/src/verification/lockWorker.js.map +1 -0
- package/dist/esm/src/verification/parallelPool.js +10 -0
- package/dist/esm/src/verification/parallelPool.js.map +1 -0
- package/dist/types/src/blsUtils.d.ts +2 -0
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/verification/common.d.ts +9 -0
- package/dist/types/src/verification/lockWorker.d.ts +13 -0
- package/dist/types/src/verification/parallelPool.d.ts +2 -0
- package/dist/types/test/verification/parallelPool.spec.d.ts +1 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__async,
|
|
3
|
+
__require,
|
|
4
|
+
blsAggregateSignatures,
|
|
5
|
+
blsRecoverDistributedPubkeyFromShares,
|
|
6
|
+
blsVerifyExtraShares,
|
|
7
|
+
blsVerifyMultiple
|
|
8
|
+
} from "./chunk-267HIPEB.js";
|
|
9
|
+
|
|
10
|
+
// src/verification/parallelPool.ts
|
|
11
|
+
import { fromHexString } from "@chainsafe/ssz";
|
|
12
|
+
var MIN_PARALLEL_VALIDATORS = 50;
|
|
13
|
+
var MIN_PARALLEL_BATCH_PAIRS = 100;
|
|
14
|
+
var MAX_WORKERS = 8;
|
|
15
|
+
var MIN_VALIDATORS_PER_WORKER = 25;
|
|
16
|
+
var MIN_PAIRS_PER_WORKER = 50;
|
|
17
|
+
var WORKER_TIMEOUT_MS = 6e4;
|
|
18
|
+
var workerThreadsCache;
|
|
19
|
+
var osCache;
|
|
20
|
+
var workerPathCache;
|
|
21
|
+
function loadWorkerThreads() {
|
|
22
|
+
if (workerThreadsCache !== void 0) return workerThreadsCache;
|
|
23
|
+
try {
|
|
24
|
+
workerThreadsCache = __require("worker_threads");
|
|
25
|
+
} catch (e) {
|
|
26
|
+
workerThreadsCache = null;
|
|
27
|
+
}
|
|
28
|
+
return workerThreadsCache;
|
|
29
|
+
}
|
|
30
|
+
function loadOs() {
|
|
31
|
+
if (osCache !== void 0) return osCache;
|
|
32
|
+
try {
|
|
33
|
+
osCache = __require("os");
|
|
34
|
+
} catch (e) {
|
|
35
|
+
osCache = null;
|
|
36
|
+
}
|
|
37
|
+
return osCache;
|
|
38
|
+
}
|
|
39
|
+
function getWorkerPath() {
|
|
40
|
+
if (workerPathCache !== void 0) return workerPathCache;
|
|
41
|
+
if (typeof __dirname === "undefined") return workerPathCache = null;
|
|
42
|
+
const path = __require("path");
|
|
43
|
+
const candidate = path.join(__dirname, "lockWorker.js");
|
|
44
|
+
try {
|
|
45
|
+
const fs = __require("fs");
|
|
46
|
+
if (!fs.existsSync(candidate)) return workerPathCache = null;
|
|
47
|
+
} catch (e) {
|
|
48
|
+
return workerPathCache = null;
|
|
49
|
+
}
|
|
50
|
+
return workerPathCache = candidate;
|
|
51
|
+
}
|
|
52
|
+
function chunkArrays(arr, n) {
|
|
53
|
+
const size = Math.ceil(arr.length / n);
|
|
54
|
+
const out = [];
|
|
55
|
+
for (let i = 0; i < arr.length; i += size) {
|
|
56
|
+
out.push(arr.slice(i, i + size));
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function verifySharesSync(shares, distributedKeys, threshold) {
|
|
61
|
+
for (let i = 0; i < shares.length; i++) {
|
|
62
|
+
const sharesBytes = shares[i].map((s) => fromHexString(s));
|
|
63
|
+
const dkBytes = fromHexString(distributedKeys[i]);
|
|
64
|
+
const recovered = blsRecoverDistributedPubkeyFromShares(
|
|
65
|
+
sharesBytes,
|
|
66
|
+
threshold
|
|
67
|
+
);
|
|
68
|
+
if (!recovered) return false;
|
|
69
|
+
if (recovered.length !== dkBytes.length) return false;
|
|
70
|
+
for (let j = 0; j < recovered.length; j++) {
|
|
71
|
+
if (recovered[j] !== dkBytes[j]) return false;
|
|
72
|
+
}
|
|
73
|
+
if (!blsVerifyExtraShares(sharesBytes, threshold, dkBytes)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
function runWorker(wt, workerFile, data) {
|
|
80
|
+
return __async(this, null, function* () {
|
|
81
|
+
return yield new Promise((resolve) => {
|
|
82
|
+
let settled = false;
|
|
83
|
+
const worker = new wt.Worker(workerFile, { workerData: data });
|
|
84
|
+
const finish = (result) => {
|
|
85
|
+
if (settled) return;
|
|
86
|
+
settled = true;
|
|
87
|
+
clearTimeout(timer);
|
|
88
|
+
worker.terminate();
|
|
89
|
+
resolve(result);
|
|
90
|
+
};
|
|
91
|
+
const timer = setTimeout(() => {
|
|
92
|
+
finish(false);
|
|
93
|
+
}, WORKER_TIMEOUT_MS);
|
|
94
|
+
worker.once("message", (msg) => {
|
|
95
|
+
finish(msg === true);
|
|
96
|
+
});
|
|
97
|
+
worker.once("error", () => {
|
|
98
|
+
finish(false);
|
|
99
|
+
});
|
|
100
|
+
worker.once("exit", (code) => {
|
|
101
|
+
if (code !== 0) finish(false);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function poolSize(itemCount, minPerWorker) {
|
|
107
|
+
const wt = loadWorkerThreads();
|
|
108
|
+
const os = loadOs();
|
|
109
|
+
const workerFile = getWorkerPath();
|
|
110
|
+
const numCpus = os ? os.cpus().length : 1;
|
|
111
|
+
const numWorkers = Math.min(
|
|
112
|
+
MAX_WORKERS,
|
|
113
|
+
Math.max(1, Math.floor(itemCount / minPerWorker)),
|
|
114
|
+
numCpus
|
|
115
|
+
);
|
|
116
|
+
return { numWorkers, wt, workerFile };
|
|
117
|
+
}
|
|
118
|
+
function verifySharesBinding(shares, distributedKeys, threshold) {
|
|
119
|
+
return __async(this, null, function* () {
|
|
120
|
+
if (shares.length !== distributedKeys.length) return false;
|
|
121
|
+
if (shares.length === 0) return true;
|
|
122
|
+
const { numWorkers, wt, workerFile } = poolSize(
|
|
123
|
+
shares.length,
|
|
124
|
+
MIN_VALIDATORS_PER_WORKER
|
|
125
|
+
);
|
|
126
|
+
if (wt === null || workerFile === null || shares.length < MIN_PARALLEL_VALIDATORS || numWorkers < 2) {
|
|
127
|
+
return verifySharesSync(shares, distributedKeys, threshold);
|
|
128
|
+
}
|
|
129
|
+
const shareChunks = chunkArrays(shares, numWorkers);
|
|
130
|
+
const keyChunks = chunkArrays(distributedKeys, numWorkers);
|
|
131
|
+
const results = yield Promise.all(
|
|
132
|
+
shareChunks.map(
|
|
133
|
+
(chunk, i) => __async(null, null, function* () {
|
|
134
|
+
return yield runWorker(wt, workerFile, {
|
|
135
|
+
mode: "shareBinding",
|
|
136
|
+
shares: chunk,
|
|
137
|
+
distributedKeys: keyChunks[i],
|
|
138
|
+
threshold
|
|
139
|
+
});
|
|
140
|
+
})
|
|
141
|
+
)
|
|
142
|
+
);
|
|
143
|
+
return results.every(Boolean);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function verifyBatchParallel(pubkeys, messages, signatures) {
|
|
147
|
+
return __async(this, null, function* () {
|
|
148
|
+
if (pubkeys.length !== messages.length || pubkeys.length !== signatures.length) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
if (pubkeys.length === 0) return true;
|
|
152
|
+
const { numWorkers, wt, workerFile } = poolSize(
|
|
153
|
+
pubkeys.length,
|
|
154
|
+
MIN_PAIRS_PER_WORKER
|
|
155
|
+
);
|
|
156
|
+
if (wt === null || workerFile === null || pubkeys.length < MIN_PARALLEL_BATCH_PAIRS || numWorkers < 2) {
|
|
157
|
+
return blsVerifyMultiple(
|
|
158
|
+
pubkeys,
|
|
159
|
+
messages,
|
|
160
|
+
blsAggregateSignatures(signatures)
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
const pkChunks = chunkArrays(pubkeys, numWorkers);
|
|
164
|
+
const msgChunks = chunkArrays(messages, numWorkers);
|
|
165
|
+
const sigChunks = chunkArrays(signatures, numWorkers);
|
|
166
|
+
const results = yield Promise.all(
|
|
167
|
+
pkChunks.map(
|
|
168
|
+
(pks, i) => __async(null, null, function* () {
|
|
169
|
+
return yield runWorker(wt, workerFile, {
|
|
170
|
+
mode: "verifyBatch",
|
|
171
|
+
pubkeys: pks,
|
|
172
|
+
messages: msgChunks[i],
|
|
173
|
+
aggregateSignature: blsAggregateSignatures(sigChunks[i])
|
|
174
|
+
});
|
|
175
|
+
})
|
|
176
|
+
)
|
|
177
|
+
);
|
|
178
|
+
return results.every(Boolean);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export {
|
|
183
|
+
verifySharesBinding,
|
|
184
|
+
verifyBatchParallel
|
|
185
|
+
};
|
|
186
|
+
//# sourceMappingURL=chunk-OYZHSNKR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/verification/parallelPool.ts"],"sourcesContent":["// Parallel BLS verification via Node worker_threads.\n//\n// IMPORTANT: only the CJS build actually runs in parallel. ESM Node and\n// browser bundles transparently fall back to sync. See the matrix in\n// PARALLEL_VALIDATION_PLAN.md. The main consumer flow (charon DKG ->\n// obol-api NestJS handler -> SDK CJS) is CJS, so it gets the speedup.\n//\n// Strategy:\n// - Look up the worker file via __dirname (CJS only). If undefined or the\n// file isn't where we expect (ESM, browser, source-mode tsx/jest), return\n// undefined and fall back to sync.\n// - Below MIN_PARALLEL_* thresholds, sync wins (worker spin-up dominates).\n// - Spawn one worker per chunk, await all, collapse to a single boolean.\n\nimport { fromHexString } from '@chainsafe/ssz';\nimport {\n blsAggregateSignatures,\n blsRecoverDistributedPubkeyFromShares,\n blsVerifyExtraShares,\n blsVerifyMultiple,\n} from '../blsUtils.js';\n// Type-only imports — erased at compile time, so they don't pull node:*\n// modules into the browser bundle.\nimport type * as WTNs from 'node:worker_threads';\nimport type * as OsNs from 'node:os';\nimport type * as PathNs from 'node:path';\nimport type * as FsNs from 'node:fs';\nimport type { WorkerInput } from './lockWorker.js';\n\nconst MIN_PARALLEL_VALIDATORS = 50;\nconst MIN_PARALLEL_BATCH_PAIRS = 100;\nconst MAX_WORKERS = 8;\nconst MIN_VALIDATORS_PER_WORKER = 25;\nconst MIN_PAIRS_PER_WORKER = 50;\n// Hard ceiling so a stuck worker can't leak past obol-api's HTTP timeout.\n// Biggest legitimate batch (~1000 pairs) finishes in ~3s on the bench; 60s\n// is conservative enough to never false-trip on real input.\nconst WORKER_TIMEOUT_MS = 60_000;\n\ntype WorkerThreads = typeof WTNs;\ntype NodeOs = typeof OsNs;\n\nlet workerThreadsCache: WorkerThreads | null | undefined;\nlet osCache: NodeOs | null | undefined;\n// Tri-state: undefined = uncached, null = checked & unavailable, string = path.\nlet workerPathCache: string | null | undefined;\n\nfunction loadWorkerThreads(): WorkerThreads | null {\n if (workerThreadsCache !== undefined) return workerThreadsCache;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n workerThreadsCache = require('node:worker_threads') as WorkerThreads;\n } catch {\n workerThreadsCache = null;\n }\n return workerThreadsCache;\n}\n\nfunction loadOs(): NodeOs | null {\n if (osCache !== undefined) return osCache;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n osCache = require('node:os') as NodeOs;\n } catch {\n osCache = null;\n }\n return osCache;\n}\n\nfunction getWorkerPath(): string | null {\n if (workerPathCache !== undefined) return workerPathCache;\n // CJS only. In ESM and browser builds __dirname is undefined, so this\n // memoizes null and the caller falls back to sync. See plan for the\n // full coverage matrix.\n if (typeof __dirname === 'undefined') return (workerPathCache = null);\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const path = require('node:path') as typeof PathNs;\n const candidate = path.join(__dirname, 'lockWorker.js');\n // Sanity check: running from source (tsx, ts-node, jest without a build)\n // also hits the CJS branch but the .js file isn't there yet. Without\n // memoizing null we'd re-run existsSync on every call.\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const fs = require('node:fs') as typeof FsNs;\n if (!fs.existsSync(candidate)) return (workerPathCache = null);\n } catch {\n return (workerPathCache = null);\n }\n return (workerPathCache = candidate);\n}\n\nfunction chunkArrays<T>(arr: T[], n: number): T[][] {\n const size = Math.ceil(arr.length / n);\n const out: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n out.push(arr.slice(i, i + size));\n }\n return out;\n}\n\nfunction verifySharesSync(\n shares: string[][],\n distributedKeys: string[],\n threshold: number,\n): boolean {\n for (let i = 0; i < shares.length; i++) {\n const sharesBytes = shares[i].map(s => fromHexString(s));\n const dkBytes = fromHexString(distributedKeys[i]);\n const recovered = blsRecoverDistributedPubkeyFromShares(\n sharesBytes,\n threshold,\n );\n if (!recovered) return false;\n if (recovered.length !== dkBytes.length) return false;\n for (let j = 0; j < recovered.length; j++) {\n if (recovered[j] !== dkBytes[j]) return false;\n }\n if (!blsVerifyExtraShares(sharesBytes, threshold, dkBytes)) {\n return false;\n }\n }\n return true;\n}\n\nasync function runWorker(\n wt: WorkerThreads,\n workerFile: string,\n data: WorkerInput,\n): Promise<boolean> {\n return await new Promise(resolve => {\n let settled = false;\n const worker = new wt.Worker(workerFile, { workerData: data });\n const finish = (result: boolean): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n resolve(result);\n };\n const timer = setTimeout(() => {\n finish(false);\n }, WORKER_TIMEOUT_MS);\n worker.once('message', (msg: unknown) => {\n finish(msg === true);\n });\n worker.once('error', () => {\n finish(false);\n });\n worker.once('exit', code => {\n if (code !== 0) finish(false);\n });\n });\n}\n\nfunction poolSize(\n itemCount: number,\n minPerWorker: number,\n): {\n numWorkers: number;\n wt: WorkerThreads | null;\n workerFile: string | null;\n} {\n const wt = loadWorkerThreads();\n const os = loadOs();\n const workerFile = getWorkerPath();\n const numCpus = os ? os.cpus().length : 1;\n const numWorkers = Math.min(\n MAX_WORKERS,\n Math.max(1, Math.floor(itemCount / minPerWorker)),\n numCpus,\n );\n return { numWorkers, wt, workerFile };\n}\n\nexport async function verifySharesBinding(\n shares: string[][],\n distributedKeys: string[],\n threshold: number,\n): Promise<boolean> {\n if (shares.length !== distributedKeys.length) return false;\n if (shares.length === 0) return true;\n\n const { numWorkers, wt, workerFile } = poolSize(\n shares.length,\n MIN_VALIDATORS_PER_WORKER,\n );\n\n // Inline the guard so TS narrows wt/workerFile for the parallel path below\n // (avoids non-null assertions).\n if (\n wt === null ||\n workerFile === null ||\n shares.length < MIN_PARALLEL_VALIDATORS ||\n numWorkers < 2\n ) {\n return verifySharesSync(shares, distributedKeys, threshold);\n }\n\n const shareChunks = chunkArrays(shares, numWorkers);\n const keyChunks = chunkArrays(distributedKeys, numWorkers);\n\n const results = await Promise.all(\n shareChunks.map(\n async (chunk, i) =>\n await runWorker(wt, workerFile, {\n mode: 'shareBinding',\n shares: chunk,\n distributedKeys: keyChunks[i],\n threshold,\n }),\n ),\n );\n return results.every(Boolean);\n}\n\n// Verify a batch of (pubkey, message, individual signature) triples.\n// Sync path aggregates all sigs and runs blsVerifyMultiple once (matches the\n// previous behavior). Parallel path splits into chunks; each chunk's sigs are\n// aggregated and verified independently — same total pairing count, K× wall\n// time speedup.\nexport async function verifyBatchParallel(\n pubkeys: Uint8Array[],\n messages: Uint8Array[],\n signatures: Uint8Array[],\n): Promise<boolean> {\n if (\n pubkeys.length !== messages.length ||\n pubkeys.length !== signatures.length\n ) {\n return false;\n }\n if (pubkeys.length === 0) return true;\n\n const { numWorkers, wt, workerFile } = poolSize(\n pubkeys.length,\n MIN_PAIRS_PER_WORKER,\n );\n\n if (\n wt === null ||\n workerFile === null ||\n pubkeys.length < MIN_PARALLEL_BATCH_PAIRS ||\n numWorkers < 2\n ) {\n return blsVerifyMultiple(\n pubkeys,\n messages,\n blsAggregateSignatures(signatures),\n );\n }\n\n const pkChunks = chunkArrays(pubkeys, numWorkers);\n const msgChunks = chunkArrays(messages, numWorkers);\n const sigChunks = chunkArrays(signatures, numWorkers);\n\n const results = await Promise.all(\n pkChunks.map(\n async (pks, i) =>\n await runWorker(wt, workerFile, {\n mode: 'verifyBatch',\n pubkeys: pks,\n messages: msgChunks[i],\n aggregateSignature: blsAggregateSignatures(sigChunks[i]),\n }),\n ),\n );\n return results.every(Boolean);\n}\n"],"mappings":";;;;;;;;;;AAcA,SAAS,qBAAqB;AAe9B,IAAM,0BAA0B;AAChC,IAAM,2BAA2B;AACjC,IAAM,cAAc;AACpB,IAAM,4BAA4B;AAClC,IAAM,uBAAuB;AAI7B,IAAM,oBAAoB;AAK1B,IAAI;AACJ,IAAI;AAEJ,IAAI;AAEJ,SAAS,oBAA0C;AACjD,MAAI,uBAAuB,OAAW,QAAO;AAC7C,MAAI;AAEF,yBAAqB,UAAQ,gBAAqB;AAAA,EACpD,SAAQ;AACN,yBAAqB;AAAA,EACvB;AACA,SAAO;AACT;AAEA,SAAS,SAAwB;AAC/B,MAAI,YAAY,OAAW,QAAO;AAClC,MAAI;AAEF,cAAU,UAAQ,IAAS;AAAA,EAC7B,SAAQ;AACN,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAEA,SAAS,gBAA+B;AACtC,MAAI,oBAAoB,OAAW,QAAO;AAI1C,MAAI,OAAO,cAAc,YAAa,QAAQ,kBAAkB;AAEhE,QAAM,OAAO,UAAQ,MAAW;AAChC,QAAM,YAAY,KAAK,KAAK,WAAW,eAAe;AAItD,MAAI;AAEF,UAAM,KAAK,UAAQ,IAAS;AAC5B,QAAI,CAAC,GAAG,WAAW,SAAS,EAAG,QAAQ,kBAAkB;AAAA,EAC3D,SAAQ;AACN,WAAQ,kBAAkB;AAAA,EAC5B;AACA,SAAQ,kBAAkB;AAC5B;AAEA,SAAS,YAAe,KAAU,GAAkB;AAClD,QAAM,OAAO,KAAK,KAAK,IAAI,SAAS,CAAC;AACrC,QAAM,MAAa,CAAC;AACpB,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,MAAM;AACzC,QAAI,KAAK,IAAI,MAAM,GAAG,IAAI,IAAI,CAAC;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,iBACP,QACA,iBACA,WACS;AACT,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,cAAc,OAAO,CAAC,EAAE,IAAI,OAAK,cAAc,CAAC,CAAC;AACvD,UAAM,UAAU,cAAc,gBAAgB,CAAC,CAAC;AAChD,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AACA,QAAI,CAAC,UAAW,QAAO;AACvB,QAAI,UAAU,WAAW,QAAQ,OAAQ,QAAO;AAChD,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,UAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,EAAG,QAAO;AAAA,IAC1C;AACA,QAAI,CAAC,qBAAqB,aAAa,WAAW,OAAO,GAAG;AAC1D,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAe,UACb,IACA,YACA,MACkB;AAAA;AAClB,WAAO,MAAM,IAAI,QAAQ,aAAW;AAClC,UAAI,UAAU;AACd,YAAM,SAAS,IAAI,GAAG,OAAO,YAAY,EAAE,YAAY,KAAK,CAAC;AAC7D,YAAM,SAAS,CAAC,WAA0B;AACxC,YAAI,QAAS;AACb,kBAAU;AACV,qBAAa,KAAK;AAElB,eAAO,UAAU;AACjB,gBAAQ,MAAM;AAAA,MAChB;AACA,YAAM,QAAQ,WAAW,MAAM;AAC7B,eAAO,KAAK;AAAA,MACd,GAAG,iBAAiB;AACpB,aAAO,KAAK,WAAW,CAAC,QAAiB;AACvC,eAAO,QAAQ,IAAI;AAAA,MACrB,CAAC;AACD,aAAO,KAAK,SAAS,MAAM;AACzB,eAAO,KAAK;AAAA,MACd,CAAC;AACD,aAAO,KAAK,QAAQ,UAAQ;AAC1B,YAAI,SAAS,EAAG,QAAO,KAAK;AAAA,MAC9B,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAEA,SAAS,SACP,WACA,cAKA;AACA,QAAM,KAAK,kBAAkB;AAC7B,QAAM,KAAK,OAAO;AAClB,QAAM,aAAa,cAAc;AACjC,QAAM,UAAU,KAAK,GAAG,KAAK,EAAE,SAAS;AACxC,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,YAAY,CAAC;AAAA,IAChD;AAAA,EACF;AACA,SAAO,EAAE,YAAY,IAAI,WAAW;AACtC;AAEA,SAAsB,oBACpB,QACA,iBACA,WACkB;AAAA;AAClB,QAAI,OAAO,WAAW,gBAAgB,OAAQ,QAAO;AACrD,QAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,UAAM,EAAE,YAAY,IAAI,WAAW,IAAI;AAAA,MACrC,OAAO;AAAA,MACP;AAAA,IACF;AAIA,QACE,OAAO,QACP,eAAe,QACf,OAAO,SAAS,2BAChB,aAAa,GACb;AACA,aAAO,iBAAiB,QAAQ,iBAAiB,SAAS;AAAA,IAC5D;AAEA,UAAM,cAAc,YAAY,QAAQ,UAAU;AAClD,UAAM,YAAY,YAAY,iBAAiB,UAAU;AAEzD,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,YAAY;AAAA,QACV,CAAO,OAAO,MAAG;AACf,uBAAM,UAAU,IAAI,YAAY;AAAA,YAC9B,MAAM;AAAA,YACN,QAAQ;AAAA,YACR,iBAAiB,UAAU,CAAC;AAAA,YAC5B;AAAA,UACF,CAAC;AAAA;AAAA,MACL;AAAA,IACF;AACA,WAAO,QAAQ,MAAM,OAAO;AAAA,EAC9B;AAAA;AAOA,SAAsB,oBACpB,SACA,UACA,YACkB;AAAA;AAClB,QACE,QAAQ,WAAW,SAAS,UAC5B,QAAQ,WAAW,WAAW,QAC9B;AACA,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,UAAM,EAAE,YAAY,IAAI,WAAW,IAAI;AAAA,MACrC,QAAQ;AAAA,MACR;AAAA,IACF;AAEA,QACE,OAAO,QACP,eAAe,QACf,QAAQ,SAAS,4BACjB,aAAa,GACb;AACA,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,uBAAuB,UAAU;AAAA,MACnC;AAAA,IACF;AAEA,UAAM,WAAW,YAAY,SAAS,UAAU;AAChD,UAAM,YAAY,YAAY,UAAU,UAAU;AAClD,UAAM,YAAY,YAAY,YAAY,UAAU;AAEpD,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,SAAS;AAAA,QACP,CAAO,KAAK,MAAG;AACb,uBAAM,UAAU,IAAI,YAAY;AAAA,YAC9B,MAAM;AAAA,YACN,SAAS;AAAA,YACT,UAAU,UAAU,CAAC;AAAA,YACrB,oBAAoB,uBAAuB,UAAU,CAAC,CAAC;AAAA,UACzD,CAAC;AAAA;AAAA,MACL;AAAA,IACF;AACA,WAAO,QAAQ,MAAM,OAAO;AAAA,EAC9B;AAAA;","names":[]}
|