prefix-safe-json 0.4.4 → 0.4.5

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.
@@ -35,6 +35,7 @@ export declare class AnthropicStreamAdapter implements ProviderStreamAdapter<unk
35
35
  readonly provider: ProviderName;
36
36
  private sequence;
37
37
  private finished;
38
+ private terminatedBlockIndices;
38
39
  push(rawEvent: unknown): readonly NormalizedToolStreamEvent[];
39
40
  finish(meta?: {
40
41
  reason?: StreamEndReason;
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,UAAU,+BAA+B;IACvC,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QACL,IAAI,EAAE,kBAAkB,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,UAAU,+BAA+B;IACvC,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE;QACb,IAAI,EAAE,UAAU,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,UAAU,8BAA8B;IACtC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,0BAA0B;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE;QACL,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,MAAM,cAAc,GACtB,+BAA+B,GAC/B,+BAA+B,GAC/B,8BAA8B,GAC9B,0BAA0B,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE7C,qBAAa,sBAAuB,YAAW,qBAAqB,CAAC,OAAO,CAAC;IAC3E,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAe;IAC9C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAS;IAEzB,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,yBAAyB,EAAE;IAyG7D,MAAM,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,eAAe,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,yBAAyB,EAAE;CAW3G"}
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAMrD,UAAU,+BAA+B;IACvC,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QACL,IAAI,EAAE,kBAAkB,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,UAAU,+BAA+B;IACvC,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE;QACb,IAAI,EAAE,UAAU,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,UAAU,8BAA8B;IACtC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,0BAA0B;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE;QACL,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,MAAM,cAAc,GACtB,+BAA+B,GAC/B,+BAA+B,GAC/B,8BAA8B,GAC9B,0BAA0B,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE7C,qBAAa,sBAAuB,YAAW,qBAAqB,CAAC,OAAO,CAAC;IAC3E,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAe;IAC9C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAS;IAgBzB,OAAO,CAAC,sBAAsB,CAA0B;IAExD,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,yBAAyB,EAAE;IAwK7D,MAAM,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,eAAe,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,yBAAyB,EAAE;CAW3G"}
@@ -1,10 +1,38 @@
1
+ import { TOOL_ARGUMENTS_AFTER_END_DIAGNOSTIC_CODE, DUPLICATE_TOOL_END_DIAGNOSTIC_CODE, } from "../coordinator/diagnostic-codes.js";
1
2
  export class AnthropicStreamAdapter {
2
3
  provider = "anthropic";
3
4
  sequence = 0;
4
5
  finished = false;
6
+ // Block-local terminal state (P4.2 / F-1): every content-block index that
7
+ // has already received its own content_block_stop. Uses the adapter's
8
+ // existing `content-block:{index}` sourceKey identity - no second
9
+ // identity system. content_block_stop closes the block's argument stream
10
+ // (tool_call_end), but that alone does not stop the coordinator from
11
+ // silently merging a LATER, real content_block_delta for the SAME index
12
+ // into the same still-"collecting" call (handleCallEnd never changes
13
+ // call.status - only finishCall(), called solely from the stream-wide
14
+ // handleStreamEnd(), does that - see coordinator.ts). Recognized argument
15
+ // evidence, and a duplicate content_block_stop itself, for an index
16
+ // already in this set are therefore hardened below instead of merged/
17
+ // silently repeated. Tracks every stopped index regardless of whether it
18
+ // was ever a real tool_use block - content_block_stop carries no
19
+ // content_block field to distinguish that, matching the adapter's own
20
+ // existing behavior of never discriminating by type at stop time.
21
+ terminatedBlockIndices = new Set();
5
22
  push(rawEvent) {
6
- if (this.finished)
7
- return [];
23
+ // No `finished` early return here: silently dropping every event after
24
+ // the first terminal meant a late argument delta, a conflicting or
25
+ // duplicate `message_delta` terminal, or a late `error` event that
26
+ // arrived even one raw event late never reached the coordinator at all -
27
+ // not even as a diagnostic - so an already-decided call's authority
28
+ // could never be revoked by it. Every case below that has ITS OWN
29
+ // meaningful post-terminal handling (a genuine argument delta, a second
30
+ // content_block_start/_stop, a second stream-terminal) still fires
31
+ // exactly as if the stream were open; the coordinator's own `isFinished`
32
+ // gate (coordinator.ts's `push()`) is what turns each of those into a
33
+ // sticky, stream-wide AUTHORITY_PROTOCOL_VIOLATION_CODES diagnostic once
34
+ // it actually receives them. Mirrors the fix already applied to
35
+ // AiSdkStreamAdapter for the same invariant (GHSA-3xpw-9694-2xxp).
8
36
  const events = [];
9
37
  if (!rawEvent || typeof rawEvent !== "object") {
10
38
  events.push({
@@ -37,18 +65,71 @@ export class AnthropicStreamAdapter {
37
65
  case "content_block_delta": {
38
66
  if (chunk.delta?.type === "input_json_delta" && typeof chunk.delta.partial_json === "string") {
39
67
  const sourceKey = `content-block:${chunk.index}`;
68
+ if (this.terminatedBlockIndices.has(chunk.index)) {
69
+ // Block-local post-terminal evidence (P4.2 / F-1): this exact
70
+ // block already recorded its own content_block_stop. Never
71
+ // merge further argument evidence as normal - that would
72
+ // silently mutate (and, if left structurally unclosed at stop
73
+ // time, silently CLOSE) an already-ended block's value with no
74
+ // record of the anomaly. Same diagnostic code
75
+ // AiSdkStreamAdapter/OpenAICompatibleStreamAdapter/
76
+ // OpenAIStreamAdapter already use for materially identical
77
+ // semantics ("tool argument evidence arrived after that call's
78
+ // end"), attributed to the block's own real, already-
79
+ // tool_call_start'd sourceKey so the coordinator resolves it to
80
+ // the actual call, not a phantom identity.
81
+ events.push({
82
+ type: "provider_diagnostic",
83
+ sequence: ++this.sequence,
84
+ provider: this.provider,
85
+ callRef: { sourceKey },
86
+ code: TOOL_ARGUMENTS_AFTER_END_DIAGNOSTIC_CODE,
87
+ severity: "error",
88
+ message: `Tool call argument evidence for content block ${chunk.index} arrived after that block's own content_block_stop`,
89
+ });
90
+ }
91
+ else {
92
+ events.push({
93
+ type: "tool_call_arguments_delta",
94
+ sequence: ++this.sequence,
95
+ provider: this.provider,
96
+ callRef: { sourceKey },
97
+ delta: chunk.delta.partial_json,
98
+ });
99
+ }
100
+ }
101
+ break;
102
+ }
103
+ case "content_block_stop": {
104
+ const sourceKey = `content-block:${chunk.index}`;
105
+ if (this.terminatedBlockIndices.has(chunk.index)) {
106
+ // Duplicate content_block_stop for the same index (P4.2 / Phase
107
+ // 7): pre-fix this silently re-emitted a second tool_call_end,
108
+ // which coordinator.ts's handleCallEnd() tolerates idempotently
109
+ // (it only sets two already-true booleans again) - authority-safe
110
+ // but tolerated: the duplicate did not create or increase
111
+ // execution authority, but it was silently accepted and did not
112
+ // itself disqualify the call, so an otherwise-valid call could
113
+ // still execute once a later, genuine terminal arrived. The
114
+ // adapter now records the duplicate as DUPLICATE_TOOL_END and
115
+ // therefore fails that call closed instead - genuinely a
116
+ // repeated end signal for the same call, exactly
117
+ // DUPLICATE_TOOL_END_DIAGNOSTIC_CODE's own documented meaning
118
+ // ("more than one end part for the same call") and
119
+ // AUTHORITY_PROTOCOL_VIOLATION_CODES membership - reused rather
120
+ // than inventing a new code.
40
121
  events.push({
41
- type: "tool_call_arguments_delta",
122
+ type: "provider_diagnostic",
42
123
  sequence: ++this.sequence,
43
124
  provider: this.provider,
44
125
  callRef: { sourceKey },
45
- delta: chunk.delta.partial_json,
126
+ code: DUPLICATE_TOOL_END_DIAGNOSTIC_CODE,
127
+ severity: "error",
128
+ message: `content block ${chunk.index} received a second content_block_stop`,
46
129
  });
130
+ break;
47
131
  }
48
- break;
49
- }
50
- case "content_block_stop": {
51
- const sourceKey = `content-block:${chunk.index}`;
132
+ this.terminatedBlockIndices.add(chunk.index);
52
133
  events.push({
53
134
  type: "tool_call_end",
54
135
  sequence: ++this.sequence,
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { ProviderStreamAdapter } from "./adapter.js";
3
3
  interface GeminiFunctionCall {
4
4
  name?: string;
5
5
  args?: unknown;
6
+ id?: string;
6
7
  }
7
8
  interface GeminiPart {
8
9
  functionCall?: GeminiFunctionCall;
@@ -13,19 +14,140 @@ interface GeminiContent {
13
14
  interface GeminiCandidate {
14
15
  content?: GeminiContent;
15
16
  finishReason?: string;
17
+ index?: number;
16
18
  }
17
19
  export interface GeminiEvent {
18
20
  candidates?: GeminiCandidate[];
19
21
  }
22
+ /**
23
+ * Gemini `generateContentStream`-shaped streaming adapter.
24
+ *
25
+ * Terminal-ownership fix (Phase B hardening sweep, corrected in Phase B.1-
26
+ * B.7 after an identity-premise error was found in raw review):
27
+ * `candidate.finishReason` is candidate-LOCAL evidence only - a genuine
28
+ * multi-candidate (n>1) stream has one finishReason per candidate, each
29
+ * reporting only that candidate's own completion, never the whole provider
30
+ * stream's. Pre-fix, ANY candidate's finishReason directly emitted
31
+ * `provider_stream_end` and set this adapter's own global `finished` flag -
32
+ * the same "first choice to finish wrongly ends every choice" defect
33
+ * already found and fixed for OpenAI (Chat Completions plural and legacy
34
+ * singular) and Anthropic this session.
35
+ *
36
+ * Candidate IDENTITY correction (Phase B.1/B.2, the raw-review finding):
37
+ * this adapter used to key all candidate-local state by array POSITION
38
+ * within each chunk's own `candidates` list. The real wire field
39
+ * `candidate.index` ("Output only. The 0-based index of this candidate...
40
+ * useful for distinguishing between multiple candidates when
41
+ * candidate_count > 1" - confirmed against the installed
42
+ * `@google/genai@2.21.0` SDK's own types AND its real SSE parser, see
43
+ * test/integration/gemini-official-sdk-lifecycle.test.ts) is the
44
+ * authoritative identity instead. Array position silently breaks the
45
+ * moment a chunk omits an already-finished candidate (entirely normal - a
46
+ * provider has no reason to keep re-sending a candidate with nothing new
47
+ * to say) or reorders candidates within one chunk: real candidate 1's
48
+ * evidence arriving alone, at array position 0, was silently misattributed
49
+ * to candidate 0's own (already-terminal) identity - captured as genuine
50
+ * RED against real SDK-parsed chunks before this fix, not merely inferred.
51
+ *
52
+ * Fixed the same way as OpenAI's legacy path (P4.3) and Anthropic (P4.2):
53
+ * candidate.finishReason
54
+ * -> records that candidate's own terminal StreamEndReason
55
+ * -> does NOT emit provider_stream_end
56
+ * -> does NOT set this adapter's global `finished` flag
57
+ * finish(meta?)
58
+ * -> the ONE provider_stream_end for this adapter's whole lifetime,
59
+ * aggregating every recorded candidate-local reason (worst wins -
60
+ * see REASON_PRIORITY above) with meta.reason.
61
+ *
62
+ * Post-provider-terminal handling (Phase B.6): the top-of-push()
63
+ * `if (this.finished) return [];` guard, previously the only adapter in
64
+ * this codebase deliberately retaining the pre-P0 silent-drop pattern, is
65
+ * REMOVED here too - normalization continues after adapter.finish(), and
66
+ * coordinator.ts's own `isFinished` gate provides the canonical
67
+ * post-provider-terminal handling, exactly like every other adapter. This
68
+ * is future-proofing / architectural consistency, NOT the closing of a
69
+ * demonstrated execution-authority gap: independently re-verified, not
70
+ * merely trusted, that no Gemini call can ever reach `execute` -
71
+ * PROJECTION_ONLY_ARGUMENTS_DIAGNOSTIC_CODE is unconditional on every
72
+ * functionCall and checked by decide.ts before status is even considered;
73
+ * gate.ts's takeDecision() re-derives fresh and only ever returns
74
+ * something for action==="execute". See the two-part epistemic
75
+ * distinction in this program's own final report: CORRECTNESS/
76
+ * architecture-consistency, never claimed as an execution-integrity fix.
77
+ *
78
+ * Call IDENTITY correction (P4.5, a genuine RED confirmed against real
79
+ * @google/genai@2.21.0-parsed chunks, not merely inferred): within one
80
+ * candidate, this adapter used to key each functionCall's own sourceKey by
81
+ * PART ARRAY POSITION (`candidate:{i}/part:{j}`). Each Gemini functionCall
82
+ * is object-level final delivery, never incrementally streamed (no
83
+ * position needs to stay stable WITHIN one call's own lifetime) - but
84
+ * array position is NOT stable ACROSS separate, unrelated calls delivered
85
+ * in separate chunks: two genuinely independent functionCalls (confirmed
86
+ * via the real SDK parser to carry distinct `id`s, distinct names, and
87
+ * distinct args) that happen to land at the same part-array-position in
88
+ * their own respective chunks were silently treated as the SAME call - the
89
+ * second's evidence colliding with and corrupting the first's
90
+ * already-closed identity (coordinator.ts's own E_DUPLICATE_TOOL_CALL_START
91
+ * plus a parser E_TRAILING_DATA), with the second call never surfacing as
92
+ * its own decision at all. This is the same class of identity-loss defect
93
+ * already found and fixed for candidate identity itself (P4.4) and for
94
+ * every other provider's own call/item/block identity this session - now
95
+ * closed at the function-call level too.
96
+ *
97
+ * Fixed by preferring the official wire field `functionCall.id` ("Optional.
98
+ * The unique id of the function call...") as the call identity when a
99
+ * valid non-empty string is present:
100
+ * `candidate:{candidateIndex}/function-call-id:{id}`
101
+ * `id` is explicitly OPTIONAL per its own doc comment, and confirmed
102
+ * empirically (real SDK-parsed evidence) that the SDK passes through a
103
+ * functionCall with no `id` at all without complaint - never assumed
104
+ * present, never required, never a fail-closed precondition. When absent
105
+ * (or an empty string, treated identically to absent), this adapter falls
106
+ * back to a per-candidate, per-adapter-instance MONOTONIC OCCURRENCE
107
+ * COUNTER (`candidate:{candidateIndex}/function-call:{n}`) - deliberately
108
+ * NOT part array position: the counter is advanced by THIS adapter's own
109
+ * processing order, never by anything the provider could reorder or omit
110
+ * across chunks, so it remains genuinely unique for the adapter's whole
111
+ * lifetime regardless of where in a `parts[]` array a later, unrelated
112
+ * no-id call happens to land. This is real, forensically-traceable
113
+ * identity - never a claim of continuity between separate observations,
114
+ * and never a byte-level/positional reconstruction.
115
+ *
116
+ * A REPEATED identical `functionCall.id` under the same candidate (or a
117
+ * no-id counter value, which can never repeat by construction) is treated
118
+ * as late/duplicate evidence for the one already-delivered call that
119
+ * sourceKey names - exactly TOOL_ARGUMENTS_AFTER_END_DIAGNOSTIC_CODE's own
120
+ * existing meaning, reusing `candidateSourceKeys`'s own existing
121
+ * "every sourceKey ever started, never cleared" tracking rather than a new
122
+ * mechanism (see push()). Official Gemini semantics document no supported
123
+ * continuation/streaming mechanism for a single function call at all
124
+ * (`partialArgs`, `willContinue`, `FunctionCallingConfig.
125
+ * streamFunctionCallArguments` are all explicitly "not supported in Gemini
126
+ * API" per the installed SDK's own doc comments) - so a repeated id is
127
+ * never treated as a legitimate multi-chunk continuation of the same call,
128
+ * only as suspect duplicate evidence disqualifying the real call it names.
129
+ * A different `id` under a DIFFERENT candidate is never merged with this
130
+ * one: identity is candidate-scoped first, exactly as P4.4 already
131
+ * established - official semantics document `id` only as a response-
132
+ * correlation mechanism (implying uniqueness where populated) and never
133
+ * claim a cross-candidate-global uniqueness scope, so candidate-scoping
134
+ * remains the conservative, evidence-supported default.
135
+ */
20
136
  export declare class GeminiStreamAdapter implements ProviderStreamAdapter<unknown> {
21
137
  readonly provider: ProviderName;
22
138
  private sequence;
23
139
  private finished;
140
+ private candidateTerminalReasons;
141
+ private candidateTerminalProviderReasons;
142
+ private candidateSourceKeys;
143
+ private noIdFunctionCallCounters;
144
+ private callSourceKey;
24
145
  push(rawEvent: unknown): readonly NormalizedToolStreamEvent[];
25
146
  finish(meta?: {
26
147
  reason?: StreamEndReason;
27
148
  providerReason?: string;
28
149
  }): readonly NormalizedToolStreamEvent[];
150
+ private aggregateTermination;
29
151
  }
30
152
  export {};
31
153
  //# sourceMappingURL=gemini.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/providers/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAIrD,UAAU,kBAAkB;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,UAAU,UAAU;IAClB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CAGnC;AAED,UAAU,aAAa;IACrB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,UAAU,eAAe;IACvB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;CAChC;AAED,qBAAa,mBAAoB,YAAW,qBAAqB,CAAC,OAAO,CAAC;IACxE,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAY;IAC3C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAS;IAEzB,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,yBAAyB,EAAE;IA8G7D,MAAM,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,eAAe,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,yBAAyB,EAAE;CAW3G"}
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/providers/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAUrD,UAAU,kBAAkB;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IAQf,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,UAAU,UAAU;IAClB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CAGnC;AAED,UAAU,aAAa;IACrB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,UAAU,eAAe;IACvB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IAatB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;CAChC;AAqCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiHG;AACH,qBAAa,mBAAoB,YAAW,qBAAqB,CAAC,OAAO,CAAC;IACxE,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAY;IAC3C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAS;IAQzB,OAAO,CAAC,wBAAwB,CAA2C;IAI3E,OAAO,CAAC,gCAAgC,CAAkC;IAW1E,OAAO,CAAC,mBAAmB,CAAuC;IAQlE,OAAO,CAAC,wBAAwB,CAAkC;IASlE,OAAO,CAAC,aAAa;IASrB,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,yBAAyB,EAAE;IAiT7D,MAAM,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,eAAe,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,yBAAyB,EAAE;IAmB1G,OAAO,CAAC,oBAAoB;CA6B7B"}