@jongodb/memory-server 0.1.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.
package/dist/index.js ADDED
@@ -0,0 +1,539 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import { delimiter, dirname, resolve } from "node:path";
5
+ import { createInterface } from "node:readline";
6
+ const require = createRequire(import.meta.url);
7
+ const READY_PREFIX = "JONGODB_URI=";
8
+ const FAILURE_PREFIX = "JONGODB_START_FAILURE=";
9
+ const DEFAULT_HOST = "127.0.0.1";
10
+ const DEFAULT_DATABASE = "test";
11
+ const DEFAULT_STARTUP_TIMEOUT_MS = 15_000;
12
+ const DEFAULT_STOP_TIMEOUT_MS = 5_000;
13
+ const DEFAULT_LAUNCHER_CLASS = "org.jongodb.server.TcpMongoServerLauncher";
14
+ const MAX_LOG_LINES = 50;
15
+ const BUNDLED_BINARY_PACKAGE_PREFIX = "@jongodb/memory-server-bin";
16
+ export async function startJongodbMemoryServer(options = {}) {
17
+ const startupTimeoutMs = normalizeTimeout(options.startupTimeoutMs, DEFAULT_STARTUP_TIMEOUT_MS, "startupTimeoutMs");
18
+ const stopTimeoutMs = normalizeTimeout(options.stopTimeoutMs, DEFAULT_STOP_TIMEOUT_MS, "stopTimeoutMs");
19
+ const host = normalizeHost(options.host);
20
+ const port = normalizePort(options.port);
21
+ const databaseName = normalizeDatabaseName(options.databaseName);
22
+ const logLevel = options.logLevel ?? "silent";
23
+ const launchConfigs = resolveLaunchConfigs(options, {
24
+ host,
25
+ port,
26
+ databaseName,
27
+ });
28
+ const launchErrors = [];
29
+ for (let index = 0; index < launchConfigs.length; index += 1) {
30
+ const launchConfig = launchConfigs[index];
31
+ try {
32
+ return await startWithLaunchConfig(launchConfig, {
33
+ startupTimeoutMs,
34
+ stopTimeoutMs,
35
+ logLevel,
36
+ env: options.env,
37
+ });
38
+ }
39
+ catch (error) {
40
+ const normalized = wrapError(error);
41
+ launchErrors.push(`[${launchConfig.mode}:${launchConfig.source}] ${normalized.message}`);
42
+ }
43
+ }
44
+ throw new Error([
45
+ "Failed to start jongodb with available launch configurations.",
46
+ ...launchErrors,
47
+ ].join(" "));
48
+ }
49
+ async function startWithLaunchConfig(launchConfig, context) {
50
+ const child = spawn(launchConfig.command, launchConfig.args, {
51
+ stdio: ["ignore", "pipe", "pipe"],
52
+ windowsHide: true,
53
+ env: {
54
+ ...process.env,
55
+ ...context.env,
56
+ },
57
+ });
58
+ const stdoutLines = [];
59
+ const stderrLines = [];
60
+ let exitResult = null;
61
+ let stopped = false;
62
+ child.on("exit", (code, signal) => {
63
+ exitResult = { code, signal };
64
+ });
65
+ const stdoutReader = createInterface({ input: child.stdout });
66
+ const stderrReader = createInterface({ input: child.stderr });
67
+ const startupResult = await waitForStartup({
68
+ child,
69
+ stdoutReader,
70
+ stderrReader,
71
+ stdoutLines,
72
+ stderrLines,
73
+ startupTimeoutMs: context.startupTimeoutMs,
74
+ logLevel: context.logLevel,
75
+ launchDescription: `${launchConfig.mode}:${launchConfig.source}`,
76
+ }).catch(async (error) => {
77
+ await forceStopIfAlive(child, context.stopTimeoutMs);
78
+ throw wrapError(error);
79
+ });
80
+ const stop = async () => {
81
+ if (stopped) {
82
+ return;
83
+ }
84
+ stopped = true;
85
+ stdoutReader.close();
86
+ stderrReader.close();
87
+ if (exitResult !== null || child.exitCode !== null) {
88
+ return;
89
+ }
90
+ const terminated = child.kill("SIGTERM");
91
+ if (!terminated) {
92
+ if (exitResult !== null || child.exitCode !== null) {
93
+ return;
94
+ }
95
+ throw new Error("Failed to stop jongodb server process: unable to send SIGTERM.");
96
+ }
97
+ const gracefulExit = await waitForExit(child, context.stopTimeoutMs);
98
+ if (gracefulExit !== null) {
99
+ return;
100
+ }
101
+ const killed = child.kill("SIGKILL");
102
+ if (!killed) {
103
+ throw new Error("Failed to stop jongodb server process: SIGTERM timeout and SIGKILL failed.");
104
+ }
105
+ const forcedExit = await waitForExit(child, context.stopTimeoutMs);
106
+ if (forcedExit === null) {
107
+ throw new Error("Failed to stop jongodb server process: process did not exit after SIGKILL.");
108
+ }
109
+ };
110
+ if (child.pid === undefined) {
111
+ throw new Error("Jongodb process started without a PID.");
112
+ }
113
+ const detach = () => {
114
+ stdoutReader.close();
115
+ stderrReader.close();
116
+ child.stdout.destroy();
117
+ child.stderr.destroy();
118
+ child.unref();
119
+ };
120
+ return {
121
+ uri: startupResult.uri,
122
+ pid: child.pid,
123
+ detach,
124
+ stop,
125
+ };
126
+ }
127
+ function resolveLaunchConfigs(options, context) {
128
+ const mode = options.launchMode ?? "auto";
129
+ if (mode !== "auto" && mode !== "binary" && mode !== "java") {
130
+ throw new Error(`launchMode must be one of: auto, binary, java (got: ${mode}).`);
131
+ }
132
+ const binary = resolveBinaryCandidate(options.binaryPath);
133
+ const java = resolveJavaCandidate(options);
134
+ if (mode === "binary") {
135
+ if (binary === null) {
136
+ throw new Error([
137
+ "Binary launch mode requested but no binary was found.",
138
+ "Provide options.binaryPath or JONGODB_BINARY_PATH.",
139
+ bundledBinaryHint(),
140
+ ].join(" "));
141
+ }
142
+ return [toBinaryLaunchConfig(binary.path, binary.source, context)];
143
+ }
144
+ if (mode === "java") {
145
+ if (java === null) {
146
+ throw new Error([
147
+ "Java launch mode requested but Java classpath is not configured.",
148
+ "Pass options.classpath or set JONGODB_CLASSPATH.",
149
+ "Example (repo-local): ./.tooling/gradle-8.10.2/bin/gradle -q printLauncherClasspath",
150
+ ].join(" "));
151
+ }
152
+ return [toJavaLaunchConfig(java, context)];
153
+ }
154
+ if (binary !== null && java !== null) {
155
+ return [
156
+ toBinaryLaunchConfig(binary.path, binary.source, context),
157
+ toJavaLaunchConfig(java, context),
158
+ ];
159
+ }
160
+ if (binary !== null) {
161
+ return [toBinaryLaunchConfig(binary.path, binary.source, context)];
162
+ }
163
+ if (java !== null) {
164
+ return [toJavaLaunchConfig(java, context)];
165
+ }
166
+ throw new Error([
167
+ "No launcher runtime configured.",
168
+ "Provide one of:",
169
+ "1) options.binaryPath or JONGODB_BINARY_PATH",
170
+ "2) options.classpath or JONGODB_CLASSPATH",
171
+ bundledBinaryHint(),
172
+ ].join(" "));
173
+ }
174
+ function toBinaryLaunchConfig(binaryPath, source, context) {
175
+ return {
176
+ mode: "binary",
177
+ command: binaryPath,
178
+ args: [
179
+ `--host=${context.host}`,
180
+ `--port=${context.port}`,
181
+ `--database=${context.databaseName}`,
182
+ ],
183
+ source,
184
+ };
185
+ }
186
+ function toJavaLaunchConfig(java, context) {
187
+ return {
188
+ mode: "java",
189
+ command: java.javaPath,
190
+ args: [
191
+ "-cp",
192
+ java.classpath,
193
+ java.launcherClass,
194
+ `--host=${context.host}`,
195
+ `--port=${context.port}`,
196
+ `--database=${context.databaseName}`,
197
+ ],
198
+ source: java.source,
199
+ };
200
+ }
201
+ function resolveBinaryCandidate(explicitBinaryPath) {
202
+ const fromOption = normalizeBinaryPath(explicitBinaryPath, "options.binaryPath");
203
+ if (fromOption !== null) {
204
+ return { path: fromOption, source: "options.binaryPath" };
205
+ }
206
+ const fromEnv = normalizeBinaryPath(process.env.JONGODB_BINARY_PATH, "JONGODB_BINARY_PATH");
207
+ if (fromEnv !== null) {
208
+ return { path: fromEnv, source: "JONGODB_BINARY_PATH" };
209
+ }
210
+ const fromBundled = resolveBundledBinaryPath();
211
+ if (fromBundled !== null) {
212
+ return fromBundled;
213
+ }
214
+ return null;
215
+ }
216
+ function normalizeBinaryPath(value, fieldName) {
217
+ if (value === undefined) {
218
+ return null;
219
+ }
220
+ const normalized = value.trim();
221
+ if (normalized.length === 0) {
222
+ throw new Error(`${fieldName} must not be empty when provided.`);
223
+ }
224
+ return normalized;
225
+ }
226
+ function resolveBundledBinaryPath() {
227
+ const candidates = bundledBinaryPackageCandidates();
228
+ for (const packageName of candidates) {
229
+ const pathFromPackage = resolveBinaryPathFromPackage(packageName);
230
+ if (pathFromPackage !== null) {
231
+ return {
232
+ path: pathFromPackage,
233
+ source: `bundled-package:${packageName}`,
234
+ };
235
+ }
236
+ }
237
+ return null;
238
+ }
239
+ function bundledBinaryPackageCandidates() {
240
+ const platform = process.platform;
241
+ const arch = process.arch;
242
+ if (platform === "darwin") {
243
+ return [`${BUNDLED_BINARY_PACKAGE_PREFIX}-darwin-${arch}`];
244
+ }
245
+ if (platform === "win32") {
246
+ return [`${BUNDLED_BINARY_PACKAGE_PREFIX}-win32-${arch}`];
247
+ }
248
+ if (platform === "linux") {
249
+ const libcVariant = detectLinuxLibcVariant();
250
+ return [
251
+ `${BUNDLED_BINARY_PACKAGE_PREFIX}-linux-${arch}-${libcVariant}`,
252
+ `${BUNDLED_BINARY_PACKAGE_PREFIX}-linux-${arch}`,
253
+ ];
254
+ }
255
+ return [];
256
+ }
257
+ function detectLinuxLibcVariant() {
258
+ const report = process.report?.getReport?.();
259
+ const glibcVersionRuntime = report?.header?.glibcVersionRuntime;
260
+ if (typeof glibcVersionRuntime === "string" && glibcVersionRuntime.length > 0) {
261
+ return "gnu";
262
+ }
263
+ return "musl";
264
+ }
265
+ function resolveBinaryPathFromPackage(packageName) {
266
+ try {
267
+ const packageJsonPath = require.resolve(`${packageName}/package.json`);
268
+ const packageDir = dirname(packageJsonPath);
269
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
270
+ const binaryRelativePath = readJongodbBinaryPath(packageJson) ??
271
+ readBinEntryPath(packageJson.bin);
272
+ if (binaryRelativePath === null) {
273
+ return null;
274
+ }
275
+ return resolve(packageDir, binaryRelativePath);
276
+ }
277
+ catch {
278
+ return null;
279
+ }
280
+ }
281
+ function readJongodbBinaryPath(packageJson) {
282
+ const binary = packageJson.jongodb?.binary;
283
+ if (typeof binary !== "string") {
284
+ return null;
285
+ }
286
+ const normalized = binary.trim();
287
+ return normalized.length === 0 ? null : normalized;
288
+ }
289
+ function readBinEntryPath(value) {
290
+ if (typeof value === "string") {
291
+ const normalized = value.trim();
292
+ return normalized.length === 0 ? null : normalized;
293
+ }
294
+ if (value !== undefined && typeof value === "object") {
295
+ const preferred = value["jongodb-memory-server"];
296
+ if (typeof preferred === "string" && preferred.trim().length > 0) {
297
+ return preferred.trim();
298
+ }
299
+ for (const candidate of Object.values(value)) {
300
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
301
+ return candidate.trim();
302
+ }
303
+ }
304
+ }
305
+ return null;
306
+ }
307
+ function bundledBinaryHint() {
308
+ const candidates = bundledBinaryPackageCandidates();
309
+ if (candidates.length === 0) {
310
+ return "Bundled platform binary package is not defined for this OS/architecture.";
311
+ }
312
+ return `Bundled platform binary package candidates: ${candidates.join(", ")}.`;
313
+ }
314
+ function resolveJavaCandidate(options) {
315
+ const classpath = resolveClasspathOrNull(options.classpath);
316
+ if (classpath === null) {
317
+ return null;
318
+ }
319
+ return {
320
+ javaPath: options.javaPath?.trim() || process.env.JONGODB_JAVA_PATH || "java",
321
+ classpath,
322
+ launcherClass: options.launcherClass?.trim() || DEFAULT_LAUNCHER_CLASS,
323
+ source: options.classpath !== undefined ? "options.classpath" : "JONGODB_CLASSPATH",
324
+ };
325
+ }
326
+ function normalizeTimeout(value, fallback, fieldName) {
327
+ const resolved = value ?? fallback;
328
+ if (!Number.isFinite(resolved) || resolved <= 0) {
329
+ throw new Error(`${fieldName} must be a positive number.`);
330
+ }
331
+ return Math.floor(resolved);
332
+ }
333
+ function normalizeHost(host) {
334
+ const normalized = host?.trim() || DEFAULT_HOST;
335
+ if (normalized.length === 0) {
336
+ throw new Error("host must not be empty.");
337
+ }
338
+ return normalized;
339
+ }
340
+ function normalizePort(port) {
341
+ const normalized = port ?? 0;
342
+ if (!Number.isInteger(normalized) || normalized < 0 || normalized > 65535) {
343
+ throw new Error("port must be an integer between 0 and 65535.");
344
+ }
345
+ return normalized;
346
+ }
347
+ function normalizeDatabaseName(databaseName) {
348
+ const normalized = databaseName?.trim() || DEFAULT_DATABASE;
349
+ if (normalized.length === 0) {
350
+ throw new Error("databaseName must not be empty.");
351
+ }
352
+ return normalized;
353
+ }
354
+ function resolveClasspathOrNull(classpath) {
355
+ const explicit = resolveExplicitClasspath(classpath);
356
+ if (explicit !== null) {
357
+ return explicit;
358
+ }
359
+ const fromEnv = process.env.JONGODB_CLASSPATH?.trim();
360
+ if (fromEnv !== undefined && fromEnv.length > 0) {
361
+ return fromEnv;
362
+ }
363
+ return null;
364
+ }
365
+ function resolveExplicitClasspath(classpath) {
366
+ if (typeof classpath === "string") {
367
+ const normalized = classpath.trim();
368
+ if (normalized.length === 0) {
369
+ throw new Error("classpath string is empty.");
370
+ }
371
+ return normalized;
372
+ }
373
+ if (Array.isArray(classpath)) {
374
+ if (classpath.length === 0) {
375
+ throw new Error("classpath array is empty.");
376
+ }
377
+ const normalizedParts = classpath
378
+ .map((part) => part.trim())
379
+ .filter((part) => part.length > 0);
380
+ if (normalizedParts.length === 0) {
381
+ throw new Error("classpath array has no valid entries.");
382
+ }
383
+ return normalizedParts.join(delimiter);
384
+ }
385
+ return null;
386
+ }
387
+ async function waitForStartup(params) {
388
+ const { child, stdoutReader, stderrReader, stdoutLines, stderrLines, startupTimeoutMs, logLevel, launchDescription, } = params;
389
+ return new Promise((resolve, reject) => {
390
+ let settled = false;
391
+ let resolvedUri = null;
392
+ const timeout = setTimeout(() => {
393
+ if (settled) {
394
+ return;
395
+ }
396
+ settled = true;
397
+ reject(new Error([
398
+ `Timed out waiting for jongodb startup after ${startupTimeoutMs}ms (${launchDescription}).`,
399
+ formatLogTail("stdout", stdoutLines),
400
+ formatLogTail("stderr", stderrLines),
401
+ ].join(" ")));
402
+ }, startupTimeoutMs);
403
+ const cleanupListeners = () => {
404
+ stdoutReader.off("line", onStdout);
405
+ stderrReader.off("line", onStderr);
406
+ child.off("error", onError);
407
+ child.off("exit", onExit);
408
+ };
409
+ const finish = (fn) => {
410
+ if (settled) {
411
+ return;
412
+ }
413
+ settled = true;
414
+ clearTimeout(timeout);
415
+ cleanupListeners();
416
+ fn();
417
+ };
418
+ const onStdout = (line) => {
419
+ appendLine(stdoutLines, line);
420
+ maybeLog("stdout", line, logLevel);
421
+ if (!line.startsWith(READY_PREFIX)) {
422
+ return;
423
+ }
424
+ const uri = line.slice(READY_PREFIX.length).trim();
425
+ if (uri.length === 0) {
426
+ finish(() => reject(new Error("Launcher emitted empty JONGODB_URI line.")));
427
+ return;
428
+ }
429
+ resolvedUri = uri;
430
+ finish(() => resolve({ uri }));
431
+ };
432
+ const onStderr = (line) => {
433
+ appendLine(stderrLines, line);
434
+ maybeLog("stderr", line, logLevel);
435
+ };
436
+ const onError = (error) => {
437
+ finish(() => {
438
+ reject(new Error([
439
+ `Failed to spawn launcher '${child.spawnfile}': ${error.message}`,
440
+ `Launch source: ${launchDescription}.`,
441
+ "Check binary/classpath configuration.",
442
+ ].join(" ")));
443
+ });
444
+ };
445
+ const onExit = (code, signal) => {
446
+ if (resolvedUri !== null) {
447
+ return;
448
+ }
449
+ finish(() => {
450
+ reject(new Error([
451
+ `Jongodb process exited before readiness (code=${code}, signal=${signal}).`,
452
+ `Launch source: ${launchDescription}.`,
453
+ formatFailureLine(stderrLines),
454
+ formatLogTail("stdout", stdoutLines),
455
+ formatLogTail("stderr", stderrLines),
456
+ ].join(" ")));
457
+ });
458
+ };
459
+ stdoutReader.on("line", onStdout);
460
+ stderrReader.on("line", onStderr);
461
+ child.once("error", onError);
462
+ child.once("exit", onExit);
463
+ });
464
+ }
465
+ function maybeLog(stream, line, logLevel) {
466
+ if (logLevel === "silent") {
467
+ return;
468
+ }
469
+ if (logLevel === "info" && stream === "stdout") {
470
+ return;
471
+ }
472
+ if (stream === "stdout") {
473
+ // eslint-disable-next-line no-console
474
+ console.log(`[jongodb:${stream}] ${line}`);
475
+ return;
476
+ }
477
+ // eslint-disable-next-line no-console
478
+ console.error(`[jongodb:${stream}] ${line}`);
479
+ }
480
+ function appendLine(lines, line) {
481
+ lines.push(line);
482
+ if (lines.length > MAX_LOG_LINES) {
483
+ lines.shift();
484
+ }
485
+ }
486
+ function formatLogTail(name, lines) {
487
+ if (lines.length === 0) {
488
+ return `${name}:<empty>`;
489
+ }
490
+ return `${name}:` + lines.join(" | ");
491
+ }
492
+ function formatFailureLine(stderrLines) {
493
+ const failureLine = stderrLines.find((line) => line.startsWith(FAILURE_PREFIX));
494
+ if (failureLine === undefined) {
495
+ return "";
496
+ }
497
+ return failureLine;
498
+ }
499
+ async function forceStopIfAlive(child, stopTimeoutMs) {
500
+ if (child.exitCode !== null) {
501
+ return;
502
+ }
503
+ child.kill("SIGTERM");
504
+ const graceful = await waitForExit(child, stopTimeoutMs);
505
+ if (graceful !== null) {
506
+ return;
507
+ }
508
+ child.kill("SIGKILL");
509
+ await waitForExit(child, stopTimeoutMs);
510
+ }
511
+ function waitForExit(child, timeoutMs) {
512
+ if (child.exitCode !== null) {
513
+ return Promise.resolve({
514
+ code: child.exitCode,
515
+ signal: child.signalCode,
516
+ });
517
+ }
518
+ return new Promise((resolve) => {
519
+ const timeout = setTimeout(() => {
520
+ cleanup();
521
+ resolve(null);
522
+ }, timeoutMs);
523
+ const onExit = (code, signal) => {
524
+ cleanup();
525
+ resolve({ code, signal });
526
+ };
527
+ const cleanup = () => {
528
+ clearTimeout(timeout);
529
+ child.off("exit", onExit);
530
+ };
531
+ child.on("exit", onExit);
532
+ });
533
+ }
534
+ function wrapError(error) {
535
+ if (error instanceof Error) {
536
+ return error;
537
+ }
538
+ return new Error(String(error));
539
+ }
package/dist/jest.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { type JongodbMemoryServerOptions } from "./index.js";
2
+ export interface JestHookRegistrar {
3
+ beforeAll(callback: () => unknown | Promise<unknown>): void;
4
+ afterAll(callback: () => unknown | Promise<unknown>): void;
5
+ }
6
+ export interface JestHookOptions extends JongodbMemoryServerOptions {
7
+ envVarName?: string;
8
+ }
9
+ export interface RegisteredJongodbTestServer {
10
+ readonly uri: string;
11
+ }
12
+ export interface JestGlobalLifecycleOptions extends JongodbMemoryServerOptions {
13
+ envVarName?: string;
14
+ stateFile?: string;
15
+ killTimeoutMs?: number;
16
+ }
17
+ export interface JestGlobalState {
18
+ uri: string;
19
+ pid: number;
20
+ envVarName: string;
21
+ }
22
+ export declare function registerJongodbForJest(hooks: JestHookRegistrar, options?: JestHookOptions): RegisteredJongodbTestServer;
23
+ export declare function createJestGlobalSetup(options?: JestGlobalLifecycleOptions): () => Promise<void>;
24
+ export declare function createJestGlobalTeardown(options?: JestGlobalLifecycleOptions): () => Promise<void>;
25
+ export declare function readJestGlobalState(options?: {
26
+ stateFile?: string;
27
+ }): Promise<JestGlobalState | null>;
28
+ export declare function readJestGlobalUri(options?: {
29
+ stateFile?: string;
30
+ }): Promise<string | null>;
31
+ //# sourceMappingURL=jest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jest.d.ts","sourceRoot":"","sources":["../src/jest.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,0BAA0B,EAEhC,MAAM,YAAY,CAAC;AAWpB,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,QAAQ,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5D;AAED,MAAM,WAAW,eAAgB,SAAQ,0BAA0B;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,0BAA2B,SAAQ,0BAA0B;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE,eAAoB,GAC5B,2BAA2B,CAgB7B;AAED,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,OAAO,CAAC,IAAI,CAAC,CAiBrB;AAED,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,0BAA+B,GACvC,MAAM,OAAO,CAAC,IAAI,CAAC,CAkBrB;AAED,wBAAsB,mBAAmB,CAAC,OAAO,GAAE;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAmBvC;AAED,wBAAsB,iBAAiB,CAAC,OAAO,GAAE;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM9B"}