@animalabs/membrane 0.5.44 → 0.5.46

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 (35) hide show
  1. package/dist/formatters/index.d.ts +0 -1
  2. package/dist/formatters/index.js +0 -1
  3. package/dist/formatters/index.js.map +1 -1
  4. package/dist/formatters/types.d.ts +0 -4
  5. package/dist/providers/bedrock.d.ts.map +1 -1
  6. package/dist/providers/bedrock.js +44 -7
  7. package/dist/providers/bedrock.js.map +1 -1
  8. package/dist/providers/gemini.js +11 -2
  9. package/dist/providers/gemini.js.map +1 -1
  10. package/dist/providers/openai-compatible.js +25 -15
  11. package/dist/providers/openai-compatible.js.map +1 -1
  12. package/dist/providers/openai-completions.js +48 -24
  13. package/dist/providers/openai-completions.js.map +1 -1
  14. package/dist/providers/openai-responses.js +6 -1
  15. package/dist/providers/openai-responses.js.map +1 -1
  16. package/dist/providers/openai.js +25 -15
  17. package/dist/providers/openai.js.map +1 -1
  18. package/dist/providers/openrouter.js +35 -16
  19. package/dist/providers/openrouter.js.map +1 -1
  20. package/dist/providers/utils.d.ts +38 -0
  21. package/dist/providers/utils.d.ts.map +1 -1
  22. package/dist/providers/utils.js +86 -0
  23. package/dist/providers/utils.js.map +1 -1
  24. package/dist/types/request.d.ts +8 -0
  25. package/dist/types/request.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/providers/bedrock.ts +40 -3
  28. package/dist/formatters/pseudo-prefill.d.ts +0 -71
  29. package/dist/formatters/pseudo-prefill.d.ts.map +0 -1
  30. package/dist/formatters/pseudo-prefill.js +0 -410
  31. package/dist/formatters/pseudo-prefill.js.map +0 -1
  32. package/dist/transforms/prefill.d.ts +0 -89
  33. package/dist/transforms/prefill.d.ts.map +0 -1
  34. package/dist/transforms/prefill.js +0 -390
  35. package/dist/transforms/prefill.js.map +0 -1
@@ -3,4 +3,42 @@
3
3
  * Used for tool call arguments which may be malformed from streaming.
4
4
  */
5
5
  export declare function safeParseJson(str: string | undefined): Record<string, unknown>;
6
+ /**
7
+ * Create a combined AbortSignal that fires on either the caller's signal
8
+ * or a timeout (whichever comes first).
9
+ *
10
+ * The returned `cleanup` function MUST be called in a `finally` block to
11
+ * clear the timeout and remove the event listener, preventing leaks.
12
+ *
13
+ * Timeout aborts with `DOMException('Request timed out', 'AbortError')`
14
+ * so it classifies identically to user-initiated aborts.
15
+ */
16
+ export declare function createCombinedSignal(signal?: AbortSignal, timeoutMs?: number): {
17
+ signal?: AbortSignal;
18
+ cleanup?: () => void;
19
+ };
20
+ /**
21
+ * SSE (Server-Sent Events) line parser that correctly handles events
22
+ * split across multiple TCP chunks.
23
+ *
24
+ * The naive approach of `chunk.split('\n').filter(l => l.startsWith('data: '))`
25
+ * silently drops events when an SSE line spans two chunks:
26
+ * Chunk 1: `data: {"choices":[{"delta":{"content":"don'` (no newline — incomplete)
27
+ * Chunk 2: `t do that"}}]}\n` (doesn't start with `data: `)
28
+ * Result: the entire event is lost, causing "skipped words" in output.
29
+ *
30
+ * This parser buffers partial lines and only yields complete `data: ...` lines.
31
+ */
32
+ export declare class SSELineParser {
33
+ private buffer;
34
+ /**
35
+ * Feed a raw chunk from the stream reader and get back complete SSE data lines.
36
+ * Each returned string is the content after `data: ` (e.g. the JSON payload or `[DONE]`).
37
+ */
38
+ feed(chunk: string): string[];
39
+ /**
40
+ * Flush any remaining buffered content (call when stream ends).
41
+ */
42
+ flush(): string[];
43
+ }
6
44
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/providers/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO9E"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/providers/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO9E;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,CAAC,EAAE,WAAW,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,CA8BhD;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAE5B;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAmB7B;;OAEG;IACH,KAAK,IAAI,MAAM,EAAE;CASlB"}
@@ -11,4 +11,90 @@ export function safeParseJson(str) {
11
11
  return {};
12
12
  }
13
13
  }
