@cloudflare/sandbox 0.2.4 → 0.3.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/Dockerfile +9 -11
  3. package/README.md +69 -7
  4. package/container_src/control-process.ts +784 -0
  5. package/container_src/handler/exec.ts +99 -254
  6. package/container_src/handler/file.ts +179 -837
  7. package/container_src/handler/git.ts +28 -80
  8. package/container_src/handler/process.ts +443 -515
  9. package/container_src/handler/session.ts +92 -0
  10. package/container_src/index.ts +68 -130
  11. package/container_src/isolation.ts +1039 -0
  12. package/container_src/shell-escape.ts +42 -0
  13. package/container_src/types.ts +27 -13
  14. package/dist/{chunk-HHUDRGPY.js → chunk-BEQUGUY4.js} +2 -2
  15. package/dist/{chunk-CKIGERRS.js → chunk-GTGWAEED.js} +237 -264
  16. package/dist/chunk-GTGWAEED.js.map +1 -0
  17. package/dist/{chunk-3CQ6THKA.js → chunk-SMUEY5JR.js} +85 -103
  18. package/dist/chunk-SMUEY5JR.js.map +1 -0
  19. package/dist/{client-Ce40ujDF.d.ts → client-Dny_ro_v.d.ts} +41 -25
  20. package/dist/client.d.ts +1 -1
  21. package/dist/client.js +1 -1
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +8 -9
  24. package/dist/interpreter.d.ts +1 -1
  25. package/dist/jupyter-client.d.ts +1 -1
  26. package/dist/jupyter-client.js +2 -2
  27. package/dist/request-handler.d.ts +1 -1
  28. package/dist/request-handler.js +3 -5
  29. package/dist/sandbox.d.ts +1 -1
  30. package/dist/sandbox.js +3 -5
  31. package/dist/types.d.ts +10 -21
  32. package/dist/types.js +35 -9
  33. package/dist/types.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/client.ts +120 -135
  36. package/src/index.ts +8 -0
  37. package/src/sandbox.ts +286 -331
  38. package/src/types.ts +15 -24
  39. package/dist/chunk-3CQ6THKA.js.map +0 -1
  40. package/dist/chunk-6EWSYSO7.js +0 -46
  41. package/dist/chunk-6EWSYSO7.js.map +0 -1
  42. package/dist/chunk-CKIGERRS.js.map +0 -1
  43. /package/dist/{chunk-HHUDRGPY.js.map → chunk-BEQUGUY4.js.map} +0 -0
@@ -4,19 +4,12 @@ import {
4
4
  sanitizeSandboxId,
5
5
  validatePort
6
6
  } from "./chunk-6UAWTJ5S.js";
7
- import {
8
- parseSSEStream
9
- } from "./chunk-NNGBXDMY.js";
10
- import {
11
- ProcessNotFoundError,
12
- SandboxError
13
- } from "./chunk-6EWSYSO7.js";
14
7
  import {
15
8
  CodeInterpreter
16
9
  } from "./chunk-FKBV7CZS.js";
17
10
  import {
18
11
  JupyterClient
19
- } from "./chunk-HHUDRGPY.js";
12
+ } from "./chunk-BEQUGUY4.js";
20
13
 
21
14
  // src/sandbox.ts
22
15
  import { Container, getContainer } from "@cloudflare/containers";
