@isidorus/cpu 0.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/binding.gyp +103 -0
- package/dist/ts/_native.d.ts +13 -0
- package/dist/ts/_native.d.ts.map +1 -0
- package/dist/ts/_native.js +22 -0
- package/dist/ts/_native.js.map +1 -0
- package/dist/ts/graph.d.ts +91 -0
- package/dist/ts/graph.d.ts.map +1 -0
- package/dist/ts/graph.js +95 -0
- package/dist/ts/graph.js.map +1 -0
- package/dist/ts/index.d.ts +47 -0
- package/dist/ts/index.d.ts.map +1 -0
- package/dist/ts/index.js +58 -0
- package/dist/ts/index.js.map +1 -0
- package/dist/ts/inference-pool.d.ts +84 -0
- package/dist/ts/inference-pool.d.ts.map +1 -0
- package/dist/ts/inference-pool.js +625 -0
- package/dist/ts/inference-pool.js.map +1 -0
- package/dist/ts/inference_pool.d.ts +99 -0
- package/dist/ts/inference_pool.d.ts.map +1 -0
- package/dist/ts/inference_pool.js +370 -0
- package/dist/ts/inference_pool.js.map +1 -0
- package/dist/ts/install-libtensorflow.d.ts +34 -0
- package/dist/ts/install-libtensorflow.d.ts.map +1 -0
- package/dist/ts/install-libtensorflow.js +254 -0
- package/dist/ts/install-libtensorflow.js.map +1 -0
- package/dist/ts/ops/array_ops.d.ts +29 -0
- package/dist/ts/ops/array_ops.d.ts.map +1 -0
- package/dist/ts/ops/array_ops.js +54 -0
- package/dist/ts/ops/array_ops.js.map +1 -0
- package/dist/ts/ops/index.d.ts +5 -0
- package/dist/ts/ops/index.d.ts.map +1 -0
- package/dist/ts/ops/index.js +5 -0
- package/dist/ts/ops/index.js.map +1 -0
- package/dist/ts/ops/math_ops.d.ts +96 -0
- package/dist/ts/ops/math_ops.d.ts.map +1 -0
- package/dist/ts/ops/math_ops.js +277 -0
- package/dist/ts/ops/math_ops.js.map +1 -0
- package/dist/ts/ops/nn_ops.d.ts +130 -0
- package/dist/ts/ops/nn_ops.d.ts.map +1 -0
- package/dist/ts/ops/nn_ops.js +340 -0
- package/dist/ts/ops/nn_ops.js.map +1 -0
- package/dist/ts/ops/variable_ops.d.ts +128 -0
- package/dist/ts/ops/variable_ops.d.ts.map +1 -0
- package/dist/ts/ops/variable_ops.js +267 -0
- package/dist/ts/ops/variable_ops.js.map +1 -0
- package/dist/ts/session.d.ts +83 -0
- package/dist/ts/session.d.ts.map +1 -0
- package/dist/ts/session.js +81 -0
- package/dist/ts/session.js.map +1 -0
- package/package.json +63 -0
- package/scripts/install.js +100 -0
- package/scripts/test-install.js +82 -0
- package/scripts/test.js +45 -0
- package/src/native/addon.cc +12 -0
- package/src/native/graph.cc +442 -0
- package/src/native/graph.h +52 -0
- package/src/native/platform_tf.h +8 -0
- package/src/native/session.cc +716 -0
- package/src/native/session.h +92 -0
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InferencePool — strategy-aware inference execution with CPU affinity.
|
|
3
|
+
*
|
|
4
|
+
* Strategies:
|
|
5
|
+
*
|
|
6
|
+
* worker-pool N Workers × Session(intra=1, inter=1)
|
|
7
|
+
* JS controls parallelism. Each Worker owns one Session.
|
|
8
|
+
* N concurrent requests run on N cores simultaneously.
|
|
9
|
+
* Best: small/medium models, high concurrency.
|
|
10
|
+
*
|
|
11
|
+
* tf-parallel 1 Session × Session(intra=hw, inter=1)
|
|
12
|
+
* TF's eigen threadpool owns all TF cores for one request.
|
|
13
|
+
* Concurrent requests queue behind each other.
|
|
14
|
+
* Best: large models where one matmul fills all cores.
|
|
15
|
+
*
|
|
16
|
+
* auto Probe-based selection:
|
|
17
|
+
* model < 150 MB → worker-pool (no probe)
|
|
18
|
+
* model ≥ 150 MB + probeShape → warm probe → threshold
|
|
19
|
+
* model ≥ 150 MB, no probeShape → tf-parallel (fallback)
|
|
20
|
+
*
|
|
21
|
+
* CPU affinity (reserveCores):
|
|
22
|
+
* reserveCores = R pins TF computation to the LAST (N-R) cores.
|
|
23
|
+
* The FIRST R cores stay free for the event loop, libuv I/O, opencv, etc.
|
|
24
|
+
* The fence is applied in OnRunWork immediately before/after TF_SessionRun.
|
|
25
|
+
*/
|
|
26
|
+
import { Worker, isMainThread, parentPort, workerData } from "worker_threads";
|
|
27
|
+
import { availableParallelism } from "os";
|
|
28
|
+
import { statSync } from "fs";
|
|
29
|
+
import { performance } from "perf_hooks";
|
|
30
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
31
|
+
const IDLE = 0;
|
|
32
|
+
const WORK = 1;
|
|
33
|
+
const DONE = 2;
|
|
34
|
+
const SHUTDOWN = 3;
|
|
35
|
+
const CTRL_SLOTS = 4; // Int32 slots per worker in the control SAB
|
|
36
|
+
const SIZE_THRESHOLD_BYTES = 150 * 1024 * 1024; // 150 MB
|
|
37
|
+
const DEFAULT_AUTO_THRESHOLD = 20; // ms
|
|
38
|
+
// ─── Worker-side logic ──────────────────────────────────────────────────────
|
|
39
|
+
//
|
|
40
|
+
// This block runs when the same file is loaded as a Worker thread.
|
|
41
|
+
// The worker owns exactly one TFSession with intra_op=1, so all parallelism
|
|
42
|
+
// is expressed at the Worker level (N workers = N cores).
|
|
43
|
+
//
|
|
44
|
+
// Control protocol (per-worker Int32Array over a SharedArrayBuffer):
|
|
45
|
+
// slot[0] = IDLE → parked, waiting for work
|
|
46
|
+
// WORK → main thread has a request ready
|
|
47
|
+
// DONE → worker finished, result sent via postMessage
|
|
48
|
+
// SHUTDOWN → main thread requests exit
|
|
49
|
+
//
|
|
50
|
+
// Message protocol (postMessage, ordered relative to Atomics):
|
|
51
|
+
// main → worker: { inputData: Buffer, inputShape: number[], inputDtype: number }
|
|
52
|
+
// worker → main: { type: "ready" }
|
|
53
|
+
// { type: "result", outputs: TensorValue[], inferenceMs: number }
|
|
54
|
+
// { type: "work_error", error: string }
|
|
55
|
+
// { type: "shutdown_ack" }
|
|
56
|
+
//
|
|
57
|
+
// Ordering guarantee:
|
|
58
|
+
// Main posts the input message BEFORE storing WORK + notifying,
|
|
59
|
+
// so the worker's Atomics.wait wakes AFTER the message is queued.
|
|
60
|
+
// Node.js buffers port messages until a listener is registered,
|
|
61
|
+
// so parentPort.once("message", ...) safely receives the queued message.
|
|
62
|
+
if (!isMainThread) {
|
|
63
|
+
const { ctrlSab, workerIndex, modelPath, inputOp, outputOps } = workerData;
|
|
64
|
+
const ctrl = new Int32Array(ctrlSab, workerIndex * CTRL_SLOTS * 4, CTRL_SLOTS);
|
|
65
|
+
// ── Init ──────────────────────────────────────────────────────────────────
|
|
66
|
+
let sess;
|
|
67
|
+
try {
|
|
68
|
+
const { TFSession } = await import("jude-tf");
|
|
69
|
+
sess = await TFSession.loadFrozenGraph(modelPath);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
parentPort.postMessage({
|
|
73
|
+
type: "init_error",
|
|
74
|
+
error: err?.stack ?? String(err),
|
|
75
|
+
});
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
Atomics.store(ctrl, 0, IDLE);
|
|
79
|
+
parentPort.postMessage({ type: "ready" });
|
|
80
|
+
// Reinterpret raw bytes as the correct typed array for jude-tf.
|
|
81
|
+
// postMessage structured-clone strips the Buffer prototype, so the worker
|
|
82
|
+
// receives a plain Uint8Array. We reinterpret the underlying bytes as the
|
|
83
|
+
// correct typed array so jude-tf sees the right TF_DataType.
|
|
84
|
+
function asTypedArray(buf, dtype) {
|
|
85
|
+
const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
86
|
+
switch (dtype) {
|
|
87
|
+
case 1:
|
|
88
|
+
return new Float32Array(ab); // TF_FLOAT
|
|
89
|
+
case 2:
|
|
90
|
+
return new Float64Array(ab); // TF_DOUBLE
|
|
91
|
+
case 3:
|
|
92
|
+
return new Int32Array(ab); // TF_INT32
|
|
93
|
+
case 4:
|
|
94
|
+
return new Uint8Array(ab); // TF_UINT8
|
|
95
|
+
case 9:
|
|
96
|
+
return new BigInt64Array(ab); // TF_INT64
|
|
97
|
+
default:
|
|
98
|
+
return new Uint8Array(ab);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ── Work loop ─────────────────────────────────────────────────────────────
|
|
102
|
+
// Atomics.wait BLOCKS the worker thread (allowed in Worker threads, not in
|
|
103
|
+
// the main thread). The block is intentional — the worker is dedicated to
|
|
104
|
+
// inference and has no other async work to process while parked.
|
|
105
|
+
while (true) {
|
|
106
|
+
// Park until main thread sets ctrl to WORK or SHUTDOWN.
|
|
107
|
+
Atomics.wait(ctrl, 0, IDLE);
|
|
108
|
+
const state = Atomics.load(ctrl, 0);
|
|
109
|
+
if (state === SHUTDOWN) {
|
|
110
|
+
sess.destroy();
|
|
111
|
+
parentPort.postMessage({ type: "shutdown_ack" });
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
if (state === WORK) {
|
|
115
|
+
// Receive input data. Main posted it BEFORE storing WORK,
|
|
116
|
+
// so the message is already queued in the port's buffer.
|
|
117
|
+
const msg = await new Promise((resolve) => parentPort.once("message", resolve));
|
|
118
|
+
try {
|
|
119
|
+
const t0 = performance.now();
|
|
120
|
+
const inputArray = asTypedArray(msg.inputData, msg.inputDtype);
|
|
121
|
+
const results = await sess.run({ [inputOp]: inputArray }, outputOps);
|
|
122
|
+
const inferenceMs = performance.now() - t0;
|
|
123
|
+
Atomics.store(ctrl, 0, DONE);
|
|
124
|
+
Atomics.notify(ctrl, 0, 1);
|
|
125
|
+
parentPort.postMessage({
|
|
126
|
+
type: "result",
|
|
127
|
+
outputs: outputOps.map((k) => {
|
|
128
|
+
const r = results[k];
|
|
129
|
+
const view = r.data;
|
|
130
|
+
return {
|
|
131
|
+
dtype: r.dtype,
|
|
132
|
+
shape: r.shape,
|
|
133
|
+
// Copy into a Buffer — postMessage will structured-clone it as
|
|
134
|
+
// Uint8Array on the receiving end; the main thread wraps it back
|
|
135
|
+
// into a Buffer in handleMessage.
|
|
136
|
+
data: Buffer.from(view.buffer, view.byteOffset, view.byteLength),
|
|
137
|
+
};
|
|
138
|
+
}),
|
|
139
|
+
inferenceMs,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
console.error(`[worker ${workerIndex}] error:`, err?.stack ?? String(err));
|
|
144
|
+
Atomics.store(ctrl, 0, DONE);
|
|
145
|
+
Atomics.notify(ctrl, 0, 1);
|
|
146
|
+
parentPort.postMessage({
|
|
147
|
+
type: "work_error",
|
|
148
|
+
error: err?.stack ?? String(err),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// Use compareExchange instead of store — if the main thread wrote
|
|
152
|
+
// SHUTDOWN between our DONE store and here, don't overwrite it.
|
|
153
|
+
// Otherwise the next Atomics.wait(ctrl, 0, IDLE) would block forever
|
|
154
|
+
// waiting for a notify that never comes.
|
|
155
|
+
Atomics.compareExchange(ctrl, 0, DONE, IDLE);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export class InferencePool {
|
|
160
|
+
strategy;
|
|
161
|
+
reserveCores;
|
|
162
|
+
workerSlots;
|
|
163
|
+
queue;
|
|
164
|
+
ctrlSab;
|
|
165
|
+
// tf-parallel path — exactly one of these pairs is non-null:
|
|
166
|
+
// (tfParallelGraph, tfParallelSess) — native @isidorus/cpu Session
|
|
167
|
+
// uses Graph.getOp() for feed/fetch
|
|
168
|
+
// (null, tfParallelSess) — jude-tf TFSession fallback
|
|
169
|
+
// uses dict API { [opName]: data }
|
|
170
|
+
tfParallelGraph;
|
|
171
|
+
tfParallelSess;
|
|
172
|
+
tfParallelBusy;
|
|
173
|
+
tfParallelQueue;
|
|
174
|
+
modelPath;
|
|
175
|
+
inputOp;
|
|
176
|
+
outputOps;
|
|
177
|
+
constructor(params) {
|
|
178
|
+
this.strategy = params.strategy;
|
|
179
|
+
this.reserveCores = params.reserveCores;
|
|
180
|
+
this.workerSlots = params.workerSlots;
|
|
181
|
+
this.queue = params.queue;
|
|
182
|
+
this.ctrlSab = params.ctrlSab;
|
|
183
|
+
this.tfParallelGraph = params.tfParallelGraph;
|
|
184
|
+
this.tfParallelSess = params.tfParallelSess;
|
|
185
|
+
this.tfParallelBusy = false;
|
|
186
|
+
this.tfParallelQueue = [];
|
|
187
|
+
this.modelPath = params.modelPath;
|
|
188
|
+
this.inputOp = params.inputOp;
|
|
189
|
+
this.outputOps = params.outputOps;
|
|
190
|
+
}
|
|
191
|
+
// ── Factory ────────────────────────────────────────────────────────────────
|
|
192
|
+
static async create(opts) {
|
|
193
|
+
// Auto-discover input/output op names if not provided.
|
|
194
|
+
// Loads the frozen graph once via jude-tf, reads inferred Placeholder
|
|
195
|
+
// names and sink op names, then destroys the probe session.
|
|
196
|
+
if (!opts.inputOp || !opts.outputOps?.length) {
|
|
197
|
+
const { TFSession } = await import("jude-tf");
|
|
198
|
+
const probe = await TFSession.loadFrozenGraph(opts.modelPath);
|
|
199
|
+
opts.inputOp ??= probe.inputs[0];
|
|
200
|
+
opts.outputOps ??= probe.outputs;
|
|
201
|
+
probe.destroy();
|
|
202
|
+
if (!opts.inputOp)
|
|
203
|
+
throw new Error(`Could not infer inputOp from ${opts.modelPath}`);
|
|
204
|
+
if (!opts.outputOps?.length)
|
|
205
|
+
throw new Error(`Could not infer outputOps from ${opts.modelPath}`);
|
|
206
|
+
}
|
|
207
|
+
const requestedStrategy = opts.strategy ?? "auto";
|
|
208
|
+
const concurrency = opts.concurrency ?? availableParallelism();
|
|
209
|
+
const autoThreshold = opts.autoThresholdMs ?? DEFAULT_AUTO_THRESHOLD;
|
|
210
|
+
const reserveCores = opts.reserveCores ?? 0;
|
|
211
|
+
let resolved;
|
|
212
|
+
if (requestedStrategy === "worker-pool") {
|
|
213
|
+
resolved = "worker-pool";
|
|
214
|
+
}
|
|
215
|
+
else if (requestedStrategy === "tf-parallel") {
|
|
216
|
+
resolved = "tf-parallel";
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
// auto — file size as cheap first signal, probe if ambiguous
|
|
220
|
+
const modelBytes = statSync(opts.modelPath).size;
|
|
221
|
+
if (modelBytes < SIZE_THRESHOLD_BYTES) {
|
|
222
|
+
resolved = "worker-pool";
|
|
223
|
+
}
|
|
224
|
+
else if (!opts.probeShape) {
|
|
225
|
+
resolved = "tf-parallel";
|
|
226
|
+
process.stderr.write(`[isidorus] auto: ${(modelBytes / 1024 / 1024).toFixed(1)}MB >= ` +
|
|
227
|
+
`threshold, no probeShape → tf-parallel\n`);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Warm probe with intra=1 — measure single-core inference time
|
|
231
|
+
const { TFSession } = await import("jude-tf");
|
|
232
|
+
const probeSess = await TFSession.loadFrozenGraph(opts.modelPath);
|
|
233
|
+
const probeInput = Buffer.alloc(opts.probeShape.reduce((a, b) => a * b, 1) * 4);
|
|
234
|
+
await probeSess.runAsync({ [opts.inputOp]: probeInput }, opts.outputOps);
|
|
235
|
+
const t0 = performance.now();
|
|
236
|
+
await probeSess.runAsync({ [opts.inputOp]: probeInput }, opts.outputOps);
|
|
237
|
+
const probeMs = performance.now() - t0;
|
|
238
|
+
probeSess.destroy();
|
|
239
|
+
resolved = probeMs >= autoThreshold ? "tf-parallel" : "worker-pool";
|
|
240
|
+
process.stderr.write(`[isidorus] auto: probe=${probeMs.toFixed(2)}ms ` +
|
|
241
|
+
`threshold=${autoThreshold}ms → ${resolved}\n`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (reserveCores > 0) {
|
|
245
|
+
const hw = availableParallelism();
|
|
246
|
+
const tfCores = Math.max(1, hw - reserveCores);
|
|
247
|
+
process.stderr.write(`[isidorus] CPU affinity: reserving ${reserveCores} core(s), ` +
|
|
248
|
+
`TF gets ${tfCores} core(s)\n`);
|
|
249
|
+
}
|
|
250
|
+
return resolved === "worker-pool"
|
|
251
|
+
? InferencePool.createWorkerPool(opts, concurrency, reserveCores)
|
|
252
|
+
: InferencePool.createTfParallel(opts, reserveCores);
|
|
253
|
+
}
|
|
254
|
+
// ── worker-pool init ───────────────────────────────────────────────────────
|
|
255
|
+
static async createWorkerPool(opts, concurrency, reserveCores) {
|
|
256
|
+
const ctrlSab = new SharedArrayBuffer(concurrency * CTRL_SLOTS * 4);
|
|
257
|
+
const slots = [];
|
|
258
|
+
const startedWorkers = [];
|
|
259
|
+
// In dev/test we run TypeScript source directly via tsx. Workers don't
|
|
260
|
+
// inherit --import tsx from the parent, so we use a small .mjs bootstrap
|
|
261
|
+
// (inference-pool-worker.mjs) that calls register() from tsx/esm/api
|
|
262
|
+
// before importing this .ts file. In production the compiled .js entry
|
|
263
|
+
// is used directly with no extra loader needed.
|
|
264
|
+
const isTsSource = import.meta.url.endsWith(".ts");
|
|
265
|
+
const workerEntry = isTsSource
|
|
266
|
+
? new URL("./inference-pool-worker.mjs", import.meta.url)
|
|
267
|
+
: new URL("./inference-pool.js", import.meta.url);
|
|
268
|
+
try {
|
|
269
|
+
for (let i = 0; i < concurrency; i++) {
|
|
270
|
+
const ctrl = new Int32Array(ctrlSab, i * CTRL_SLOTS * 4, CTRL_SLOTS);
|
|
271
|
+
Atomics.store(ctrl, 0, IDLE);
|
|
272
|
+
const worker = new Worker(workerEntry, {
|
|
273
|
+
workerData: {
|
|
274
|
+
ctrlSab,
|
|
275
|
+
workerIndex: i,
|
|
276
|
+
modelPath: opts.modelPath,
|
|
277
|
+
inputOp: opts.inputOp,
|
|
278
|
+
outputOps: opts.outputOps,
|
|
279
|
+
reserveCores,
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
startedWorkers.push(worker);
|
|
283
|
+
await new Promise((resolve, reject) => {
|
|
284
|
+
worker.once("message", (msg) => {
|
|
285
|
+
if (msg.type === "ready")
|
|
286
|
+
resolve();
|
|
287
|
+
else if (msg.type === "init_error")
|
|
288
|
+
reject(new Error(`Worker ${i} init failed: ${msg.error}`));
|
|
289
|
+
else
|
|
290
|
+
reject(new Error(`Worker ${i} unexpected init message: ${msg.type}`));
|
|
291
|
+
});
|
|
292
|
+
worker.once("error", reject);
|
|
293
|
+
});
|
|
294
|
+
slots.push({ worker, ctrl, busy: false, resolve: null, reject: null });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
// Terminate any workers that were already started before the failure.
|
|
299
|
+
await Promise.allSettled(startedWorkers.map((w) => w.terminate()));
|
|
300
|
+
throw err;
|
|
301
|
+
}
|
|
302
|
+
return new InferencePool({
|
|
303
|
+
strategy: "worker-pool",
|
|
304
|
+
reserveCores,
|
|
305
|
+
workerSlots: slots,
|
|
306
|
+
queue: [],
|
|
307
|
+
ctrlSab,
|
|
308
|
+
tfParallelGraph: null,
|
|
309
|
+
tfParallelSess: null,
|
|
310
|
+
modelPath: opts.modelPath,
|
|
311
|
+
inputOp: opts.inputOp,
|
|
312
|
+
outputOps: opts.outputOps,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
// ── tf-parallel init ───────────────────────────────────────────────────────
|
|
316
|
+
static async createTfParallel(opts, reserveCores) {
|
|
317
|
+
const hw = availableParallelism();
|
|
318
|
+
const tfCores = Math.max(1, hw - reserveCores);
|
|
319
|
+
// Try the native @isidorus/cpu Session path first (ConfigProto thread
|
|
320
|
+
// config + OnRunWork affinity fence). Falls back to jude-tf if the addon
|
|
321
|
+
// hasn't been initialised (e.g. when called from outside @isidorus/cpu).
|
|
322
|
+
//
|
|
323
|
+
// We import _native.js rather than "@isidorus/cpu" to avoid a circular
|
|
324
|
+
// dependency — this file IS part of @isidorus/cpu, so importing the
|
|
325
|
+
// package entry point would re-run ensureTf() + node-gyp-build.
|
|
326
|
+
let tfParallelGraph = null;
|
|
327
|
+
let tfParallelSess = null;
|
|
328
|
+
try {
|
|
329
|
+
const { getAddon } = await import("./_native.js");
|
|
330
|
+
const { readFileSync } = await import("fs");
|
|
331
|
+
const { Graph: GraphClass } = await import("./graph.js");
|
|
332
|
+
const { Session: SessionClass } = await import("./session.js");
|
|
333
|
+
const addon = getAddon();
|
|
334
|
+
const g = new GraphClass(new addon.Graph());
|
|
335
|
+
g.importGraphDef(readFileSync(opts.modelPath));
|
|
336
|
+
tfParallelGraph = g;
|
|
337
|
+
tfParallelSess = new SessionClass(new addon.Session(g._native, {
|
|
338
|
+
strategy: "tf-parallel",
|
|
339
|
+
reserveCores,
|
|
340
|
+
}));
|
|
341
|
+
process.stderr.write(`[isidorus] tf-parallel: intra_op=${tfCores} ` +
|
|
342
|
+
`(${reserveCores} core(s) reserved, native Session)\n`);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
// Native addon not available — fall back to jude-tf TFSession.
|
|
346
|
+
// This path lacks the affinity fence but is otherwise correct.
|
|
347
|
+
const { TFSession } = await import("jude-tf");
|
|
348
|
+
tfParallelSess = await TFSession.loadFrozenGraph(opts.modelPath);
|
|
349
|
+
process.stderr.write(`[isidorus] tf-parallel: intra_op=${tfCores} ` +
|
|
350
|
+
`(${reserveCores} core(s) reserved, jude-tf fallback)\n`);
|
|
351
|
+
}
|
|
352
|
+
return new InferencePool({
|
|
353
|
+
strategy: "tf-parallel",
|
|
354
|
+
reserveCores,
|
|
355
|
+
workerSlots: [],
|
|
356
|
+
queue: [],
|
|
357
|
+
ctrlSab: null,
|
|
358
|
+
tfParallelGraph,
|
|
359
|
+
tfParallelSess,
|
|
360
|
+
modelPath: opts.modelPath,
|
|
361
|
+
inputOp: opts.inputOp,
|
|
362
|
+
outputOps: opts.outputOps,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
// ── Inference ──────────────────────────────────────────────────────────────
|
|
366
|
+
infer(inputBuf, inputShape, inputDtype = 1) {
|
|
367
|
+
return this.strategy === "worker-pool"
|
|
368
|
+
? this.inferWorkerPool(inputBuf, inputShape, inputDtype)
|
|
369
|
+
: this.inferTfParallel(inputBuf, inputShape, inputDtype);
|
|
370
|
+
}
|
|
371
|
+
inferWorkerPool(inputBuf, inputShape, inputDtype) {
|
|
372
|
+
return new Promise((resolve, reject) => {
|
|
373
|
+
const slot = this.workerSlots.find((w) => !w.busy);
|
|
374
|
+
if (slot) {
|
|
375
|
+
this.dispatchToWorker(slot, inputBuf, inputShape, inputDtype, resolve, reject);
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
this.queue.push({ inputBuf, inputShape, inputDtype, resolve, reject });
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
dispatchToWorker(slot, inputBuf, inputShape, inputDtype, resolve, reject) {
|
|
383
|
+
const workerId = this.workerSlots.indexOf(slot);
|
|
384
|
+
slot.busy = true;
|
|
385
|
+
slot.resolve = resolve;
|
|
386
|
+
slot.reject = reject;
|
|
387
|
+
// ── ORDERING CRITICAL ──────────────────────────────────────────────────
|
|
388
|
+
// 1. Register the result listener FIRST — before the worker can possibly
|
|
389
|
+
// send a response. Node.js buffers port messages until a listener is
|
|
390
|
+
// registered, but registering after notify introduces a thread-level
|
|
391
|
+
// race where an extremely fast result could be missed.
|
|
392
|
+
// 2. Post the input data SECOND — the worker awaits this message after
|
|
393
|
+
// waking from Atomics.wait, so it must arrive before WORK is stored.
|
|
394
|
+
// 3. Store WORK + notify LAST — wakes the worker.
|
|
395
|
+
const handleMessage = (msg) => {
|
|
396
|
+
if (msg.type === "work_error") {
|
|
397
|
+
this.settleSlot(slot, null, new Error(msg.error));
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (msg.type !== "result") {
|
|
401
|
+
// Unexpected message type — re-register to wait for the actual result.
|
|
402
|
+
slot.worker.once("message", handleMessage);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
this.settleSlot(slot, {
|
|
406
|
+
workerId,
|
|
407
|
+
strategy: "worker-pool",
|
|
408
|
+
outputs: msg.outputs.map((o) => ({
|
|
409
|
+
dtype: o.dtype,
|
|
410
|
+
shape: o.shape,
|
|
411
|
+
// postMessage structured-clones Buffer as plain Uint8Array —
|
|
412
|
+
// wrap it back into a Buffer so callers can use Buffer.isBuffer().
|
|
413
|
+
data: Buffer.isBuffer(o.data) ? o.data : Buffer.from(o.data),
|
|
414
|
+
})),
|
|
415
|
+
inferenceMs: msg.inferenceMs,
|
|
416
|
+
}, null);
|
|
417
|
+
};
|
|
418
|
+
// Register listener before waking the worker.
|
|
419
|
+
slot.worker.once("message", handleMessage);
|
|
420
|
+
// Register a one-shot error listener so an uncaught worker crash rejects
|
|
421
|
+
// the promise instead of leaving it hanging.
|
|
422
|
+
slot.worker.once("error", (err) => {
|
|
423
|
+
this.settleSlot(slot, null, err);
|
|
424
|
+
});
|
|
425
|
+
// Post input, then wake worker.
|
|
426
|
+
slot.worker.postMessage({ inputData: inputBuf, inputShape, inputDtype });
|
|
427
|
+
Atomics.store(slot.ctrl, 0, WORK);
|
|
428
|
+
Atomics.notify(slot.ctrl, 0, 1);
|
|
429
|
+
}
|
|
430
|
+
/** Settle a worker slot's in-flight promise and drain the queue. */
|
|
431
|
+
settleSlot(slot, result, err) {
|
|
432
|
+
const resolve = slot.resolve;
|
|
433
|
+
const reject = slot.reject;
|
|
434
|
+
slot.busy = false;
|
|
435
|
+
slot.resolve = null;
|
|
436
|
+
slot.reject = null;
|
|
437
|
+
if (err)
|
|
438
|
+
reject?.(err);
|
|
439
|
+
else
|
|
440
|
+
resolve?.(result);
|
|
441
|
+
// Drain one queued request now that the slot is free.
|
|
442
|
+
const next = this.queue.shift();
|
|
443
|
+
if (next) {
|
|
444
|
+
this.dispatchToWorker(slot, next.inputBuf, next.inputShape, next.inputDtype, next.resolve, next.reject);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// ── tf-parallel path ───────────────────────────────────────────────────────
|
|
448
|
+
inferTfParallel(inputBuf, inputShape, inputDtype) {
|
|
449
|
+
return new Promise((resolve, reject) => {
|
|
450
|
+
if (this.tfParallelBusy) {
|
|
451
|
+
this.tfParallelQueue.push({
|
|
452
|
+
inputBuf,
|
|
453
|
+
inputShape,
|
|
454
|
+
inputDtype,
|
|
455
|
+
resolve,
|
|
456
|
+
reject,
|
|
457
|
+
});
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
this.runTfParallel(inputBuf, inputShape, inputDtype, resolve, reject);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
runTfParallel(inputBuf, inputShape, inputDtype, resolve, reject) {
|
|
464
|
+
this.tfParallelBusy = true;
|
|
465
|
+
const t0 = performance.now();
|
|
466
|
+
let inferencePromise;
|
|
467
|
+
if (this.tfParallelGraph) {
|
|
468
|
+
// ── Native @isidorus/cpu Session path ──────────────────────────────
|
|
469
|
+
// Build feed/fetch arrays using Graph.getOp() to resolve op names to
|
|
470
|
+
// Tensor references, which Session.runAsync expects.
|
|
471
|
+
const g = this.tfParallelGraph;
|
|
472
|
+
const inputTensor = g.getOp(this.inputOp);
|
|
473
|
+
if (!inputTensor) {
|
|
474
|
+
this.tfParallelBusy = false;
|
|
475
|
+
reject(new Error(`tf-parallel: input op not found in graph: ${this.inputOp}`));
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const outputTensors = this.outputOps.map((name) => {
|
|
479
|
+
const t = g.getOp(name);
|
|
480
|
+
if (!t)
|
|
481
|
+
throw new Error(`tf-parallel: output op not found in graph: ${name}`);
|
|
482
|
+
return t;
|
|
483
|
+
});
|
|
484
|
+
// Reinterpret the raw Buffer bytes as the correct TypedArray dtype.
|
|
485
|
+
// asTypedArray is only defined inside the !isMainThread block, so we
|
|
486
|
+
// inline the same logic here for the main-thread tf-parallel path.
|
|
487
|
+
const ab = inputBuf.buffer.slice(inputBuf.byteOffset, inputBuf.byteOffset + inputBuf.byteLength);
|
|
488
|
+
let typedInput;
|
|
489
|
+
switch (inputDtype) {
|
|
490
|
+
case 1:
|
|
491
|
+
typedInput = new Float32Array(ab);
|
|
492
|
+
break;
|
|
493
|
+
case 2:
|
|
494
|
+
typedInput = new Float64Array(ab);
|
|
495
|
+
break;
|
|
496
|
+
case 3:
|
|
497
|
+
typedInput = new Int32Array(ab);
|
|
498
|
+
break;
|
|
499
|
+
case 4:
|
|
500
|
+
typedInput = new Uint8Array(ab);
|
|
501
|
+
break;
|
|
502
|
+
case 9:
|
|
503
|
+
typedInput = new BigInt64Array(ab);
|
|
504
|
+
break;
|
|
505
|
+
default:
|
|
506
|
+
typedInput = new Uint8Array(ab);
|
|
507
|
+
}
|
|
508
|
+
const feedValue = {
|
|
509
|
+
dtype: inputDtype,
|
|
510
|
+
shape: inputShape,
|
|
511
|
+
data: Buffer.from(typedInput.buffer, typedInput.byteOffset, typedInput.byteLength),
|
|
512
|
+
};
|
|
513
|
+
inferencePromise = this.tfParallelSess.runAsync([[inputTensor, feedValue]], outputTensors).then((outputs) => {
|
|
514
|
+
// Map back to { [outputKey]: TensorResult } for uniform handling below
|
|
515
|
+
const result = {};
|
|
516
|
+
this.outputOps.forEach((key, i) => {
|
|
517
|
+
result[key] = outputs[i];
|
|
518
|
+
});
|
|
519
|
+
return result;
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
// ── jude-tf TFSession fallback path ───────────────────────────────
|
|
524
|
+
inferencePromise = this.tfParallelSess.runAsync({ [this.inputOp]: inputBuf }, this.outputOps);
|
|
525
|
+
}
|
|
526
|
+
inferencePromise
|
|
527
|
+
.then((results) => {
|
|
528
|
+
const inferenceMs = performance.now() - t0;
|
|
529
|
+
this.tfParallelBusy = false;
|
|
530
|
+
resolve({
|
|
531
|
+
workerId: 0,
|
|
532
|
+
strategy: "tf-parallel",
|
|
533
|
+
outputs: this.outputOps.map((k) => {
|
|
534
|
+
const r = results[k];
|
|
535
|
+
if (!r)
|
|
536
|
+
return { dtype: 0, shape: [], data: Buffer.alloc(0) };
|
|
537
|
+
const view = r.data;
|
|
538
|
+
return {
|
|
539
|
+
dtype: r.dtype,
|
|
540
|
+
shape: r.shape,
|
|
541
|
+
data: Buffer.isBuffer(r.data)
|
|
542
|
+
? r.data
|
|
543
|
+
: Buffer.from(view.buffer, view.byteOffset, view.byteLength),
|
|
544
|
+
};
|
|
545
|
+
}),
|
|
546
|
+
inferenceMs,
|
|
547
|
+
});
|
|
548
|
+
const next = this.tfParallelQueue.shift();
|
|
549
|
+
if (next) {
|
|
550
|
+
this.runTfParallel(next.inputBuf, next.inputShape, next.inputDtype, next.resolve, next.reject);
|
|
551
|
+
}
|
|
552
|
+
})
|
|
553
|
+
.catch((err) => {
|
|
554
|
+
this.tfParallelBusy = false;
|
|
555
|
+
reject(err);
|
|
556
|
+
const next = this.tfParallelQueue.shift();
|
|
557
|
+
if (next) {
|
|
558
|
+
this.runTfParallel(next.inputBuf, next.inputShape, next.inputDtype, next.resolve, next.reject);
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
// ── Introspection ──────────────────────────────────────────────────────────
|
|
563
|
+
get busyCount() {
|
|
564
|
+
if (this.strategy === "worker-pool")
|
|
565
|
+
return this.workerSlots.filter((w) => w.busy).length;
|
|
566
|
+
return this.tfParallelBusy ? 1 : 0;
|
|
567
|
+
}
|
|
568
|
+
get queueDepth() {
|
|
569
|
+
return this.strategy === "worker-pool"
|
|
570
|
+
? this.queue.length
|
|
571
|
+
: this.tfParallelQueue.length;
|
|
572
|
+
}
|
|
573
|
+
get size() {
|
|
574
|
+
return this.strategy === "worker-pool" ? this.workerSlots.length : 1;
|
|
575
|
+
}
|
|
576
|
+
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
577
|
+
async destroy() {
|
|
578
|
+
if (this.strategy === "worker-pool") {
|
|
579
|
+
await Promise.all(this.workerSlots.map((slot) => new Promise((resolve, reject) => {
|
|
580
|
+
const doShutdown = () => {
|
|
581
|
+
// Register shutdown_ack listener before storing SHUTDOWN.
|
|
582
|
+
slot.worker.once("message", (msg) => {
|
|
583
|
+
if (msg.type === "shutdown_ack")
|
|
584
|
+
resolve();
|
|
585
|
+
});
|
|
586
|
+
slot.worker.once("error", reject);
|
|
587
|
+
Atomics.store(slot.ctrl, 0, SHUTDOWN);
|
|
588
|
+
Atomics.notify(slot.ctrl, 0, 1);
|
|
589
|
+
};
|
|
590
|
+
if (slot.busy) {
|
|
591
|
+
// Wait for the current in-flight request to finish first.
|
|
592
|
+
const origResolve = slot.resolve;
|
|
593
|
+
const origReject = slot.reject;
|
|
594
|
+
slot.resolve = (r) => {
|
|
595
|
+
origResolve?.(r);
|
|
596
|
+
doShutdown();
|
|
597
|
+
};
|
|
598
|
+
slot.reject = (e) => {
|
|
599
|
+
origReject?.(e);
|
|
600
|
+
doShutdown();
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
doShutdown();
|
|
605
|
+
}
|
|
606
|
+
})));
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
if (this.tfParallelBusy) {
|
|
610
|
+
await new Promise((res) => {
|
|
611
|
+
const t = setInterval(() => {
|
|
612
|
+
if (!this.tfParallelBusy) {
|
|
613
|
+
clearInterval(t);
|
|
614
|
+
res();
|
|
615
|
+
}
|
|
616
|
+
}, 1);
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
this.tfParallelSess?.destroy();
|
|
620
|
+
this.tfParallelSess = null;
|
|
621
|
+
this.tfParallelGraph = null;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
//# sourceMappingURL=inference-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inference-pool.js","sourceRoot":"","sources":["../../src/ts/inference-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAIzC,+EAA+E;AAC/E,MAAM,IAAI,GAAG,CAAC,CAAC;AACf,MAAM,IAAI,GAAG,CAAC,CAAC;AACf,MAAM,IAAI,GAAG,CAAC,CAAC;AACf,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,4CAA4C;AAElE,MAAM,oBAAoB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,SAAS;AACzD,MAAM,sBAAsB,GAAG,EAAE,CAAC,CAAC,KAAK;AAgCxC,+EAA+E;AAC/E,EAAE;AACF,mEAAmE;AACnE,4EAA4E;AAC5E,0DAA0D;AAC1D,EAAE;AACF,qEAAqE;AACrE,mDAAmD;AACnD,0DAA0D;AAC1D,uEAAuE;AACvE,oDAAoD;AACpD,EAAE;AACF,+DAA+D;AAC/D,oFAAoF;AACpF,sCAAsC;AACtC,oFAAoF;AACpF,0DAA0D;AAC1D,6CAA6C;AAC7C,EAAE;AACF,sBAAsB;AACtB,kEAAkE;AAClE,oEAAoE;AACpE,kEAAkE;AAClE,2EAA2E;AAE3E,IAAI,CAAC,YAAY,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,GAC3D,UAOC,CAAC;IAEJ,MAAM,IAAI,GAAG,IAAI,UAAU,CACzB,OAAO,EACP,WAAW,GAAG,UAAU,GAAG,CAAC,EAC5B,UAAU,CACX,CAAC;IAEF,6EAA6E;IAC7E,IAAI,IAAS,CAAC;IACd,IAAI,CAAC;QACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,GAAG,MAAM,SAAS,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,UAAW,CAAC,WAAW,CAAC;YACtB,IAAI,EAAE,YAAY;YAClB,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC;SACjC,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAC7B,UAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAE3C,gEAAgE;IAChE,0EAA0E;IAC1E,0EAA0E;IAC1E,6DAA6D;IAC7D,SAAS,YAAY,CAAC,GAAW,EAAE,KAAa;QAC9C,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CACzB,GAAG,CAAC,UAAU,EACd,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU,CAChC,CAAC;QACF,QAAQ,KAAK,EAAE,CAAC;YACd,KAAK,CAAC;gBACJ,OAAO,IAAI,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW;YAC1C,KAAK,CAAC;gBACJ,OAAO,IAAI,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY;YAC3C,KAAK,CAAC;gBACJ,OAAO,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW;YACxC,KAAK,CAAC;gBACJ,OAAO,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW;YACxC,KAAK,CAAC;gBACJ,OAAO,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW;YAC3C;gBACE,OAAO,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,iEAAiE;IACjE,OAAO,IAAI,EAAE,CAAC;QACZ,wDAAwD;QACxD,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAEpC,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,UAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;YAClD,MAAM;QACR,CAAC;QAED,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,0DAA0D;YAC1D,yDAAyD;YACzD,MAAM,GAAG,GAAQ,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAC7C,UAAW,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CACrC,CAAC;YAEF,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;gBAC7B,MAAM,UAAU,GAAG,YAAY,CAC7B,GAAG,CAAC,SAAmB,EACvB,GAAG,CAAC,UAAoB,CACzB,CAAC;gBAEF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,SAAS,CAAC,CAAC;gBAErE,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;gBAE3C,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBAC7B,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBAE3B,UAAW,CAAC,WAAW,CAAC;oBACtB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;wBAC3B,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;wBACrB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAuB,CAAC;wBACvC,OAAO;4BACL,KAAK,EAAE,CAAC,CAAC,KAAK;4BACd,KAAK,EAAE,CAAC,CAAC,KAAK;4BACd,+DAA+D;4BAC/D,iEAAiE;4BACjE,kCAAkC;4BAClC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC;yBACjE,CAAC;oBACJ,CAAC,CAAC;oBACF,WAAW;iBACZ,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CACX,WAAW,WAAW,UAAU,EAChC,GAAG,EAAE,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,CAC1B,CAAC;gBACF,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBAC7B,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC3B,UAAW,CAAC,WAAW,CAAC;oBACtB,IAAI,EAAE,YAAY;oBAClB,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC;iBACjC,CAAC,CAAC;YACL,CAAC;YAED,kEAAkE;YAClE,gEAAgE;YAChE,qEAAqE;YACrE,yCAAyC;YACzC,OAAO,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;AACH,CAAC;AAoBD,MAAM,OAAO,aAAa;IACf,QAAQ,CAAgC;IACxC,YAAY,CAAS;IAEb,WAAW,CAAe;IAC1B,KAAK,CAAe;IACpB,OAAO,CAA2B;IAEnD,6DAA6D;IAC7D,qEAAqE;IACrE,0EAA0E;IAC1E,mEAAmE;IACnE,yEAAyE;IACjE,eAAe,CAAe;IAC9B,cAAc,CAAuB;IACrC,cAAc,CAAU;IACf,eAAe,CAAe;IAE9B,SAAS,CAAS;IAClB,OAAO,CAAS;IAChB,SAAS,CAAW;IAErC,YAAoB,MAWnB;QACC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAChC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QACxC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC;QAC9C,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACpC,CAAC;IAED,8EAA8E;IAE9E,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAiB;QACnC,uDAAuD;QACvD,sEAAsE;QACtE,4DAA4D;QAC5D,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;YAC7C,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YAC9C,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9D,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACjC,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,OAAO,CAAC;YACjC,KAAK,CAAC,OAAO,EAAE,CAAC;YAChB,IAAI,CAAC,IAAI,CAAC,OAAO;gBACf,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM;gBACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC;QAClD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,oBAAoB,EAAE,CAAC;QAC/D,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,IAAI,sBAAsB,CAAC;QACrE,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC;QAE5C,IAAI,QAAuC,CAAC;QAE5C,IAAI,iBAAiB,KAAK,aAAa,EAAE,CAAC;YACxC,QAAQ,GAAG,aAAa,CAAC;QAC3B,CAAC;aAAM,IAAI,iBAAiB,KAAK,aAAa,EAAE,CAAC;YAC/C,QAAQ,GAAG,aAAa,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,6DAA6D;YAC7D,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;YAEjD,IAAI,UAAU,GAAG,oBAAoB,EAAE,CAAC;gBACtC,QAAQ,GAAG,aAAa,CAAC;YAC3B,CAAC;iBAAM,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC5B,QAAQ,GAAG,aAAa,CAAC;gBACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,oBAAoB,CAAC,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;oBAC/D,0CAA0C,CAC7C,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,+DAA+D;gBAC/D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC9C,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAClE,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAC7B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAC/C,CAAC;gBAEF,MAAM,SAAS,CAAC,QAAQ,CACtB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAC9B,IAAI,CAAC,SAAS,CACf,CAAC;gBACF,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;gBAC7B,MAAM,SAAS,CAAC,QAAQ,CACtB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAC9B,IAAI,CAAC,SAAS,CACf,CAAC;gBACF,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;gBACvC,SAAS,CAAC,OAAO,EAAE,CAAC;gBAEpB,QAAQ,GAAG,OAAO,IAAI,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC;gBACpE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0BAA0B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;oBAC/C,aAAa,aAAa,QAAQ,QAAQ,IAAI,CACjD,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,EAAE,GAAG,oBAAoB,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC;YAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,sCAAsC,YAAY,YAAY;gBAC5D,WAAW,OAAO,YAAY,CACjC,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,KAAK,aAAa;YAC/B,CAAC,CAAC,aAAa,CAAC,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,CAAC;YACjE,CAAC,CAAC,aAAa,CAAC,gBAAgB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACzD,CAAC;IAED,8EAA8E;IAEtE,MAAM,CAAC,KAAK,CAAC,gBAAgB,CACnC,IAAiB,EACjB,WAAmB,EACnB,YAAoB;QAEpB,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,WAAW,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC;QACpE,MAAM,KAAK,GAAiB,EAAE,CAAC;QAC/B,MAAM,cAAc,GAAa,EAAE,CAAC;QAEpC,uEAAuE;QACvE,yEAAyE;QACzE,qEAAqE;QACrE,uEAAuE;QACvE,gDAAgD;QAChD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,UAAU;YAC5B,CAAC,CAAC,IAAI,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;YACzD,CAAC,CAAC,IAAI,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEpD,IAAI,CAAC;YACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;gBACrE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBAE7B,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE;oBACrC,UAAU,EAAE;wBACV,OAAO;wBACP,WAAW,EAAE,CAAC;wBACd,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,OAAO,EAAE,IAAI,CAAC,OAAO;wBACrB,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,YAAY;qBACb;iBACF,CAAC,CAAC;gBACH,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAE5B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBAC1C,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAQ,EAAE,EAAE;wBAClC,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO;4BAAE,OAAO,EAAE,CAAC;6BAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY;4BAChC,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,iBAAiB,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;;4BAE3D,MAAM,CACJ,IAAI,KAAK,CAAC,UAAU,CAAC,6BAA6B,GAAG,CAAC,IAAI,EAAE,CAAC,CAC9D,CAAC;oBACN,CAAC,CAAC,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAC/B,CAAC,CAAC,CAAC;gBAEH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,sEAAsE;YACtE,MAAM,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACnE,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,OAAO,IAAI,aAAa,CAAC;YACvB,QAAQ,EAAE,aAAa;YACvB,YAAY;YACZ,WAAW,EAAE,KAAK;YAClB,KAAK,EAAE,EAAE;YACT,OAAO;YACP,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,IAAI;YACpB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,IAAI,CAAC,OAAQ;YACtB,SAAS,EAAE,IAAI,CAAC,SAAU;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,8EAA8E;IAEtE,MAAM,CAAC,KAAK,CAAC,gBAAgB,CACnC,IAAiB,EACjB,YAAoB;QAEpB,MAAM,EAAE,GAAG,oBAAoB,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC;QAE/C,sEAAsE;QACtE,yEAAyE;QACzE,yEAAyE;QACzE,EAAE;QACF,uEAAuE;QACvE,oEAAoE;QACpE,gEAAgE;QAChE,IAAI,eAAe,GAAiB,IAAI,CAAC;QACzC,IAAI,cAAc,GAAyB,IAAI,CAAC;QAEhD,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;YAClD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;YACzD,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;YAC/D,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;YAEzB,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAC5C,CAAC,CAAC,cAAc,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YAE/C,eAAe,GAAG,CAAC,CAAC;YACpB,cAAc,GAAG,IAAI,YAAY,CAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE;gBAC3B,QAAQ,EAAE,aAAa;gBACvB,YAAY;aACb,CAAC,CACH,CAAC;YAEF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,oCAAoC,OAAO,GAAG;gBAC5C,IAAI,YAAY,sCAAsC,CACzD,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,+DAA+D;YAC/D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YAC9C,cAAc,GAAG,MAAM,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAEjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,oCAAoC,OAAO,GAAG;gBAC5C,IAAI,YAAY,wCAAwC,CAC3D,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,aAAa,CAAC;YACvB,QAAQ,EAAE,aAAa;YACvB,YAAY;YACZ,WAAW,EAAE,EAAE;YACf,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,IAAI;YACb,eAAe;YACf,cAAc;YACd,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,IAAI,CAAC,OAAQ;YACtB,SAAS,EAAE,IAAI,CAAC,SAAU;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,8EAA8E;IAE9E,KAAK,CACH,QAAgB,EAChB,UAAoB,EACpB,UAAU,GAAG,CAAC;QAEd,OAAO,IAAI,CAAC,QAAQ,KAAK,aAAa;YACpC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC;YACxD,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC7D,CAAC;IAEO,eAAe,CACrB,QAAgB,EAChB,UAAoB,EACpB,UAAkB;QAElB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACnD,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,gBAAgB,CACnB,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,UAAU,EACV,OAAO,EACP,MAAM,CACP,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YACzE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB,CACtB,IAAgB,EAChB,QAAgB,EAChB,UAAoB,EACpB,UAAkB,EAClB,OAAgC,EAChC,MAA0B;QAE1B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,0EAA0E;QAC1E,yEAAyE;QACzE,wEAAwE;QACxE,wEAAwE;QACxE,0DAA0D;QAC1D,uEAAuE;QACvE,wEAAwE;QACxE,kDAAkD;QAClD,MAAM,aAAa,GAAG,CAAC,GAAQ,EAAE,EAAE;YACjC,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;gBAClD,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,uEAAuE;gBACvE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YACD,IAAI,CAAC,UAAU,CACb,IAAI,EACJ;gBACE,QAAQ;gBACR,QAAQ,EAAE,aAAa;gBACvB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;oBACpC,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,6DAA6D;oBAC7D,mEAAmE;oBACnE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;iBAC7D,CAAC,CAAC;gBACH,WAAW,EAAE,GAAG,CAAC,WAAW;aAC7B,EACD,IAAI,CACL,CAAC;QACJ,CAAC,CAAC;QAEF,8CAA8C;QAC9C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAE3C,yEAAyE;QACzE,6CAA6C;QAC7C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;YACvC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,gCAAgC;QAChC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;QACzE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QAClC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,oEAAoE;IAC5D,UAAU,CAChB,IAAgB,EAChB,MAAyB,EACzB,GAAiB;QAEjB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QAEnB,IAAI,GAAG;YAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;;YAClB,OAAO,EAAE,CAAC,MAAO,CAAC,CAAC;QAExB,sDAAsD;QACtD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,gBAAgB,CACnB,IAAI,EACJ,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,MAAM,CACZ,CAAC;QACJ,CAAC;IACH,CAAC;IAED,8EAA8E;IAEtE,eAAe,CACrB,QAAgB,EAChB,UAAoB,EACpB,UAAkB;QAElB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;oBACxB,QAAQ;oBACR,UAAU;oBACV,UAAU;oBACV,OAAO;oBACP,MAAM;iBACP,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,aAAa,CACnB,QAAgB,EAChB,UAAoB,EACpB,UAAkB,EAClB,OAAgC,EAChC,MAA0B;QAE1B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,gBAA8B,CAAC;QAEnC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,sEAAsE;YACtE,qEAAqE;YACrE,qDAAqD;YACrD,MAAM,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC;YAC/B,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;gBAC5B,MAAM,CACJ,IAAI,KAAK,CACP,6CAA6C,IAAI,CAAC,OAAO,EAAE,CAC5D,CACF,CAAC;gBACF,OAAO;YACT,CAAC;YAED,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBAChD,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACxB,IAAI,CAAC,CAAC;oBACJ,MAAM,IAAI,KAAK,CAAC,8CAA8C,IAAI,EAAE,CAAC,CAAC;gBACxE,OAAO,CAAC,CAAC;YACX,CAAC,CAAC,CAAC;YAEH,oEAAoE;YACpE,qEAAqE;YACrE,mEAAmE;YACnE,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAC9B,QAAQ,CAAC,UAAU,EACnB,QAAQ,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAC1C,CAAC;YACF,IAAI,UAA2B,CAAC;YAChC,QAAQ,UAAU,EAAE,CAAC;gBACnB,KAAK,CAAC;oBACJ,UAAU,GAAG,IAAI,YAAY,CAAC,EAAE,CAAC,CAAC;oBAClC,MAAM;gBACR,KAAK,CAAC;oBACJ,UAAU,GAAG,IAAI,YAAY,CAAC,EAAE,CAAC,CAAC;oBAClC,MAAM;gBACR,KAAK,CAAC;oBACJ,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;oBAChC,MAAM;gBACR,KAAK,CAAC;oBACJ,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;oBAChC,MAAM;gBACR,KAAK,CAAC;oBACJ,UAAU,GAAG,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC;oBACnC,MAAM;gBACR;oBACE,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;YACpC,CAAC;YAED,MAAM,SAAS,GAAG;gBAChB,KAAK,EAAE,UAAU;gBACjB,KAAK,EAAE,UAAU;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI,CACf,UAAU,CAAC,MAAM,EACjB,UAAU,CAAC,UAAU,EACrB,UAAU,CAAC,UAAU,CACtB;aACF,CAAC;YAEF,gBAAgB,GAAG,IAAI,CAAC,cAAe,CAAC,QAAQ,CAC9C,CAAC,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,EAC1B,aAAa,CACd,CAAC,IAAI,CAAC,CAAC,OAAc,EAAE,EAAE;gBACxB,uEAAuE;gBACvE,MAAM,MAAM,GAAwB,EAAE,CAAC;gBACvC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;oBAChC,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC3B,CAAC,CAAC,CAAC;gBACH,OAAO,MAAM,CAAC;YAChB,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,qEAAqE;YACrE,gBAAgB,GAAG,IAAI,CAAC,cAAe,CAAC,QAAQ,CAC9C,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,EAC5B,IAAI,CAAC,SAAS,CACf,CAAC;QACJ,CAAC;QAED,gBAAgB;aACb,IAAI,CAAC,CAAC,OAAY,EAAE,EAAE;YACrB,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;YAC3C,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;YAC5B,OAAO,CAAC;gBACN,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,aAAa;gBACvB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE;oBACxC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;oBACrB,IAAI,CAAC,CAAC;wBAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC9D,MAAM,IAAI,GAAG,CAAC,CAAC,IAAuB,CAAC;oBACvC,OAAO;wBACL,KAAK,EAAE,CAAC,CAAC,KAAK;wBACd,KAAK,EAAE,CAAC,CAAC,KAAK;wBACd,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;4BAC3B,CAAC,CAAC,CAAC,CAAC,IAAI;4BACR,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC;qBAC/D,CAAC;gBACJ,CAAC,CAAC;gBACF,WAAW;aACZ,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YAC1C,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,aAAa,CAChB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,MAAM,CACZ,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;YACpB,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;YAC5B,MAAM,CAAC,GAAG,CAAC,CAAC;YACZ,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YAC1C,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,aAAa,CAChB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,MAAM,CACZ,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACP,CAAC;IAED,8EAA8E;IAE9E,IAAI,SAAS;QACX,IAAI,IAAI,CAAC,QAAQ,KAAK,aAAa;YACjC,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QACvD,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,KAAK,aAAa;YACpC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;YACnB,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;IAClC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YACpC,MAAM,OAAO,CAAC,GAAG,CACf,IAAI,CAAC,WAAW,CAAC,GAAG,CAClB,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACpC,MAAM,UAAU,GAAG,GAAG,EAAE;oBACtB,0DAA0D;oBAC1D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAQ,EAAE,EAAE;wBACvC,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc;4BAAE,OAAO,EAAE,CAAC;oBAC7C,CAAC,CAAC,CAAC;oBACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBAClC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;oBACtC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBAClC,CAAC,CAAC;gBAEF,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,0DAA0D;oBAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC;oBACjC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;oBAC/B,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,EAAE;wBACnB,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;wBACjB,UAAU,EAAE,CAAC;oBACf,CAAC,CAAC;oBACF,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE;wBAClB,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;wBAChB,UAAU,EAAE,CAAC;oBACf,CAAC,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,UAAU,EAAE,CAAC;gBACf,CAAC;YACH,CAAC,CAAC,CACL,CACF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxB,MAAM,IAAI,OAAO,CAAO,CAAC,GAAG,EAAE,EAAE;oBAC9B,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE;wBACzB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;4BACzB,aAAa,CAAC,CAAC,CAAC,CAAC;4BACjB,GAAG,EAAE,CAAC;wBACR,CAAC;oBACH,CAAC,EAAE,CAAC,CAAC,CAAC;gBACR,CAAC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,CAAC;YAC/B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC3B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC;CACF"}
|