14
+ /**
15
+ * Create a combined AbortSignal that fires on either the caller's signal
16
+ * or a timeout (whichever comes first).
17
+ *
18
+ * The returned `cleanup` function MUST be called in a `finally` block to
19
+ * clear the timeout and remove the event listener, preventing leaks.
20
+ *
21
+ * Timeout aborts with `DOMException('Request timed out', 'AbortError')`
22
+ * so it classifies identically to user-initiated aborts.
23
+ */
24
+ export function createCombinedSignal(signal, timeoutMs) {
25
+ if (!signal && !timeoutMs)
26
+ return {};
27
+ if (signal && !timeoutMs)
28
+ return { signal };
29
+ const controller = new AbortController();
30
+ let timeoutId;
31
+ if (timeoutMs) {
32
+ timeoutId = setTimeout(() => controller.abort(new DOMException('Request timed out', 'AbortError')), timeoutMs);
33
+ }
34
+ const onAbort = () => controller.abort(signal.reason);
35
+ if (signal) {
36
+ if (signal.aborted) {
37
+ controller.abort(signal.reason);
38
+ }
39
+ else {
40
+ signal.addEventListener('abort', onAbort, { once: true });
41
+ }
42
+ }
43
+ return {
44
+ signal: controller.signal,
45
+ cleanup: () => {
46
+ if (timeoutId)
47
+ clearTimeout(timeoutId);
48
+ if (signal)
49
+ signal.removeEventListener('abort', onAbort);
50
+ },
51
+ };
52
+ }
53
+ /**
54
+ * SSE (Server-Sent Events) line parser that correctly handles events
55
+ * split across multiple TCP chunks.
56
+ *
57
+ * The naive approach of `chunk.split('\n').filter(l => l.startsWith('data: '))`
58
+ * silently drops events when an SSE line spans two chunks:
59
+ * Chunk 1: `data: {"choices":[{"delta":{"content":"don'` (no newline — incomplete)
60
+ * Chunk 2: `t do that"}}]}\n` (doesn't start with `data: `)
61
+ * Result: the entire event is lost, causing "skipped words" in output.
62
+ *
63
+ * This parser buffers partial lines and only yields complete `data: ...` lines.
64
+ */
65
+ export class SSELineParser {
66
+ buffer = '';
67
+ /**
68
+ * Feed a raw chunk from the stream reader and get back complete SSE data lines.
69
+ * Each returned string is the content after `data: ` (e.g. the JSON payload or `[DONE]`).
70
+ */
71
+ feed(chunk) {
72
+ this.buffer += chunk;
73
+ const results = [];
74
+ // Split on newlines, keeping the last (potentially incomplete) segment in the buffer
75
+ const lines = this.buffer.split('\n');
76
+ this.buffer = lines.pop() || '';
77
+ for (const line of lines) {
78
+ const trimmed = line.trim();
79
+ if (trimmed.startsWith('data: ')) {
80
+ results.push(trimmed.slice(6));
81
+ }
82
+ // Skip empty lines, comments (`:...`), and other SSE fields (event:, id:, retry:)
83
+ }
84
+ return results;
85
+ }
86
+ /**
87
+ * Flush any remaining buffered content (call when stream ends).
88
+ */
89
+ flush() {
90
+ if (!this.buffer.trim())
91
+ return [];
92
+ const trimmed = this.buffer.trim();
93
+ this.buffer = '';
94
+ if (trimmed.startsWith('data: ')) {
95
+ return [trimmed.slice(6)];
96
+ }
97
+ return [];
98
+ }
99
+ }
14
100
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/providers/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,iDAAiD,EAAE,CAAC,CAAC,CAAC;QACnE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/providers/utils.ts"],"names":[],"mappings":"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"}
@@ -102,6 +102,14 @@ export interface NormalizedRequest {
102
102
  * Default: 'Claude'
103
103
  */
104
104
  assistantParticipant?: string;
105
+ /**
106
+ * Control streaming behavior when calling membrane.stream().
107
+ * - true or undefined: use streaming (default)
108
+ * - false: force non-streaming — membrane.stream() will internally use
109
+ * complete() and synthesize streaming callbacks from the full response.
110
+ * Useful for working around provider streaming bugs.
111
+ */
112
+ streaming?: boolean;
105
113
  /** Provider-specific parameters (pass-through) */
106
114
  providerParams?: Record<string, unknown>;
107
115
  }
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/types/request.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjD,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IAEd,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAElB,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,2CAA2C;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,qCAAqC;IACrC,QAAQ,CAAC,EAAE;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IAEF,uCAAuC;IACvC,eAAe,CAAC,EAAE;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;QACjC,WAAW,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;QACtD,SAAS,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;KAC1C,CAAC;CACH;AAMD,MAAM,MAAM,oBAAoB,GAC5B,MAAM,GACN,YAAY,GACZ,oBAAoB,CAAC;AAEzB,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IAEpB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAEhC,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAMD,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAMD,MAAM,MAAM,QAAQ,GAChB,KAAK,GACL,QAAQ,GACR,MAAM,CAAC;AAMX,MAAM,WAAW,iBAAiB;IAChC,4BAA4B;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAE9B,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,+BAA+B;IAC/B,MAAM,EAAE,gBAAgB,CAAC;IAEzB,uBAAuB;IACvB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IAEzB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB,kCAAkC;IAClC,aAAa,CAAC,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAAC;IAE9C;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/types/request.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animalabs/membrane",
3
- "version": "0.5.44",
3
+ "version": "0.5.46",
4
4
  "description": "LLM middleware - a selective boundary that transforms what passes through",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -533,8 +533,9 @@ export class BedrockAdapter implements ProviderAdapter {
533
533
  const payloadEnd = totalLength - 4;
534
534
  const payloadBytes = buffer.slice(payloadStart, payloadEnd);
535
535
 
536
- // Parse headers to find event type
536
+ // Parse headers to find event type and exception type
537
537
  let eventType = '';
538
+ let exceptionType = '';
538
539
  let headerOffset = 12;
539
540
  const headerEnd = 12 + headersLength;
540
541
  while (headerOffset < headerEnd) {
@@ -554,6 +555,8 @@ export class BedrockAdapter implements ProviderAdapter {
554
555
 
555
556
  if (name === ':event-type') {
556
557
  eventType = value;
558
+ } else if (name === ':exception-type') {
559
+ exceptionType = value;
557
560
  }
558
561
  } else {
559
562
  // Skip other header types
@@ -561,6 +564,21 @@ export class BedrockAdapter implements ProviderAdapter {
561
564
  }
562
565
  }
563
566
 
567
+ // Handle exception events from Bedrock (throttling, model errors, etc.)
568
+ if (exceptionType) {
569
+ let errorMessage = exceptionType;
570
+ try {
571
+ const exPayload = JSON.parse(new TextDecoder().decode(payloadBytes));
572
+ errorMessage = exPayload.message || exPayload.Message || exceptionType;
573
+ } catch {
574
+ // Use exception type as message
575
+ }
576
+ throw new BedrockError(
577
+ exceptionType.toLowerCase().includes('throttl') ? 429 : 500,
578
+ `Bedrock stream error (${exceptionType}): ${errorMessage}`
579
+ );
580
+ }
581
+
564
582
  // Parse the JSON payload
565
583
  if (eventType === 'chunk' && payloadBytes.length > 0) {
566
584
  try {
@@ -575,6 +593,14 @@ export class BedrockAdapter implements ProviderAdapter {
575
593
  }
576
594
  const eventData = JSON.parse(new TextDecoder().decode(bytes)) as BedrockStreamEvent;
577
595
 
596
+ // Check for error events within the stream
597
+ if (eventData.type === 'error') {
598
+ throw new BedrockError(
599
+ 500,
600
+ `Bedrock stream error: ${(eventData as any).error?.message || JSON.stringify(eventData)}`
601
+ );
602
+ }
603
+
578
604
  if (eventData.type === 'message_start' && eventData.message) {
579
605
  inputTokens = eventData.message.usage?.input_tokens ?? 0;
580
606
  } else if (eventData.type === 'content_block_start') {
@@ -607,8 +633,11 @@ export class BedrockAdapter implements ProviderAdapter {
607
633
  }
608
634
  }
609
635
  }
610
- } catch {
611
- // Skip malformed events
636
+ } catch (e) {
637
+ // Re-throw BedrockErrors (from error events above)
638
+ if (e instanceof BedrockError) throw e;
639
+ // Skip genuinely malformed events (e.g. truncated JSON)
640
+ console.warn('[membrane:bedrock] Skipping malformed stream event:', e);
612
641
  }
613
642
  }
614
643
 
@@ -620,6 +649,14 @@ export class BedrockAdapter implements ProviderAdapter {
620
649
  reader.releaseLock();
621
650
  }
622
651
 
652
+ // Detect empty responses — Bedrock returned no content and no tokens
653
+ if (contentBlocks.length === 0 && inputTokens === 0 && outputTokens === 0) {
654
+ throw new BedrockError(
655
+ 500,
656
+ 'Bedrock returned empty response: no content blocks, 0 input/output tokens. This may indicate a transient service issue.'
657
+ );
658
+ }
659
+
623
660
  // Build response from accumulated data
624
661
  finalMessage = {
625
662
  id: 'msg_stream',
@@ -1,71 +0,0 @@
1
- /**
2
- * Pseudo-Prefill Formatter
3
- *
4
- * Recovers prefill-like behavior for models that don't support native
5
- * assistant message prefill (e.g., Sonnet 4.6, Opus 4.6). Uses a CLI
6
- * simulation framing trick:
7
- *
8
- * System: "The assistant is in CLI simulation mode..."
9
- * User: "<cmd>cut -c 1-N < conversation.txt</cmd>"
10
- * Assistant: <the full conversation log, N chars>
11
- * User: "<cmd>cat conversation.txt</cmd>" (or cut -c N+1-)
12
- * <model continues from where the cut output ended>
13
- *
14
- * Two continuation modes:
15
- * - 'cat': model repeats full file then continues (reliable, caller strips log)
16
- * - 'tail-cut': model outputs only new content (efficient, needs simulated stops)
17
- *
18
- * IMPORTANT: API-level stop sequences should NOT be used with pseudo-prefill.
19
- * In 'cat' mode, the model repeats participant names from the log which would
20
- * trigger stops prematurely. The caller should handle stop sequences post-facto
21
- * after stripping the repeated log. The stop sequences returned in BuildResult
22
- * are for the caller's post-facto detection, not for the API.
23
- *
24
- * Uses PassthroughParser and native API tools (same as NativeFormatter).
25
- */
26
- import type { NormalizedMessage, ContentBlock, ToolCall, ToolResult } from '../types/index.js';
27
- import type { PrefillFormatter, StreamParser, BuildOptions, BuildResult, FormatterConfig } from './types.js';
28
- export interface PseudoPrefillFormatterConfig extends FormatterConfig {
29
- /**
30
- * Filename used in the CLI simulation commands.
31
- * Default: 'conversation.txt'
32
- */
33
- filename?: string;
34
- /**
35
- * Continuation mode:
36
- * - 'cat': `cat filename` — model repeats full file then continues.
37
- * More reliable but uses more output tokens. Caller must strip the
38
- * repeated conversation log from the response.
39
- * - 'tail-cut': `cut -c N+1- < filename` — model outputs only new content.
40
- * More efficient but may be less reliable. Caller needs simulated stop
41
- * sequences (only after \n\n, not at position 0).
42
- * Default: 'cat'
43
- */
44
- continuationMode?: 'cat' | 'tail-cut';
45
- /**
46
- * Maximum participants to include in stop sequences.
47
- * Default: 10
48
- */
49
- maxParticipantsForStop?: number;
50
- /**
51
- * Message delimiter between participant entries.
52
- * Default: '' (none, just newlines)
53
- */
54
- messageDelimiter?: string;
55
- }
56
- export declare class PseudoPrefillFormatter implements PrefillFormatter {
57
- readonly name = "pseudo-prefill";
58
- readonly usesPrefill = false;
59
- private config;
60
- constructor(config?: PseudoPrefillFormatterConfig);
61
- buildMessages(messages: NormalizedMessage[], options: BuildOptions): BuildResult;
62
- formatToolResults(results: ToolResult[]): string;
63
- createStreamParser(): StreamParser;
64
- parseToolCalls(_content: string): ToolCall[];
65
- hasToolUse(_content: string): boolean;
66
- parseContentBlocks(content: string): ContentBlock[];
67
- private extractContent;
68
- private buildStopSequences;
69
- private convertToNativeTools;
70
- }
71
- //# sourceMappingURL=pseudo-prefill.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pseudo-prefill.d.ts","sourceRoot":"","sources":["../../src/formatters/pseudo-prefill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EAEZ,QAAQ,EACR,UAAU,EACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,eAAe,EAMhB,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,4BAA6B,SAAQ,eAAe;IACnE;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC;IAEtC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAqGD,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,QAAQ,CAAC,IAAI,oBAAoB;IACjC,QAAQ,CAAC,WAAW,SAAS;IAE7B,OAAO,CAAC,MAAM,CAAyC;gBAE3C,MAAM,GAAE,4BAAiC;IAerD,aAAa,CAAC,QAAQ,EAAE,iBAAiB,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,WAAW;IA+NhF,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM;IAahD,kBAAkB,IAAI,YAAY;IAIlC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE;IAK5C,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKrC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE;IAWnD,OAAO,CAAC,cAAc;IAqCtB,OAAO,CAAC,kBAAkB;IA8B1B,OAAO,CAAC,oBAAoB;CAO7B"}