@@ -134,6 +127,7 @@ var Sandbox = class extends Container {
134
127
  client;
135
128
  sandboxName = null;
136
129
  codeInterpreter;
130
+ defaultSession = null;
137
131
  constructor(ctx, env) {
138
132
  super(ctx, env);
139
133
  this.client = new JupyterClient({
@@ -172,15 +166,15 @@ var Sandbox = class extends Container {
172
166
  async setEnvVars(envVars) {
173
167
  this.envVars = { ...this.envVars, ...envVars };
174
168
  console.log(`[Sandbox] Updated environment variables`);
169
+ if (this.defaultSession) {
170
+ await this.defaultSession.setEnvVars(envVars);
171
+ }
175
172
  }
176
173
  onStart() {
177
174
  console.log("Sandbox successfully started");
178
175
  }
179
176
  onStop() {
180
177
  console.log("Sandbox successfully shut down");
181
- if (this.client) {
182
- this.client.clearSession();
183
- }
184
178
  }
185
179
  onError(error) {
186
180
  console.log("Sandbox error:", error);
@@ -204,293 +198,92 @@ var Sandbox = class extends Container {
204
198
  }
205
199
  return 3e3;
206
200
  }
207
- // Enhanced exec method - always returns ExecResult with optional streaming
208
- // This replaces the old exec method to match ISandbox interface
209
- async exec(command, options) {
210
- const startTime = Date.now();
211
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
212
- let timeoutId;
213
- try {
214
- if (options?.signal?.aborted) {
215
- throw new Error("Operation was aborted");
216
- }
217
- let result;
218
- if (options?.stream && options?.onOutput) {
219
- result = await this.executeWithStreaming(
220
- command,
221
- options,
222
- startTime,
223
- timestamp
224
- );
225
- } else {
226
- const response = await this.client.execute(command, {
227
- sessionId: options?.sessionId,
228
- cwd: options?.cwd,
229
- env: options?.env
230
- });
231
- const duration = Date.now() - startTime;
232
- result = this.mapExecuteResponseToExecResult(
233
- response,
234
- duration,
235
- options?.sessionId
236
- );
237
- }
238
- if (options?.onComplete) {
239
- options.onComplete(result);
240
- }
241
- return result;
242
- } catch (error) {
243
- if (options?.onError && error instanceof Error) {
244
- options.onError(error);
245
- }
246
- throw error;
247
- } finally {
248
- if (timeoutId) {
249
- clearTimeout(timeoutId);
250
- }
251
- }
252
- }
253
- async executeWithStreaming(command, options, startTime, timestamp) {
254
- let stdout = "";
255
- let stderr = "";
256
- try {
257
- const stream = await this.client.executeCommandStream(
258
- command,
259
- options.sessionId
260
- );
261
- for await (const event of parseSSEStream(stream)) {
262
- if (options.signal?.aborted) {
263
- throw new Error("Operation was aborted");
264
- }
265
- switch (event.type) {
266
- case "stdout":
267
- case "stderr":
268
- if (event.data) {
269
- if (event.type === "stdout") stdout += event.data;
270
- if (event.type === "stderr") stderr += event.data;
271
- if (options.onOutput) {
272
- options.onOutput(event.type, event.data);
273
- }
274
- }
275
- break;
276
- case "complete": {
277
- const duration = Date.now() - startTime;
278
- return event.result || {
279
- success: event.exitCode === 0,
280
- exitCode: event.exitCode || 0,
281
- stdout,
282
- stderr,
283
- command,
284
- duration,
285
- timestamp,
286
- sessionId: options.sessionId
287
- };
288
- }
289
- case "error":
290
- throw new Error(event.error || "Command execution failed");
291
- }
292
- }
293
- throw new Error("Stream ended without completion event");
294
- } catch (error) {
295
- if (options.signal?.aborted) {
296
- throw new Error("Operation was aborted");
297
- }
298
- throw error;
201
+ // Helper to ensure default session is initialized
202
+ async ensureDefaultSession() {
203
+ if (!this.defaultSession) {
204
+ const sessionId = `sandbox-${this.sandboxName || "default"}`;
205
+ this.defaultSession = await this.createSession({
206
+ id: sessionId,
207
+ env: this.envVars || {},
208
+ cwd: "/workspace",
209
+ isolation: true
210
+ });
211
+ console.log(`[Sandbox] Default session initialized: ${sessionId}`);
299
212
  }
213
+ return this.defaultSession;
300
214
  }
301
- mapExecuteResponseToExecResult(response, duration, sessionId) {
302
- return {
303
- success: response.success,
304
- exitCode: response.exitCode,
305
- stdout: response.stdout,
306
- stderr: response.stderr,
307
- command: response.command,
308
- duration,
309
- timestamp: response.timestamp,
310
- sessionId
311
- };
215
+ async exec(command, options) {
216
+ const session = await this.ensureDefaultSession();
217
+ return session.exec(command, options);
312
218
  }
313
- // Background process management
314
219
  async startProcess(command, options) {
315
- try {
316
- const response = await this.client.startProcess(command, {
317
- processId: options?.processId,
318
- sessionId: options?.sessionId,
319
- timeout: options?.timeout,
320
- env: options?.env,
321
- cwd: options?.cwd,
322
- encoding: options?.encoding,
323
- autoCleanup: options?.autoCleanup
324
- });
325
- const process = response.process;
326
- const processObj = {
327
- id: process.id,
328
- pid: process.pid,
329
- command: process.command,
330
- status: process.status,
331
- startTime: new Date(process.startTime),
332
- endTime: void 0,
333
- exitCode: void 0,
334
- sessionId: process.sessionId,
335
- async kill() {
336
- throw new Error("Method will be replaced");
337
- },
338
- async getStatus() {
339
- throw new Error("Method will be replaced");
340
- },
341
- async getLogs() {
342
- throw new Error("Method will be replaced");
343
- }
344
- };
345
- processObj.kill = async (signal) => {
346
- await this.killProcess(process.id, signal);
347
- };
348
- processObj.getStatus = async () => {
349
- const current = await this.getProcess(process.id);
350
- return current?.status || "error";
351
- };
352
- processObj.getLogs = async () => {
353
- const logs = await this.getProcessLogs(process.id);
354
- return { stdout: logs.stdout, stderr: logs.stderr };
355
- };
356
- if (options?.onStart) {
357
- options.onStart(processObj);
358
- }
359
- return processObj;
360
- } catch (error) {
361
- if (options?.onError && error instanceof Error) {
362
- options.onError(error);
363
- }
364
- throw error;
365
- }
220
+ const session = await this.ensureDefaultSession();
221
+ return session.startProcess(command, options);
366
222
  }
367
223
  async listProcesses() {
368
- const response = await this.client.listProcesses();
369
- return response.processes.map((processData) => ({
370
- id: processData.id,
371
- pid: processData.pid,
372
- command: processData.command,
373
- status: processData.status,
374
- startTime: new Date(processData.startTime),
375
- endTime: processData.endTime ? new Date(processData.endTime) : void 0,
376
- exitCode: processData.exitCode,
377
- sessionId: processData.sessionId,
378
- kill: async (signal) => {
379
- await this.killProcess(processData.id, signal);
380
- },
381
- getStatus: async () => {
382
- const current = await this.getProcess(processData.id);
383
- return current?.status || "error";
384
- },
385
- getLogs: async () => {
386
- const logs = await this.getProcessLogs(processData.id);
387
- return { stdout: logs.stdout, stderr: logs.stderr };
388
- }
389
- }));
224
+ const session = await this.ensureDefaultSession();
225
+ return session.listProcesses();
390
226
  }
391
227
  async getProcess(id) {
392
- const response = await this.client.getProcess(id);
393
- if (!response.process) {
394
- return null;
395
- }
396
- const processData = response.process;
397
- return {
398
- id: processData.id,
399
- pid: processData.pid,
400
- command: processData.command,
401
- status: processData.status,
402
- startTime: new Date(processData.startTime),
403
- endTime: processData.endTime ? new Date(processData.endTime) : void 0,
404
- exitCode: processData.exitCode,
405
- sessionId: processData.sessionId,
406
- kill: async (signal) => {
407
- await this.killProcess(processData.id, signal);
408
- },
409
- getStatus: async () => {
410
- const current = await this.getProcess(processData.id);
411
- return current?.status || "error";
412
- },
413
- getLogs: async () => {
414
- const logs = await this.getProcessLogs(processData.id);
415
- return { stdout: logs.stdout, stderr: logs.stderr };
416
- }
417
- };
228
+ const session = await this.ensureDefaultSession();
229
+ return session.getProcess(id);
418
230
  }
419
- async killProcess(id, _signal) {
420
- try {
421
- await this.client.killProcess(id);
422
- } catch (error) {
423
- if (error instanceof Error && error.message.includes("Process not found")) {
424
- throw new ProcessNotFoundError(id);
425
- }
426
- throw new SandboxError(
427
- `Failed to kill process ${id}: ${error instanceof Error ? error.message : "Unknown error"}`,
428
- "KILL_PROCESS_FAILED"
429
- );
430
- }
231
+ async killProcess(id, signal) {
232
+ const session = await this.ensureDefaultSession();
233
+ return session.killProcess(id, signal);
431
234
  }
432
235
  async killAllProcesses() {
433
- const response = await this.client.killAllProcesses();
434
- return response.killedCount;
236
+ const session = await this.ensureDefaultSession();
237
+ return session.killAllProcesses();
435
238
  }
436
239
  async cleanupCompletedProcesses() {
437
- return 0;
240
+ const session = await this.ensureDefaultSession();
241
+ return session.cleanupCompletedProcesses();
438
242
  }
439
243
  async getProcessLogs(id) {
440
- try {
441
- const response = await this.client.getProcessLogs(id);
442
- return {
443
- stdout: response.stdout,
444
- stderr: response.stderr
445
- };
446
- } catch (error) {
447
- if (error instanceof Error && error.message.includes("Process not found")) {
448
- throw new ProcessNotFoundError(id);
449
- }
450
- throw error;
451
- }
244
+ const session = await this.ensureDefaultSession();
245
+ return session.getProcessLogs(id);
452
246
  }
453
- // Streaming methods - return ReadableStream for RPC compatibility
247
+ // Streaming methods - delegates to default session
454
248
  async execStream(command, options) {
455
- if (options?.signal?.aborted) {
456
- throw new Error("Operation was aborted");
457
- }
458
- const stream = await this.client.executeCommandStream(
459
- command,
460
- options?.sessionId
461
- );
462
- return stream;
249
+ const session = await this.ensureDefaultSession();
250
+ return session.execStream(command, options);
463
251
  }
464
252
  async streamProcessLogs(processId, options) {
465
- if (options?.signal?.aborted) {
466
- throw new Error("Operation was aborted");
467
- }
468
- const stream = await this.client.streamProcessLogs(processId);
469
- return stream;
253
+ const session = await this.ensureDefaultSession();
254
+ return session.streamProcessLogs(processId, options);
470
255
  }
471
256
  async gitCheckout(repoUrl, options) {
472
- return this.client.gitCheckout(repoUrl, options.branch, options.targetDir);
257
+ const session = await this.ensureDefaultSession();
258
+ return session.gitCheckout(repoUrl, options);
473
259
  }
474
260
  async mkdir(path, options = {}) {
475
- return this.client.mkdir(path, options.recursive);
261
+ const session = await this.ensureDefaultSession();
262
+ return session.mkdir(path, options);
476
263
  }
477
264
  async writeFile(path, content, options = {}) {
478
- return this.client.writeFile(path, content, options.encoding);
265
+ const session = await this.ensureDefaultSession();
266
+ return session.writeFile(path, content, options);
479
267
  }
480
268
  async deleteFile(path) {
481
- return this.client.deleteFile(path);
269
+ const session = await this.ensureDefaultSession();
270
+ return session.deleteFile(path);
482
271
  }
483
272
  async renameFile(oldPath, newPath) {
484
- return this.client.renameFile(oldPath, newPath);
273
+ const session = await this.ensureDefaultSession();
274
+ return session.renameFile(oldPath, newPath);
485
275
  }
486
276
  async moveFile(sourcePath, destinationPath) {
487
- return this.client.moveFile(sourcePath, destinationPath);
277
+ const session = await this.ensureDefaultSession();
278
+ return session.moveFile(sourcePath, destinationPath);
488
279
  }
489
280
  async readFile(path, options = {}) {
490
- return this.client.readFile(path, options.encoding);
281
+ const session = await this.ensureDefaultSession();
282
+ return session.readFile(path, options);
491
283
  }
492
284
  async listFiles(path, options = {}) {
493
- return this.client.listFiles(path, options);
285
+ const session = await this.ensureDefaultSession();
286
+ return session.listFiles(path, options);
494
287
  }
495
288
  async exposePort(port, options) {
496
289
  await this.client.exposePort(port, options?.name);
@@ -680,6 +473,186 @@ var Sandbox = class extends Container {
680
473
  async deleteCodeContext(contextId) {
681
474
  return this.codeInterpreter.deleteCodeContext(contextId);
682
475
  }
476
+ // ============================================================================
477
+ // Session Management (Simple Isolation)
478
+ // ============================================================================
479
+ /**
480
+ * Create a new execution session with isolation
481
+ * Returns a session object with exec() method
482
+ */
483
+ async createSession(options) {
484
+ const sessionId = options.id || `session-${Date.now()}`;
485
+ await this.client.createSession({
486
+ id: sessionId,
487
+ env: options.env,
488
+ cwd: options.cwd,
489
+ isolation: options.isolation
490
+ });
491
+ return {
492
+ id: sessionId,
493
+ // Command execution - clean method names
494
+ exec: async (command, options2) => {
495
+ const result = await this.client.exec(sessionId, command);
496
+ return {
497
+ ...result,
498
+ command,
499
+ duration: 0,
500
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
501
+ };
502
+ },
503
+ execStream: async (command, options2) => {
504
+ return await this.client.execStream(sessionId, command);
505
+ },
506
+ // Process management - route to session-aware methods
507
+ startProcess: async (command, options2) => {
508
+ const response = await this.client.startProcess(command, sessionId, {
509
+ processId: options2?.processId,
510
+ timeout: options2?.timeout,
511
+ env: options2?.env,
512
+ cwd: options2?.cwd,
513
+ encoding: options2?.encoding,
514
+ autoCleanup: options2?.autoCleanup
515
+ });
516
+ const process = response.process;
517
+ return {
518
+ id: process.id,
519
+ pid: process.pid,
520
+ command: process.command,
521
+ status: process.status,
522
+ startTime: new Date(process.startTime),
523
+ endTime: process.endTime ? new Date(process.endTime) : void 0,
524
+ exitCode: process.exitCode ?? void 0,
525
+ kill: async (signal) => {
526
+ await this.client.killProcess(process.id);
527
+ },
528
+ getStatus: async () => {
529
+ const resp = await this.client.getProcess(process.id);
530
+ return resp.process?.status || "error";
531
+ },
532
+ getLogs: async () => {
533
+ return await this.client.getProcessLogs(process.id);
534
+ }
535
+ };
536
+ },
537
+ listProcesses: async () => {
538
+ const response = await this.client.listProcesses(sessionId);
539
+ return response.processes.map((p) => ({
540
+ id: p.id,
541
+ pid: p.pid,
542
+ command: p.command,
543
+ status: p.status,
544
+ startTime: new Date(p.startTime),
545
+ endTime: p.endTime ? new Date(p.endTime) : void 0,
546
+ exitCode: p.exitCode ?? void 0,
547
+ kill: async (signal) => {
548
+ await this.client.killProcess(p.id);
549
+ },
550
+ getStatus: async () => {
551
+ const processResp = await this.client.getProcess(p.id);
552
+ return processResp.process?.status || "error";
553
+ },
554
+ getLogs: async () => {
555
+ return this.client.getProcessLogs(p.id);
556
+ }
557
+ }));
558
+ },
559
+ getProcess: async (id) => {
560
+ const response = await this.client.getProcess(id);
561
+ if (!response.process) return null;
562
+ const p = response.process;
563
+ return {
564
+ id: p.id,
565
+ pid: p.pid,
566
+ command: p.command,
567
+ status: p.status,
568
+ startTime: new Date(p.startTime),
569
+ endTime: p.endTime ? new Date(p.endTime) : void 0,
570
+ exitCode: p.exitCode ?? void 0,
571
+ kill: async (signal) => {
572
+ await this.client.killProcess(p.id);
573
+ },
574
+ getStatus: async () => {
575
+ const processResp = await this.client.getProcess(p.id);
576
+ return processResp.process?.status || "error";
577
+ },
578
+ getLogs: async () => {
579
+ return this.client.getProcessLogs(p.id);
580
+ }
581
+ };
582
+ },
583
+ killProcess: async (id, signal) => {
584
+ await this.client.killProcess(id);
585
+ },
586
+ killAllProcesses: async () => {
587
+ const response = await this.client.killAllProcesses(sessionId);
588
+ return response.killedCount;
589
+ },
590
+ streamProcessLogs: async (processId, options2) => {
591
+ return await this.client.streamProcessLogs(processId, options2);
592
+ },
593
+ getProcessLogs: async (id) => {
594
+ return await this.client.getProcessLogs(id);
595
+ },
596
+ cleanupCompletedProcesses: async () => {
597
+ return 0;
598
+ },
599
+ // File operations - clean method names (no "InSession" suffix)
600
+ writeFile: async (path, content, options2) => {
601
+ return await this.client.writeFile(path, content, options2?.encoding, sessionId);
602
+ },
603
+ readFile: async (path, options2) => {
604
+ return await this.client.readFile(path, options2?.encoding, sessionId);
605
+ },
606
+ mkdir: async (path, options2) => {
607
+ return await this.client.mkdir(path, options2?.recursive, sessionId);
608
+ },
609
+ deleteFile: async (path) => {
610
+ return await this.client.deleteFile(path, sessionId);
611
+ },
612
+ renameFile: async (oldPath, newPath) => {
613
+ return await this.client.renameFile(oldPath, newPath, sessionId);
614
+ },
615
+ moveFile: async (sourcePath, destinationPath) => {
616
+ return await this.client.moveFile(sourcePath, destinationPath, sessionId);
617
+ },
618
+ listFiles: async (path, options2) => {
619
+ return await this.client.listFiles(path, sessionId, options2);
620
+ },
621
+ gitCheckout: async (repoUrl, options2) => {
622
+ return await this.client.gitCheckout(repoUrl, sessionId, options2?.branch, options2?.targetDir);
623
+ },
624
+ // Port management
625
+ exposePort: async (port, options2) => {
626
+ return await this.exposePort(port, options2);
627
+ },
628
+ unexposePort: async (port) => {
629
+ return await this.unexposePort(port);
630
+ },
631
+ getExposedPorts: async (hostname) => {
632
+ return await this.getExposedPorts(hostname);
633
+ },
634
+ // Environment management
635
+ setEnvVars: async (envVars) => {
636
+ console.log(`[Session ${sessionId}] Environment variables update not yet implemented`);
637
+ },
638
+ // Code Interpreter API
639
+ createCodeContext: async (options2) => {
640
+ return await this.createCodeContext(options2);
641
+ },
642
+ runCode: async (code, options2) => {
643
+ return await this.runCode(code, options2);
644
+ },
645
+ runCodeStream: async (code, options2) => {
646
+ return await this.runCodeStream(code, options2);
647
+ },
648
+ listCodeContexts: async () => {
649
+ return await this.listCodeContexts();
650
+ },
651
+ deleteCodeContext: async (contextId) => {
652
+ return await this.deleteCodeContext(contextId);
653
+ }
654
+ };
655
+ }
683
656
  };
684
657
 
685
658
  export {
@@ -688,4 +661,4 @@ export {
688
661
  proxyToSandbox,
689
662
  isLocalhostPattern
690
663
  };
691
- //# sourceMappingURL=chunk-CKIGERRS.js.map
664
+ //# sourceMappingURL=chunk-GTGWAEED.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sandbox.ts","../src/request-handler.ts"],"sourcesContent":["import { Container, getContainer } from \"@cloudflare/containers\";\nimport { CodeInterpreter } from \"./interpreter\";\nimport type {\n CodeContext,\n CreateContextOptions,\n ExecutionResult,\n RunCodeOptions,\n} from \"./interpreter-types\";\nimport { JupyterClient } from \"./jupyter-client\";\nimport { isLocalhostPattern } from \"./request-handler\";\nimport {\n logSecurityEvent,\n SecurityError,\n sanitizeSandboxId,\n validatePort,\n} from \"./security\";\nimport { parseSSEStream } from \"./sse-parser\";\nimport type {\n ExecEvent,\n ExecOptions,\n ExecResult,\n ExecuteResponse,\n ExecutionSession,\n ISandbox,\n Process,\n ProcessOptions,\n ProcessStatus,\n StreamOptions,\n} from \"./types\";\nimport { ProcessNotFoundError, SandboxError } from \"./types\";\n\nexport function getSandbox(ns: DurableObjectNamespace<Sandbox>, id: string) {\n const stub = getContainer(ns, id);\n\n // Store the name on first access\n stub.setSandboxName?.(id);\n\n return stub;\n}\n\nexport class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {\n defaultPort = 3000; // Default port for the container's Bun server\n sleepAfter = \"20m\"; // Keep container warm for 20 minutes to avoid cold starts\n client: JupyterClient;\n private sandboxName: string | null = null;\n private codeInterpreter: CodeInterpreter;\n private defaultSession: ExecutionSession | null = null;\n\n constructor(ctx: DurableObjectState, env: Env) {\n super(ctx, env);\n this.client = new JupyterClient({\n onCommandComplete: (success, exitCode, _stdout, _stderr, command) => {\n console.log(\n `[Container] Command completed: ${command}, Success: ${success}, Exit code: ${exitCode}`\n );\n },\n onCommandStart: (command) => {\n console.log(`[Container] Command started: ${command}`);\n },\n onError: (error, _command) => {\n console.error(`[Container] Command error: ${error}`);\n },\n onOutput: (stream, data, _command) => {\n console.log(`[Container] [${stream}] ${data}`);\n },\n port: 3000, // Control plane port\n stub: this,\n });\n\n // Initialize code interpreter\n this.codeInterpreter = new CodeInterpreter(this);\n\n // Load the sandbox name from storage on initialization\n this.ctx.blockConcurrencyWhile(async () => {\n this.sandboxName =\n (await this.ctx.storage.get<string>(\"sandboxName\")) || null;\n });\n }\n\n // RPC method to set the sandbox name\n async setSandboxName(name: string): Promise<void> {\n if (!this.sandboxName) {\n this.sandboxName = name;\n await this.ctx.storage.put(\"sandboxName\", name);\n console.log(`[Sandbox] Stored sandbox name via RPC: ${name}`);\n }\n }\n\n // RPC method to set environment variables\n async setEnvVars(envVars: Record<string, string>): Promise<void> {\n this.envVars = { ...this.envVars, ...envVars };\n console.log(`[Sandbox] Updated environment variables`);\n \n // If we have a default session, update its environment too\n if (this.defaultSession) {\n await this.defaultSession.setEnvVars(envVars);\n }\n }\n\n override onStart() {\n console.log(\"Sandbox successfully started\");\n }\n\n override onStop() {\n console.log(\"Sandbox successfully shut down\");\n }\n\n override onError(error: unknown) {\n console.log(\"Sandbox error:\", error);\n }\n\n // Override fetch to route internal container requests to appropriate ports\n override async fetch(request: Request): Promise<Response> {\n const url = new URL(request.url);\n\n // Capture and store the sandbox name from the header if present\n if (!this.sandboxName && request.headers.has(\"X-Sandbox-Name\")) {\n const name = request.headers.get(\"X-Sandbox-Name\")!;\n this.sandboxName = name;\n await this.ctx.storage.put(\"sandboxName\", name);\n console.log(`[Sandbox] Stored sandbox name: ${this.sandboxName}`);\n }\n\n // Determine which port to route to\n const port = this.determinePort(url);\n\n // Route to the appropriate port\n return await this.containerFetch(request, port);\n }\n\n private determinePort(url: URL): number {\n // Extract port from proxy requests (e.g., /proxy/8080/*)\n const proxyMatch = url.pathname.match(/^\\/proxy\\/(\\d+)/);\n if (proxyMatch) {\n return parseInt(proxyMatch[1]);\n }\n\n // All other requests go to control plane on port 3000\n // This includes /api/* endpoints and any other control requests\n return 3000;\n }\n\n // Helper to ensure default session is initialized\n private async ensureDefaultSession(): Promise<ExecutionSession> {\n if (!this.defaultSession) {\n const sessionId = `sandbox-${this.sandboxName || 'default'}`;\n this.defaultSession = await this.createSession({\n id: sessionId,\n env: this.envVars || {},\n cwd: '/workspace',\n isolation: true\n });\n console.log(`[Sandbox] Default session initialized: ${sessionId}`);\n }\n return this.defaultSession;\n }\n\n\n async exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n const session = await this.ensureDefaultSession();\n return session.exec(command, options);\n }\n\n async startProcess(\n command: string,\n options?: ProcessOptions\n ): Promise<Process> {\n const session = await this.ensureDefaultSession();\n return session.startProcess(command, options);\n }\n\n async listProcesses(): Promise<Process[]> {\n const session = await this.ensureDefaultSession();\n return session.listProcesses();\n }\n\n async getProcess(id: string): Promise<Process | null> {\n const session = await this.ensureDefaultSession();\n return session.getProcess(id);\n }\n\n async killProcess(id: string, signal?: string): Promise<void> {\n const session = await this.ensureDefaultSession();\n return session.killProcess(id, signal);\n }\n\n async killAllProcesses(): Promise<number> {\n const session = await this.ensureDefaultSession();\n return session.killAllProcesses();\n }\n\n async cleanupCompletedProcesses(): Promise<number> {\n const session = await this.ensureDefaultSession();\n return session.cleanupCompletedProcesses();\n }\n\n async getProcessLogs(\n id: string\n ): Promise<{ stdout: string; stderr: string }> {\n const session = await this.ensureDefaultSession();\n return session.getProcessLogs(id);\n }\n\n // Streaming methods - delegates to default session\n async execStream(\n command: string,\n options?: StreamOptions\n ): Promise<ReadableStream<Uint8Array>> {\n const session = await this.ensureDefaultSession();\n return session.execStream(command, options);\n }\n\n async streamProcessLogs(\n processId: string,\n options?: { signal?: AbortSignal }\n ): Promise<ReadableStream<Uint8Array>> {\n const session = await this.ensureDefaultSession();\n return session.streamProcessLogs(processId, options);\n }\n\n async gitCheckout(\n repoUrl: string,\n options: { branch?: string; targetDir?: string }\n ) {\n const session = await this.ensureDefaultSession();\n return session.gitCheckout(repoUrl, options);\n }\n\n async mkdir(path: string, options: { recursive?: boolean } = {}) {\n const session = await this.ensureDefaultSession();\n return session.mkdir(path, options);\n }\n\n async writeFile(\n path: string,\n content: string,\n options: { encoding?: string } = {}\n ) {\n const session = await this.ensureDefaultSession();\n return session.writeFile(path, content, options);\n }\n\n async deleteFile(path: string) {\n const session = await this.ensureDefaultSession();\n return session.deleteFile(path);\n }\n\n async renameFile(oldPath: string, newPath: string) {\n const session = await this.ensureDefaultSession();\n return session.renameFile(oldPath, newPath);\n }\n\n async moveFile(sourcePath: string, destinationPath: string) {\n const session = await this.ensureDefaultSession();\n return session.moveFile(sourcePath, destinationPath);\n }\n\n async readFile(path: string, options: { encoding?: string } = {}) {\n const session = await this.ensureDefaultSession();\n return session.readFile(path, options);\n }\n\n async listFiles(\n path: string,\n options: {\n recursive?: boolean;\n includeHidden?: boolean;\n } = {}\n ) {\n const session = await this.ensureDefaultSession();\n return session.listFiles(path, options);\n }\n\n async exposePort(port: number, options: { name?: string; hostname: string }) {\n await this.client.exposePort(port, options?.name);\n\n // We need the sandbox name to construct preview URLs\n if (!this.sandboxName) {\n throw new Error(\n \"Sandbox name not available. Ensure sandbox is accessed through getSandbox()\"\n );\n }\n\n const url = this.constructPreviewUrl(\n port,\n this.sandboxName,\n options.hostname\n );\n\n return {\n url,\n port,\n name: options?.name,\n };\n }\n\n async unexposePort(port: number) {\n if (!validatePort(port)) {\n logSecurityEvent(\n \"INVALID_PORT_UNEXPOSE\",\n {\n port,\n },\n \"high\"\n );\n throw new SecurityError(\n `Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`\n );\n }\n\n await this.client.unexposePort(port);\n\n logSecurityEvent(\n \"PORT_UNEXPOSED\",\n {\n port,\n },\n \"low\"\n );\n }\n\n async getExposedPorts(hostname: string) {\n const response = await this.client.getExposedPorts();\n\n // We need the sandbox name to construct preview URLs\n if (!this.sandboxName) {\n throw new Error(\n \"Sandbox name not available. Ensure sandbox is accessed through getSandbox()\"\n );\n }\n\n return response.ports.map((port) => ({\n url: this.constructPreviewUrl(port.port, this.sandboxName!, hostname),\n port: port.port,\n name: port.name,\n exposedAt: port.exposedAt,\n }));\n }\n\n private constructPreviewUrl(\n port: number,\n sandboxId: string,\n hostname: string\n ): string {\n if (!validatePort(port)) {\n logSecurityEvent(\n \"INVALID_PORT_REJECTED\",\n {\n port,\n sandboxId,\n hostname,\n },\n \"high\"\n );\n throw new SecurityError(\n `Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`\n );\n }\n\n let sanitizedSandboxId: string;\n try {\n sanitizedSandboxId = sanitizeSandboxId(sandboxId);\n } catch (error) {\n logSecurityEvent(\n \"INVALID_SANDBOX_ID_REJECTED\",\n {\n sandboxId,\n port,\n hostname,\n error: error instanceof Error ? error.message : \"Unknown error\",\n },\n \"high\"\n );\n throw error;\n }\n\n const isLocalhost = isLocalhostPattern(hostname);\n\n if (isLocalhost) {\n // Unified subdomain approach for localhost (RFC 6761)\n const [host, portStr] = hostname.split(\":\");\n const mainPort = portStr || \"80\";\n\n // Use URL constructor for safe URL building\n try {\n const baseUrl = new URL(`http://${host}:${mainPort}`);\n // Construct subdomain safely\n const subdomainHost = `${port}-${sanitizedSandboxId}.${host}`;\n baseUrl.hostname = subdomainHost;\n\n const finalUrl = baseUrl.toString();\n\n logSecurityEvent(\n \"PREVIEW_URL_CONSTRUCTED\",\n {\n port,\n sandboxId: sanitizedSandboxId,\n hostname,\n resultUrl: finalUrl,\n environment: \"localhost\",\n },\n \"low\"\n );\n\n return finalUrl;\n } catch (error) {\n logSecurityEvent(\n \"URL_CONSTRUCTION_FAILED\",\n {\n port,\n sandboxId: sanitizedSandboxId,\n hostname,\n error: error instanceof Error ? error.message : \"Unknown error\",\n },\n \"high\"\n );\n throw new SecurityError(\n `Failed to construct preview URL: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`\n );\n }\n }\n\n // Production subdomain logic - enforce HTTPS\n try {\n // Always use HTTPS for production (non-localhost)\n const protocol = \"https\";\n const baseUrl = new URL(`${protocol}://${hostname}`);\n\n // Construct subdomain safely\n const subdomainHost = `${port}-${sanitizedSandboxId}.${hostname}`;\n baseUrl.hostname = subdomainHost;\n\n const finalUrl = baseUrl.toString();\n\n logSecurityEvent(\n \"PREVIEW_URL_CONSTRUCTED\",\n {\n port,\n sandboxId: sanitizedSandboxId,\n hostname,\n resultUrl: finalUrl,\n environment: \"production\",\n },\n \"low\"\n );\n\n return finalUrl;\n } catch (error) {\n logSecurityEvent(\n \"URL_CONSTRUCTION_FAILED\",\n {\n port,\n sandboxId: sanitizedSandboxId,\n hostname,\n error: error instanceof Error ? error.message : \"Unknown error\",\n },\n \"high\"\n );\n throw new SecurityError(\n `Failed to construct preview URL: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`\n );\n }\n }\n\n // Code Interpreter Methods\n\n /**\n * Create a new code execution context\n */\n async createCodeContext(\n options?: CreateContextOptions\n ): Promise<CodeContext> {\n return this.codeInterpreter.createCodeContext(options);\n }\n\n /**\n * Run code with streaming callbacks\n */\n async runCode(\n code: string,\n options?: RunCodeOptions\n ): Promise<ExecutionResult> {\n const execution = await this.codeInterpreter.runCode(code, options);\n // Convert to plain object for RPC serialization\n return execution.toJSON();\n }\n\n /**\n * Run code and return a streaming response\n */\n async runCodeStream(\n code: string,\n options?: RunCodeOptions\n ): Promise<ReadableStream> {\n return this.codeInterpreter.runCodeStream(code, options);\n }\n\n /**\n * List all code contexts\n */\n async listCodeContexts(): Promise<CodeContext[]> {\n return this.codeInterpreter.listCodeContexts();\n }\n\n /**\n * Delete a code context\n */\n async deleteCodeContext(contextId: string): Promise<void> {\n return this.codeInterpreter.deleteCodeContext(contextId);\n }\n\n // ============================================================================\n // Session Management (Simple Isolation)\n // ============================================================================\n\n /**\n * Create a new execution session with isolation\n * Returns a session object with exec() method\n */\n\n async createSession(options: {\n id?: string;\n env?: Record<string, string>;\n cwd?: string;\n isolation?: boolean;\n }): Promise<ExecutionSession> {\n const sessionId = options.id || `session-${Date.now()}`;\n \n await this.client.createSession({\n id: sessionId,\n env: options.env,\n cwd: options.cwd,\n isolation: options.isolation\n });\n // Return comprehensive ExecutionSession object that implements all ISandbox methods\n return {\n id: sessionId,\n \n // Command execution - clean method names\n exec: async (command: string, options?: ExecOptions) => {\n const result = await this.client.exec(sessionId, command);\n return {\n ...result,\n command,\n duration: 0,\n timestamp: new Date().toISOString()\n };\n },\n \n execStream: async (command: string, options?: StreamOptions) => {\n return await this.client.execStream(sessionId, command);\n },\n \n // Process management - route to session-aware methods\n startProcess: async (command: string, options?: ProcessOptions) => {\n // Use session-specific process management\n const response = await this.client.startProcess(command, sessionId, {\n processId: options?.processId,\n timeout: options?.timeout,\n env: options?.env,\n cwd: options?.cwd,\n encoding: options?.encoding,\n autoCleanup: options?.autoCleanup,\n });\n \n // Convert response to Process object with bound methods\n const process = response.process;\n return {\n id: process.id,\n pid: process.pid,\n command: process.command,\n status: process.status as ProcessStatus,\n startTime: new Date(process.startTime),\n endTime: process.endTime ? new Date(process.endTime) : undefined,\n exitCode: process.exitCode ?? undefined,\n kill: async (signal?: string) => {\n await this.client.killProcess(process.id);\n },\n getStatus: async () => {\n const resp = await this.client.getProcess(process.id);\n return resp.process?.status as ProcessStatus || \"error\";\n },\n getLogs: async () => {\n return await this.client.getProcessLogs(process.id);\n },\n };\n },\n \n listProcesses: async () => {\n // Get processes for this specific session\n const response = await this.client.listProcesses(sessionId);\n \n // Convert to Process objects with bound methods\n return response.processes.map(p => ({\n id: p.id,\n pid: p.pid,\n command: p.command,\n status: p.status as ProcessStatus,\n startTime: new Date(p.startTime),\n endTime: p.endTime ? new Date(p.endTime) : undefined,\n exitCode: p.exitCode ?? undefined,\n kill: async (signal?: string) => {\n await this.client.killProcess(p.id);\n },\n getStatus: async () => {\n const processResp = await this.client.getProcess(p.id);\n return processResp.process?.status as ProcessStatus || \"error\";\n },\n getLogs: async () => {\n return this.client.getProcessLogs(p.id);\n },\n }));\n },\n \n getProcess: async (id: string) => {\n const response = await this.client.getProcess(id);\n if (!response.process) return null;\n \n const p = response.process;\n return {\n id: p.id,\n pid: p.pid,\n command: p.command,\n status: p.status as ProcessStatus,\n startTime: new Date(p.startTime),\n endTime: p.endTime ? new Date(p.endTime) : undefined,\n exitCode: p.exitCode ?? undefined,\n kill: async (signal?: string) => {\n await this.client.killProcess(p.id);\n },\n getStatus: async () => {\n const processResp = await this.client.getProcess(p.id);\n return processResp.process?.status as ProcessStatus || \"error\";\n },\n getLogs: async () => {\n return this.client.getProcessLogs(p.id);\n },\n };\n },\n \n killProcess: async (id: string, signal?: string) => {\n await this.client.killProcess(id);\n },\n \n killAllProcesses: async () => {\n // Kill all processes for this specific session\n const response = await this.client.killAllProcesses(sessionId);\n return response.killedCount;\n },\n \n streamProcessLogs: async (processId: string, options?: { signal?: AbortSignal }) => {\n return await this.client.streamProcessLogs(processId, options);\n },\n \n getProcessLogs: async (id: string) => {\n return await this.client.getProcessLogs(id);\n },\n \n cleanupCompletedProcesses: async () => {\n // This would need a new endpoint to cleanup processes for a specific session\n // For now, return 0 as no cleanup is performed\n return 0;\n },\n \n // File operations - clean method names (no \"InSession\" suffix)\n writeFile: async (path: string, content: string, options?: { encoding?: string }) => {\n return await this.client.writeFile(path, content, options?.encoding, sessionId);\n },\n \n readFile: async (path: string, options?: { encoding?: string }) => {\n return await this.client.readFile(path, options?.encoding, sessionId);\n },\n \n mkdir: async (path: string, options?: { recursive?: boolean }) => {\n return await this.client.mkdir(path, options?.recursive, sessionId);\n },\n \n deleteFile: async (path: string) => {\n return await this.client.deleteFile(path, sessionId);\n },\n \n renameFile: async (oldPath: string, newPath: string) => {\n return await this.client.renameFile(oldPath, newPath, sessionId);\n },\n \n moveFile: async (sourcePath: string, destinationPath: string) => {\n return await this.client.moveFile(sourcePath, destinationPath, sessionId);\n },\n \n listFiles: async (path: string, options?: { recursive?: boolean; includeHidden?: boolean }) => {\n return await this.client.listFiles(path, sessionId, options);\n },\n \n gitCheckout: async (repoUrl: string, options?: { branch?: string; targetDir?: string }) => {\n return await this.client.gitCheckout(repoUrl, sessionId, options?.branch, options?.targetDir);\n },\n \n // Port management\n exposePort: async (port: number, options: { name?: string; hostname: string }) => {\n return await this.exposePort(port, options);\n },\n \n unexposePort: async (port: number) => {\n return await this.unexposePort(port);\n },\n \n getExposedPorts: async (hostname: string) => {\n return await this.getExposedPorts(hostname);\n },\n \n // Environment management\n setEnvVars: async (envVars: Record<string, string>) => {\n // TODO: Implement session-specific environment updates\n console.log(`[Session ${sessionId}] Environment variables update not yet implemented`);\n },\n \n // Code Interpreter API\n createCodeContext: async (options?: any) => {\n return await this.createCodeContext(options);\n },\n \n runCode: async (code: string, options?: any) => {\n return await this.runCode(code, options);\n },\n \n runCodeStream: async (code: string, options?: any) => {\n return await this.runCodeStream(code, options);\n },\n \n listCodeContexts: async () => {\n return await this.listCodeContexts();\n },\n \n deleteCodeContext: async (contextId: string) => {\n return await this.deleteCodeContext(contextId);\n }\n };\n }\n}\n","import { getSandbox, type Sandbox } from \"./sandbox\";\nimport {\n logSecurityEvent,\n sanitizeSandboxId,\n validatePort\n} from \"./security\";\n\nexport interface SandboxEnv {\n Sandbox: DurableObjectNamespace<Sandbox>;\n}\n\nexport interface RouteInfo {\n port: number;\n sandboxId: string;\n path: string;\n}\n\nexport async function proxyToSandbox<E extends SandboxEnv>(\n request: Request,\n env: E\n): Promise<Response | null> {\n try {\n const url = new URL(request.url);\n const routeInfo = extractSandboxRoute(url);\n\n if (!routeInfo) {\n return null; // Not a request to an exposed container port\n }\n\n const { sandboxId, port, path } = routeInfo;\n const sandbox = getSandbox(env.Sandbox, sandboxId);\n\n // Build proxy request with proper headers\n let proxyUrl: string;\n\n // Route based on the target port\n if (port !== 3000) {\n // Route directly to user's service on the specified port\n proxyUrl = `http://localhost:${port}${path}${url.search}`;\n } else {\n // Port 3000 is our control plane - route normally\n proxyUrl = `http://localhost:3000${path}${url.search}`;\n }\n\n const proxyRequest = new Request(proxyUrl, {\n method: request.method,\n headers: {\n ...Object.fromEntries(request.headers),\n 'X-Original-URL': request.url,\n 'X-Forwarded-Host': url.hostname,\n 'X-Forwarded-Proto': url.protocol.replace(':', ''),\n 'X-Sandbox-Name': sandboxId, // Pass the friendly name\n },\n body: request.body,\n });\n\n return sandbox.containerFetch(proxyRequest, port);\n } catch (error) {\n console.error('[Sandbox] Proxy routing error:', error);\n return new Response('Proxy routing error', { status: 500 });\n }\n}\n\nfunction extractSandboxRoute(url: URL): RouteInfo | null {\n // Parse subdomain pattern: port-sandboxId.domain\n const subdomainMatch = url.hostname.match(/^(\\d{4,5})-([^.-][^.]*[^.-]|[^.-])\\.(.+)$/);\n\n if (!subdomainMatch) {\n // Log malformed subdomain attempts\n if (url.hostname.includes('-') && url.hostname.includes('.')) {\n logSecurityEvent('MALFORMED_SUBDOMAIN_ATTEMPT', {\n hostname: url.hostname,\n url: url.toString()\n }, 'medium');\n }\n return null;\n }\n\n const portStr = subdomainMatch[1];\n const sandboxId = subdomainMatch[2];\n const domain = subdomainMatch[3];\n\n const port = parseInt(portStr, 10);\n if (!validatePort(port)) {\n logSecurityEvent('INVALID_PORT_IN_SUBDOMAIN', {\n port,\n portStr,\n sandboxId,\n hostname: url.hostname,\n url: url.toString()\n }, 'high');\n return null;\n }\n\n let sanitizedSandboxId: string;\n try {\n sanitizedSandboxId = sanitizeSandboxId(sandboxId);\n } catch (error) {\n logSecurityEvent('INVALID_SANDBOX_ID_IN_SUBDOMAIN', {\n sandboxId,\n port,\n hostname: url.hostname,\n url: url.toString(),\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'high');\n return null;\n }\n\n // DNS subdomain length limit is 63 characters\n if (sandboxId.length > 63) {\n logSecurityEvent('SANDBOX_ID_LENGTH_VIOLATION', {\n sandboxId,\n length: sandboxId.length,\n port,\n hostname: url.hostname\n }, 'medium');\n return null;\n }\n\n logSecurityEvent('SANDBOX_ROUTE_EXTRACTED', {\n port,\n sandboxId: sanitizedSandboxId,\n domain,\n path: url.pathname || \"/\",\n hostname: url.hostname\n }, 'low');\n\n return {\n port,\n sandboxId: sanitizedSandboxId,\n path: url.pathname || \"/\",\n };\n}\n\nexport function isLocalhostPattern(hostname: string): boolean {\n const hostPart = hostname.split(\":\")[0];\n return (\n hostPart === \"localhost\" ||\n hostPart === \"127.0.0.1\" ||\n hostPart === \"::1\" ||\n hostPart === \"[::1]\" ||\n hostPart === \"0.0.0.0\"\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,WAAW,oBAAoB;;;ACiBxC,eAAsB,eACpB,SACA,KAC0B;AAC1B,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,UAAM,YAAY,oBAAoB,GAAG;AAEzC,QAAI,CAAC,WAAW;AACd,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,WAAW,MAAM,KAAK,IAAI;AAClC,UAAM,UAAU,WAAW,IAAI,SAAS,SAAS;AAGjD,QAAI;AAGJ,QAAI,SAAS,KAAM;AAEjB,iBAAW,oBAAoB,IAAI,GAAG,IAAI,GAAG,IAAI,MAAM;AAAA,IACzD,OAAO;AAEL,iBAAW,wBAAwB,IAAI,GAAG,IAAI,MAAM;AAAA,IACtD;AAEA,UAAM,eAAe,IAAI,QAAQ,UAAU;AAAA,MACzC,QAAQ,QAAQ;AAAA,MAChB,SAAS;AAAA,QACP,GAAG,OAAO,YAAY,QAAQ,OAAO;AAAA,QACrC,kBAAkB,QAAQ;AAAA,QAC1B,oBAAoB,IAAI;AAAA,QACxB,qBAAqB,IAAI,SAAS,QAAQ,KAAK,EAAE;AAAA,QACjD,kBAAkB;AAAA;AAAA,MACpB;AAAA,MACA,MAAM,QAAQ;AAAA,IAChB,CAAC;AAED,WAAO,QAAQ,eAAe,cAAc,IAAI;AAAA,EAClD,SAAS,OAAO;AACd,YAAQ,MAAM,kCAAkC,KAAK;AACrD,WAAO,IAAI,SAAS,uBAAuB,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC5D;AACF;AAEA,SAAS,oBAAoB,KAA4B;AAEvD,QAAM,iBAAiB,IAAI,SAAS,MAAM,2CAA2C;AAErF,MAAI,CAAC,gBAAgB;AAEnB,QAAI,IAAI,SAAS,SAAS,GAAG,KAAK,IAAI,SAAS,SAAS,GAAG,GAAG;AAC5D,uBAAiB,+BAA+B;AAAA,QAC9C,UAAU,IAAI;AAAA,QACd,KAAK,IAAI,SAAS;AAAA,MACpB,GAAG,QAAQ;AAAA,IACb;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,eAAe,CAAC;AAChC,QAAM,YAAY,eAAe,CAAC;AAClC,QAAM,SAAS,eAAe,CAAC;AAE/B,QAAM,OAAO,SAAS,SAAS,EAAE;AACjC,MAAI,CAAC,aAAa,IAAI,GAAG;AACvB,qBAAiB,6BAA6B;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,IAAI;AAAA,MACd,KAAK,IAAI,SAAS;AAAA,IACpB,GAAG,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,yBAAqB,kBAAkB,SAAS;AAAA,EAClD,SAAS,OAAO;AACd,qBAAiB,mCAAmC;AAAA,MAClD;AAAA,MACA;AAAA,MACA,UAAU,IAAI;AAAA,MACd,KAAK,IAAI,SAAS;AAAA,MAClB,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD,GAAG,MAAM;AACT,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,SAAS,IAAI;AACzB,qBAAiB,+BAA+B;AAAA,MAC9C;AAAA,MACA,QAAQ,UAAU;AAAA,MAClB;AAAA,MACA,UAAU,IAAI;AAAA,IAChB,GAAG,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,mBAAiB,2BAA2B;AAAA,IAC1C;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,MAAM,IAAI,YAAY;AAAA,IACtB,UAAU,IAAI;AAAA,EAChB,GAAG,KAAK;AAER,SAAO;AAAA,IACL;AAAA,IACA,WAAW;AAAA,IACX,MAAM,IAAI,YAAY;AAAA,EACxB;AACF;AAEO,SAAS,mBAAmB,UAA2B;AAC5D,QAAM,WAAW,SAAS,MAAM,GAAG,EAAE,CAAC;AACtC,SACE,aAAa,eACb,aAAa,eACb,aAAa,SACb,aAAa,WACb,aAAa;AAEjB;;;ADhHO,SAAS,WAAW,IAAqC,IAAY;AAC1E,QAAM,OAAO,aAAa,IAAI,EAAE;AAGhC,OAAK,iBAAiB,EAAE;AAExB,SAAO;AACT;AAEO,IAAM,UAAN,cAAqC,UAAmC;AAAA,EAC7E,cAAc;AAAA;AAAA,EACd,aAAa;AAAA;AAAA,EACb;AAAA,EACQ,cAA6B;AAAA,EAC7B;AAAA,EACA,iBAA0C;AAAA,EAElD,YAAY,KAAyB,KAAU;AAC7C,UAAM,KAAK,GAAG;AACd,SAAK,SAAS,IAAI,cAAc;AAAA,MAC9B,mBAAmB,CAAC,SAAS,UAAU,SAAS,SAAS,YAAY;AACnE,gBAAQ;AAAA,UACN,kCAAkC,OAAO,cAAc,OAAO,gBAAgB,QAAQ;AAAA,QACxF;AAAA,MACF;AAAA,MACA,gBAAgB,CAAC,YAAY;AAC3B,gBAAQ,IAAI,gCAAgC,OAAO,EAAE;AAAA,MACvD;AAAA,MACA,SAAS,CAAC,OAAO,aAAa;AAC5B,gBAAQ,MAAM,8BAA8B,KAAK,EAAE;AAAA,MACrD;AAAA,MACA,UAAU,CAAC,QAAQ,MAAM,aAAa;AACpC,gBAAQ,IAAI,gBAAgB,MAAM,KAAK,IAAI,EAAE;AAAA,MAC/C;AAAA,MACA,MAAM;AAAA;AAAA,MACN,MAAM;AAAA,IACR,CAAC;AAGD,SAAK,kBAAkB,IAAI,gBAAgB,IAAI;AAG/C,SAAK,IAAI,sBAAsB,YAAY;AACzC,WAAK,cACF,MAAM,KAAK,IAAI,QAAQ,IAAY,aAAa,KAAM;AAAA,IAC3D,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,eAAe,MAA6B;AAChD,QAAI,CAAC,KAAK,aAAa;AACrB,WAAK,cAAc;AACnB,YAAM,KAAK,IAAI,QAAQ,IAAI,eAAe,IAAI;AAC9C,cAAQ,IAAI,0CAA0C,IAAI,EAAE;AAAA,IAC9D;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,WAAW,SAAgD;AAC/D,SAAK,UAAU,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ;AAC7C,YAAQ,IAAI,yCAAyC;AAGrD,QAAI,KAAK,gBAAgB;AACvB,YAAM,KAAK,eAAe,WAAW,OAAO;AAAA,IAC9C;AAAA,EACF;AAAA,EAES,UAAU;AACjB,YAAQ,IAAI,8BAA8B;AAAA,EAC5C;AAAA,EAES,SAAS;AAChB,YAAQ,IAAI,gCAAgC;AAAA,EAC9C;AAAA,EAES,QAAQ,OAAgB;AAC/B,YAAQ,IAAI,kBAAkB,KAAK;AAAA,EACrC;AAAA;AAAA,EAGA,MAAe,MAAM,SAAqC;AACxD,UAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAG/B,QAAI,CAAC,KAAK,eAAe,QAAQ,QAAQ,IAAI,gBAAgB,GAAG;AAC9D,YAAM,OAAO,QAAQ,QAAQ,IAAI,gBAAgB;AACjD,WAAK,cAAc;AACnB,YAAM,KAAK,IAAI,QAAQ,IAAI,eAAe,IAAI;AAC9C,cAAQ,IAAI,kCAAkC,KAAK,WAAW,EAAE;AAAA,IAClE;AAGA,UAAM,OAAO,KAAK,cAAc,GAAG;AAGnC,WAAO,MAAM,KAAK,eAAe,SAAS,IAAI;AAAA,EAChD;AAAA,EAEQ,cAAc,KAAkB;AAEtC,UAAM,aAAa,IAAI,SAAS,MAAM,iBAAiB;AACvD,QAAI,YAAY;AACd,aAAO,SAAS,WAAW,CAAC,CAAC;AAAA,IAC/B;AAIA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,uBAAkD;AAC9D,QAAI,CAAC,KAAK,gBAAgB;AACxB,YAAM,YAAY,WAAW,KAAK,eAAe,SAAS;AAC1D,WAAK,iBAAiB,MAAM,KAAK,cAAc;AAAA,QAC7C,IAAI;AAAA,QACJ,KAAK,KAAK,WAAW,CAAC;AAAA,QACtB,KAAK;AAAA,QACL,WAAW;AAAA,MACb,CAAC;AACD,cAAQ,IAAI,0CAA0C,SAAS,EAAE;AAAA,IACnE;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAGA,MAAM,KAAK,SAAiB,SAA4C;AACtE,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,KAAK,SAAS,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,aACJ,SACA,SACkB;AAClB,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,aAAa,SAAS,OAAO;AAAA,EAC9C;AAAA,EAEA,MAAM,gBAAoC;AACxC,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,cAAc;AAAA,EAC/B;AAAA,EAEA,MAAM,WAAW,IAAqC;AACpD,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,WAAW,EAAE;AAAA,EAC9B;AAAA,EAEA,MAAM,YAAY,IAAY,QAAgC;AAC5D,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,YAAY,IAAI,MAAM;AAAA,EACvC;AAAA,EAEA,MAAM,mBAAoC;AACxC,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,iBAAiB;AAAA,EAClC;AAAA,EAEA,MAAM,4BAA6C;AACjD,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,0BAA0B;AAAA,EAC3C;AAAA,EAEA,MAAM,eACJ,IAC6C;AAC7C,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,eAAe,EAAE;AAAA,EAClC;AAAA;AAAA,EAGA,MAAM,WACJ,SACA,SACqC;AACrC,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,WAAW,SAAS,OAAO;AAAA,EAC5C;AAAA,EAEA,MAAM,kBACJ,WACA,SACqC;AACrC,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,kBAAkB,WAAW,OAAO;AAAA,EACrD;AAAA,EAEA,MAAM,YACJ,SACA,SACA;AACA,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,YAAY,SAAS,OAAO;AAAA,EAC7C;AAAA,EAEA,MAAM,MAAM,MAAc,UAAmC,CAAC,GAAG;AAC/D,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,MAAM,MAAM,OAAO;AAAA,EACpC;AAAA,EAEA,MAAM,UACJ,MACA,SACA,UAAiC,CAAC,GAClC;AACA,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,UAAU,MAAM,SAAS,OAAO;AAAA,EACjD;AAAA,EAEA,MAAM,WAAW,MAAc;AAC7B,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,WAAW,IAAI;AAAA,EAChC;AAAA,EAEA,MAAM,WAAW,SAAiB,SAAiB;AACjD,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,WAAW,SAAS,OAAO;AAAA,EAC5C;AAAA,EAEA,MAAM,SAAS,YAAoB,iBAAyB;AAC1D,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,SAAS,YAAY,eAAe;AAAA,EACrD;AAAA,EAEA,MAAM,SAAS,MAAc,UAAiC,CAAC,GAAG;AAChE,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,SAAS,MAAM,OAAO;AAAA,EACvC;AAAA,EAEA,MAAM,UACJ,MACA,UAGI,CAAC,GACL;AACA,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,UAAU,MAAM,OAAO;AAAA,EACxC;AAAA,EAEA,MAAM,WAAW,MAAc,SAA8C;AAC3E,UAAM,KAAK,OAAO,WAAW,MAAM,SAAS,IAAI;AAGhD,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL,QAAQ;AAAA,IACV;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,MAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,MAAc;AAC/B,QAAI,CAAC,aAAa,IAAI,GAAG;AACvB;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,wBAAwB,IAAI;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,KAAK,OAAO,aAAa,IAAI;AAEnC;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,UAAkB;AACtC,UAAM,WAAW,MAAM,KAAK,OAAO,gBAAgB;AAGnD,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO,SAAS,MAAM,IAAI,CAAC,UAAU;AAAA,MACnC,KAAK,KAAK,oBAAoB,KAAK,MAAM,KAAK,aAAc,QAAQ;AAAA,MACpE,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,WAAW,KAAK;AAAA,IAClB,EAAE;AAAA,EACJ;AAAA,EAEQ,oBACN,MACA,WACA,UACQ;AACR,QAAI,CAAC,aAAa,IAAI,GAAG;AACvB;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,wBAAwB,IAAI;AAAA,MAC9B;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,2BAAqB,kBAAkB,SAAS;AAAA,IAClD,SAAS,OAAO;AACd;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD;AAAA,QACA;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAEA,UAAM,cAAc,mBAAmB,QAAQ;AAE/C,QAAI,aAAa;AAEf,YAAM,CAAC,MAAM,OAAO,IAAI,SAAS,MAAM,GAAG;AAC1C,YAAM,WAAW,WAAW;AAG5B,UAAI;AACF,cAAM,UAAU,IAAI,IAAI,UAAU,IAAI,IAAI,QAAQ,EAAE;AAEpD,cAAM,gBAAgB,GAAG,IAAI,IAAI,kBAAkB,IAAI,IAAI;AAC3D,gBAAQ,WAAW;AAEnB,cAAM,WAAW,QAAQ,SAAS;AAElC;AAAA,UACE;AAAA,UACA;AAAA,YACE;AAAA,YACA,WAAW;AAAA,YACX;AAAA,YACA,WAAW;AAAA,YACX,aAAa;AAAA,UACf;AAAA,UACA;AAAA,QACF;AAEA,eAAO;AAAA,MACT,SAAS,OAAO;AACd;AAAA,UACE;AAAA,UACA;AAAA,YACE;AAAA,YACA,WAAW;AAAA,YACX;AAAA,YACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,UAClD;AAAA,UACA;AAAA,QACF;AACA,cAAM,IAAI;AAAA,UACR,oCACE,iBAAiB,QAAQ,MAAM,UAAU,eAC3C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI;AAEF,YAAM,WAAW;AACjB,YAAM,UAAU,IAAI,IAAI,GAAG,QAAQ,MAAM,QAAQ,EAAE;AAGnD,YAAM,gBAAgB,GAAG,IAAI,IAAI,kBAAkB,IAAI,QAAQ;AAC/D,cAAQ,WAAW;AAEnB,YAAM,WAAW,QAAQ,SAAS;AAElC;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA,WAAW;AAAA,UACX;AAAA,UACA,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA,WAAW;AAAA,UACX;AAAA,UACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD;AAAA,QACA;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,oCACE,iBAAiB,QAAQ,MAAM,UAAU,eAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBACJ,SACsB;AACtB,WAAO,KAAK,gBAAgB,kBAAkB,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QACJ,MACA,SAC0B;AAC1B,UAAM,YAAY,MAAM,KAAK,gBAAgB,QAAQ,MAAM,OAAO;AAElE,WAAO,UAAU,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cACJ,MACA,SACyB;AACzB,WAAO,KAAK,gBAAgB,cAAc,MAAM,OAAO;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAA2C;AAC/C,WAAO,KAAK,gBAAgB,iBAAiB;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,WAAkC;AACxD,WAAO,KAAK,gBAAgB,kBAAkB,SAAS;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,cAAc,SAKU;AAC5B,UAAM,YAAY,QAAQ,MAAM,WAAW,KAAK,IAAI,CAAC;AAErD,UAAM,KAAK,OAAO,cAAc;AAAA,MAC9B,IAAI;AAAA,MACJ,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,MACb,WAAW,QAAQ;AAAA,IACrB,CAAC;AAED,WAAO;AAAA,MACL,IAAI;AAAA;AAAA,MAGJ,MAAM,OAAO,SAAiBA,aAA0B;AACtD,cAAM,SAAS,MAAM,KAAK,OAAO,KAAK,WAAW,OAAO;AACxD,eAAO;AAAA,UACL,GAAG;AAAA,UACH;AAAA,UACA,UAAU;AAAA,UACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,MACF;AAAA,MAEA,YAAY,OAAO,SAAiBA,aAA4B;AAC9D,eAAO,MAAM,KAAK,OAAO,WAAW,WAAW,OAAO;AAAA,MACxD;AAAA;AAAA,MAGA,cAAc,OAAO,SAAiBA,aAA6B;AAEjE,cAAM,WAAW,MAAM,KAAK,OAAO,aAAa,SAAS,WAAW;AAAA,UAClE,WAAWA,UAAS;AAAA,UACpB,SAASA,UAAS;AAAA,UAClB,KAAKA,UAAS;AAAA,UACd,KAAKA,UAAS;AAAA,UACd,UAAUA,UAAS;AAAA,UACnB,aAAaA,UAAS;AAAA,QACxB,CAAC;AAGD,cAAM,UAAU,SAAS;AACzB,eAAO;AAAA,UACL,IAAI,QAAQ;AAAA,UACZ,KAAK,QAAQ;AAAA,UACb,SAAS,QAAQ;AAAA,UACjB,QAAQ,QAAQ;AAAA,UAChB,WAAW,IAAI,KAAK,QAAQ,SAAS;AAAA,UACrC,SAAS,QAAQ,UAAU,IAAI,KAAK,QAAQ,OAAO,IAAI;AAAA,UACvD,UAAU,QAAQ,YAAY;AAAA,UAC9B,MAAM,OAAO,WAAoB;AAC/B,kBAAM,KAAK,OAAO,YAAY,QAAQ,EAAE;AAAA,UAC1C;AAAA,UACA,WAAW,YAAY;AACrB,kBAAM,OAAO,MAAM,KAAK,OAAO,WAAW,QAAQ,EAAE;AACpD,mBAAO,KAAK,SAAS,UAA2B;AAAA,UAClD;AAAA,UACA,SAAS,YAAY;AACnB,mBAAO,MAAM,KAAK,OAAO,eAAe,QAAQ,EAAE;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AAAA,MAEA,eAAe,YAAY;AAEzB,cAAM,WAAW,MAAM,KAAK,OAAO,cAAc,SAAS;AAG1D,eAAO,SAAS,UAAU,IAAI,QAAM;AAAA,UAClC,IAAI,EAAE;AAAA,UACN,KAAK,EAAE;AAAA,UACP,SAAS,EAAE;AAAA,UACX,QAAQ,EAAE;AAAA,UACV,WAAW,IAAI,KAAK,EAAE,SAAS;AAAA,UAC/B,SAAS,EAAE,UAAU,IAAI,KAAK,EAAE,OAAO,IAAI;AAAA,UAC3C,UAAU,EAAE,YAAY;AAAA,UACxB,MAAM,OAAO,WAAoB;AAC/B,kBAAM,KAAK,OAAO,YAAY,EAAE,EAAE;AAAA,UACpC;AAAA,UACA,WAAW,YAAY;AACrB,kBAAM,cAAc,MAAM,KAAK,OAAO,WAAW,EAAE,EAAE;AACrD,mBAAO,YAAY,SAAS,UAA2B;AAAA,UACzD;AAAA,UACA,SAAS,YAAY;AACnB,mBAAO,KAAK,OAAO,eAAe,EAAE,EAAE;AAAA,UACxC;AAAA,QACF,EAAE;AAAA,MACJ;AAAA,MAEA,YAAY,OAAO,OAAe;AAChC,cAAM,WAAW,MAAM,KAAK,OAAO,WAAW,EAAE;AAChD,YAAI,CAAC,SAAS,QAAS,QAAO;AAE9B,cAAM,IAAI,SAAS;AACnB,eAAO;AAAA,UACL,IAAI,EAAE;AAAA,UACN,KAAK,EAAE;AAAA,UACP,SAAS,EAAE;AAAA,UACX,QAAQ,EAAE;AAAA,UACV,WAAW,IAAI,KAAK,EAAE,SAAS;AAAA,UAC/B,SAAS,EAAE,UAAU,IAAI,KAAK,EAAE,OAAO,IAAI;AAAA,UAC3C,UAAU,EAAE,YAAY;AAAA,UACxB,MAAM,OAAO,WAAoB;AAC/B,kBAAM,KAAK,OAAO,YAAY,EAAE,EAAE;AAAA,UACpC;AAAA,UACA,WAAW,YAAY;AACrB,kBAAM,cAAc,MAAM,KAAK,OAAO,WAAW,EAAE,EAAE;AACrD,mBAAO,YAAY,SAAS,UAA2B;AAAA,UACzD;AAAA,UACA,SAAS,YAAY;AACnB,mBAAO,KAAK,OAAO,eAAe,EAAE,EAAE;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,MAEA,aAAa,OAAO,IAAY,WAAoB;AAClD,cAAM,KAAK,OAAO,YAAY,EAAE;AAAA,MAClC;AAAA,MAEA,kBAAkB,YAAY;AAE5B,cAAM,WAAW,MAAM,KAAK,OAAO,iBAAiB,SAAS;AAC7D,eAAO,SAAS;AAAA,MAClB;AAAA,MAEA,mBAAmB,OAAO,WAAmBA,aAAuC;AAClF,eAAO,MAAM,KAAK,OAAO,kBAAkB,WAAWA,QAAO;AAAA,MAC/D;AAAA,MAEA,gBAAgB,OAAO,OAAe;AACpC,eAAO,MAAM,KAAK,OAAO,eAAe,EAAE;AAAA,MAC5C;AAAA,MAEA,2BAA2B,YAAY;AAGrC,eAAO;AAAA,MACT;AAAA;AAAA,MAGA,WAAW,OAAO,MAAc,SAAiBA,aAAoC;AACnF,eAAO,MAAM,KAAK,OAAO,UAAU,MAAM,SAASA,UAAS,UAAU,SAAS;AAAA,MAChF;AAAA,MAEA,UAAU,OAAO,MAAcA,aAAoC;AACjE,eAAO,MAAM,KAAK,OAAO,SAAS,MAAMA,UAAS,UAAU,SAAS;AAAA,MACtE;AAAA,MAEA,OAAO,OAAO,MAAcA,aAAsC;AAChE,eAAO,MAAM,KAAK,OAAO,MAAM,MAAMA,UAAS,WAAW,SAAS;AAAA,MACpE;AAAA,MAEA,YAAY,OAAO,SAAiB;AAClC,eAAO,MAAM,KAAK,OAAO,WAAW,MAAM,SAAS;AAAA,MACrD;AAAA,MAEA,YAAY,OAAO,SAAiB,YAAoB;AACtD,eAAO,MAAM,KAAK,OAAO,WAAW,SAAS,SAAS,SAAS;AAAA,MACjE;AAAA,MAEA,UAAU,OAAO,YAAoB,oBAA4B;AAC/D,eAAO,MAAM,KAAK,OAAO,SAAS,YAAY,iBAAiB,SAAS;AAAA,MAC1E;AAAA,MAEA,WAAW,OAAO,MAAcA,aAA+D;AAC7F,eAAO,MAAM,KAAK,OAAO,UAAU,MAAM,WAAWA,QAAO;AAAA,MAC7D;AAAA,MAEA,aAAa,OAAO,SAAiBA,aAAsD;AACzF,eAAO,MAAM,KAAK,OAAO,YAAY,SAAS,WAAWA,UAAS,QAAQA,UAAS,SAAS;AAAA,MAC9F;AAAA;AAAA,MAGA,YAAY,OAAO,MAAcA,aAAiD;AAChF,eAAO,MAAM,KAAK,WAAW,MAAMA,QAAO;AAAA,MAC5C;AAAA,MAEA,cAAc,OAAO,SAAiB;AACpC,eAAO,MAAM,KAAK,aAAa,IAAI;AAAA,MACrC;AAAA,MAEA,iBAAiB,OAAO,aAAqB;AAC3C,eAAO,MAAM,KAAK,gBAAgB,QAAQ;AAAA,MAC5C;AAAA;AAAA,MAGA,YAAY,OAAO,YAAoC;AAErD,gBAAQ,IAAI,YAAY,SAAS,oDAAoD;AAAA,MACvF;AAAA;AAAA,MAGA,mBAAmB,OAAOA,aAAkB;AAC1C,eAAO,MAAM,KAAK,kBAAkBA,QAAO;AAAA,MAC7C;AAAA,MAEA,SAAS,OAAO,MAAcA,aAAkB;AAC9C,eAAO,MAAM,KAAK,QAAQ,MAAMA,QAAO;AAAA,MACzC;AAAA,MAEA,eAAe,OAAO,MAAcA,aAAkB;AACpD,eAAO,MAAM,KAAK,cAAc,MAAMA,QAAO;AAAA,MAC/C;AAAA,MAEA,kBAAkB,YAAY;AAC5B,eAAO,MAAM,KAAK,iBAAiB;AAAA,MACrC;AAAA,MAEA,mBAAmB,OAAO,cAAsB;AAC9C,eAAO,MAAM,KAAK,kBAAkB,SAAS;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACF;","names":["options"]}