@cendor/tokenguard 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +78 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.ts +188 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +607 -0
- package/dist/index.js.map +1 -0
- package/dist/sinks.d.ts +82 -0
- package/dist/sinks.d.ts.map +1 -0
- package/dist/sinks.js +219 -0
- package/dist/sinks.js.map +1 -0
- package/package.json +58 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@cendor/tokenguard` — pre-flight cost caps + free per-tag spend attribution for LLM calls. The
|
|
3
|
+
* TypeScript port of `cendor.tokenguard`.
|
|
4
|
+
*
|
|
5
|
+
* It **subscribes** to `@cendor/core`'s event bus and registers a pre-flight interceptor; it never
|
|
6
|
+
* patches a client itself (the locked architecture: one `instrument()`, many subscribers). Once a
|
|
7
|
+
* client is instrumented, `budget(...)` enforces a cap and `track(...)` attributes spend by tags —
|
|
8
|
+
* with zero per-call wiring.
|
|
9
|
+
*
|
|
10
|
+
* Parity notes vs. the Python original:
|
|
11
|
+
* - Python `contextvars` become two `node:async_hooks` `AsyncLocalStorage` scopes (`_tags`,
|
|
12
|
+
* `_budgets`) — they propagate across `await` in the same async task, but NOT across worker
|
|
13
|
+
* threads (same caveat as Python's contextvars vs. OS threads).
|
|
14
|
+
* - Python `with budget(...) as b:` / `@budget(...)` become {@link withBudget} (async-callback
|
|
15
|
+
* scope) and {@link budget} (decorator: `budget(cfg)(fn)`); `with track(...)` becomes
|
|
16
|
+
* {@link track} (async-callback scope). `track.report` is attached as an ergonomic alias.
|
|
17
|
+
* - `warnings.warn(UnpricedModelWarning)` becomes a capturable/escalatable warning channel:
|
|
18
|
+
* register a listener via {@link onUnpricedWarning}; with no listener it falls back to
|
|
19
|
+
* `console.warn`. Deduped once-per-model (cleared by {@link reset}).
|
|
20
|
+
*/
|
|
21
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
22
|
+
import { Dec, LLMCall, MISS, Money, Reroute, UnknownModelError, addInterceptor, bus, prices, tokens, } from '@cendor/core';
|
|
23
|
+
// --------------------------------------------------------------------------- constants
|
|
24
|
+
/** Output tokens are unknown pre-flight; reserve this many for the projection unless the request
|
|
25
|
+
* carries an explicit `max_tokens` / `max_completion_tokens`. */
|
|
26
|
+
const DEFAULT_OUTPUT_RESERVE = 256;
|
|
27
|
+
/** Valid string values for `budget({ onExceed })` (a callable is also accepted). */
|
|
28
|
+
const ON_EXCEED = ['raise', 'block', 'truncate', 'downgrade', 'clamp'];
|
|
29
|
+
/** Per-provider request kwarg that caps generated (reasoning + visible) output tokens, used by
|
|
30
|
+
* `onExceed: 'clamp'`. Providers absent here can't have the cap injected safely (clamp falls back
|
|
31
|
+
* to a hard block). */
|
|
32
|
+
const CLAMP_KWARG = {
|
|
33
|
+
openai: 'max_completion_tokens',
|
|
34
|
+
anthropic: 'max_tokens',
|
|
35
|
+
};
|
|
36
|
+
const DEFAULT_MAX_RECORDS = 100_000;
|
|
37
|
+
const DEFAULT_ON_UNPRICED = 'warn';
|
|
38
|
+
// --------------------------------------------------------------------------- errors + warnings
|
|
39
|
+
/** Raised when a call pushes an active budget over its cap (post-flight `raise`, or pre-flight
|
|
40
|
+
* `block` / `clamp`-fallback). */
|
|
41
|
+
export class BudgetExceeded extends Error {
|
|
42
|
+
constructor(message) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = 'BudgetExceeded';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Warned (once per model) when a USD budget is active but the call's model has no price — an
|
|
48
|
+
* unpriced model records `$0` toward USD spend, so a USD-only cap can't enforce against it. */
|
|
49
|
+
export class UnpricedModelWarning extends Error {
|
|
50
|
+
constructor(message) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = 'UnpricedModelWarning';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Internal graceful-degradation signal for `onExceed: 'truncate'`; never escapes a budget. */
|
|
56
|
+
class Truncated extends Error {
|
|
57
|
+
constructor() {
|
|
58
|
+
super('truncated');
|
|
59
|
+
this.name = 'Truncated';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Internal — mirrors Python's `ValueError` for eager config validation (tests match a substring). */
|
|
63
|
+
class ValueError extends Error {
|
|
64
|
+
constructor(message) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = 'ValueError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Internal — mirrors Python's `AssertionError` for {@link Report.assertUnder}. */
|
|
70
|
+
class AssertionError extends Error {
|
|
71
|
+
constructor(message) {
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = 'AssertionError';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const warningListeners = new Set();
|
|
77
|
+
/**
|
|
78
|
+
* Register a listener for {@link UnpricedModelWarning}s (the TS analog of a Python warning filter).
|
|
79
|
+
* Returns an unsubscribe function. With at least one listener installed the warning is delivered to
|
|
80
|
+
* the listeners (and NOT to `console.warn`); a listener may re-throw to escalate the warning to an
|
|
81
|
+
* error, exactly like `simplefilter("error", UnpricedModelWarning)`.
|
|
82
|
+
*/
|
|
83
|
+
export function onUnpricedWarning(listener) {
|
|
84
|
+
warningListeners.add(listener);
|
|
85
|
+
return () => {
|
|
86
|
+
warningListeners.delete(listener);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** One active budget (mutable — the post-flight subscriber accumulates spend into it). */
|
|
90
|
+
export class Frame {
|
|
91
|
+
capUsd;
|
|
92
|
+
capTokens;
|
|
93
|
+
onExceed;
|
|
94
|
+
scope;
|
|
95
|
+
downgrade;
|
|
96
|
+
outputReserve;
|
|
97
|
+
reasoningReserve;
|
|
98
|
+
spentUsd = new Dec(0);
|
|
99
|
+
spentTokens = 0;
|
|
100
|
+
calls = 0;
|
|
101
|
+
constructor(init) {
|
|
102
|
+
this.capUsd = init.capUsd;
|
|
103
|
+
this.capTokens = init.capTokens;
|
|
104
|
+
this.onExceed = init.onExceed;
|
|
105
|
+
this.scope = init.scope;
|
|
106
|
+
this.downgrade = init.downgrade;
|
|
107
|
+
this.outputReserve = init.outputReserve;
|
|
108
|
+
this.reasoningReserve = init.reasoningReserve;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// --------------------------------------------------------------------------- module state
|
|
112
|
+
const tagsStore = new AsyncLocalStorage();
|
|
113
|
+
const budgetsStore = new AsyncLocalStorage();
|
|
114
|
+
const records = [];
|
|
115
|
+
const downgradeRows = [];
|
|
116
|
+
const clampRows = [];
|
|
117
|
+
let sink = null;
|
|
118
|
+
let maxRecords = DEFAULT_MAX_RECORDS;
|
|
119
|
+
let droppedCount = 0;
|
|
120
|
+
let onUnpriced = DEFAULT_ON_UNPRICED;
|
|
121
|
+
const warnedUnpriced = new Set();
|
|
122
|
+
function currentTags() {
|
|
123
|
+
return tagsStore.getStore() ?? {};
|
|
124
|
+
}
|
|
125
|
+
function currentFrames() {
|
|
126
|
+
return budgetsStore.getStore() ?? [];
|
|
127
|
+
}
|
|
128
|
+
function warnUnpriced(model, mode) {
|
|
129
|
+
if (warnedUnpriced.has(model))
|
|
130
|
+
return;
|
|
131
|
+
warnedUnpriced.add(model);
|
|
132
|
+
const warning = new UnpricedModelWarning(`tokenguard: no price for model '${model}', so the active USD budget (on_exceed='${mode}') counts its calls as $0 and cannot enforce a USD cap on it. Add a rate (cendor.core.prices), use a tokens= cap instead, or configure(on_unpriced='raise') to reject unpriced calls under on_exceed='block'.`);
|
|
133
|
+
if (warningListeners.size === 0) {
|
|
134
|
+
console.warn(warning.message);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
for (const listener of warningListeners)
|
|
138
|
+
listener(warning);
|
|
139
|
+
}
|
|
140
|
+
function ensureSubscribed() {
|
|
141
|
+
bus.subscribe(onCall); // idempotent on the bus side
|
|
142
|
+
addInterceptor(_preflightInterceptor); // idempotent; pre-flight downgrade/clamp/block routing
|
|
143
|
+
}
|
|
144
|
+
// --------------------------------------------------------------------------- projection helpers
|
|
145
|
+
/**
|
|
146
|
+
* Output tokens to assume pre-flight. Prefers the request's explicit output cap
|
|
147
|
+
* (`max_completion_tokens`, else `max_tokens`) using `!= null` checks so `max_tokens: 0` is honored
|
|
148
|
+
* (project 0 output), NOT treated as unset. Otherwise assumes `reserve + reasoningReserve`.
|
|
149
|
+
*
|
|
150
|
+
* Internal, but exported for parity with the Python test that asserts its behavior directly.
|
|
151
|
+
*/
|
|
152
|
+
export function _projectedOutput(call, reserve, reasoningReserve = 0) {
|
|
153
|
+
const kwargs = call.metadata.request_kwargs ?? {};
|
|
154
|
+
let explicit = kwargs.max_completion_tokens;
|
|
155
|
+
if (explicit == null)
|
|
156
|
+
explicit = kwargs.max_tokens;
|
|
157
|
+
if (explicit != null)
|
|
158
|
+
return Math.trunc(Number(explicit));
|
|
159
|
+
return reserve + reasoningReserve;
|
|
160
|
+
}
|
|
161
|
+
/** Project a call's cost pre-flight from its model + messages (+ an output reserve). May throw
|
|
162
|
+
* `UnknownModelError` (the KeyError-equivalent) for an unpriced model. */
|
|
163
|
+
function estimateEvent(call, reserve, reasoningReserve = 0) {
|
|
164
|
+
const inputTokens = tokens.count(call.messages, call.model);
|
|
165
|
+
const projected = _projectedOutput(call, reserve, reasoningReserve);
|
|
166
|
+
return prices.estimate(call.model, inputTokens, { outputTokens: projected }).amount;
|
|
167
|
+
}
|
|
168
|
+
/** Pre-flight token projection: input tokens + the output reserve (max_tokens or default). */
|
|
169
|
+
function projectTokens(call, reserve, reasoningReserve = 0) {
|
|
170
|
+
return (tokens.count(call.messages, call.model) + _projectedOutput(call, reserve, reasoningReserve));
|
|
171
|
+
}
|
|
172
|
+
// --------------------------------------------------------------------------- pre-flight interceptor
|
|
173
|
+
/**
|
|
174
|
+
* Pre-flight enforcement, before the call runs: reroute (`downgrade`), clamp (`clamp`), or block
|
|
175
|
+
* (`block`). `raise`/`truncate`/callable are ignored here (post-flight only). Iterates frames
|
|
176
|
+
* innermost-first.
|
|
177
|
+
*
|
|
178
|
+
* Internal, but exported so tests can drive it directly on a synthesized `LLMCall` (the TS core's
|
|
179
|
+
* `instrument()` only structurally detects openai/anthropic clients, so an "ollama-shaped" client
|
|
180
|
+
* isn't wrapped — this exercises the same clamp-fallback code path).
|
|
181
|
+
*/
|
|
182
|
+
export function _preflightInterceptor(call) {
|
|
183
|
+
if (!(call instanceof LLMCall))
|
|
184
|
+
return MISS;
|
|
185
|
+
const frames = currentFrames();
|
|
186
|
+
for (let i = frames.length - 1; i >= 0; i--) {
|
|
187
|
+
const frame = frames[i];
|
|
188
|
+
if (frame.onExceed === 'downgrade' && frame.downgrade && frame.capUsd !== null) {
|
|
189
|
+
const cheaper = frame.downgrade[call.model];
|
|
190
|
+
if (!cheaper)
|
|
191
|
+
continue;
|
|
192
|
+
let projected;
|
|
193
|
+
try {
|
|
194
|
+
projected = estimateEvent(call, frame.outputReserve, frame.reasoningReserve);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
if (err instanceof UnknownModelError) {
|
|
198
|
+
warnUnpriced(call.model, 'downgrade'); // can't project — no longer silent
|
|
199
|
+
continue; // unknown model price — leave the call as-is
|
|
200
|
+
}
|
|
201
|
+
throw err;
|
|
202
|
+
}
|
|
203
|
+
if (frame.spentUsd.plus(projected).greaterThan(frame.capUsd)) {
|
|
204
|
+
downgradeRows.push({ from: call.model, to: cheaper, tags: { ...currentTags() } });
|
|
205
|
+
return new Reroute({ model: cheaper });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if (frame.onExceed === 'clamp') {
|
|
209
|
+
const reroute = clamp(call, frame);
|
|
210
|
+
if (reroute !== null)
|
|
211
|
+
return reroute;
|
|
212
|
+
}
|
|
213
|
+
else if (frame.onExceed === 'block') {
|
|
214
|
+
const projTokens = projectTokens(call, frame.outputReserve, frame.reasoningReserve);
|
|
215
|
+
if (frame.capTokens !== null && frame.spentTokens + projTokens > frame.capTokens) {
|
|
216
|
+
throw new BudgetExceeded(`pre-flight block: ~${frame.spentTokens + projTokens} tokens would exceed cap ${frame.capTokens} (model=${call.model})`);
|
|
217
|
+
}
|
|
218
|
+
if (frame.capUsd !== null) {
|
|
219
|
+
let projected;
|
|
220
|
+
try {
|
|
221
|
+
projected = estimateEvent(call, frame.outputReserve, frame.reasoningReserve);
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
if (err instanceof UnknownModelError) {
|
|
225
|
+
if (onUnpriced === 'raise') {
|
|
226
|
+
throw new BudgetExceeded(`pre-flight block: model=${call.model} has no price, so a USD cap cannot be projected; configure(on_unpriced='raise') rejects unpriced calls (set on_unpriced='warn' to let them through as $0).`);
|
|
227
|
+
}
|
|
228
|
+
warnUnpriced(call.model, 'block');
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
throw err;
|
|
232
|
+
}
|
|
233
|
+
if (frame.spentUsd.plus(projected).greaterThan(frame.capUsd)) {
|
|
234
|
+
throw new BudgetExceeded(`pre-flight block: projected $${frame.spentUsd.plus(projected)} would exceed cap $${frame.capUsd} (model=${call.model})`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return MISS;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Inject a provider output ceiling so a single call can't exceed the remaining token budget.
|
|
243
|
+
* Requires a `tokens=` cap; a no-op when comfortably under; falls back to a hard block when it
|
|
244
|
+
* would breach but no ceiling can be injected safely (unknown provider, or no room even for input).
|
|
245
|
+
*/
|
|
246
|
+
function clamp(call, frame) {
|
|
247
|
+
if (frame.capTokens === null)
|
|
248
|
+
return null;
|
|
249
|
+
const projectedInput = tokens.count(call.messages, call.model);
|
|
250
|
+
const projOutput = _projectedOutput(call, frame.outputReserve, frame.reasoningReserve);
|
|
251
|
+
if (frame.spentTokens + projectedInput + projOutput <= frame.capTokens)
|
|
252
|
+
return null;
|
|
253
|
+
const allowance = frame.capTokens - frame.spentTokens - projectedInput;
|
|
254
|
+
const kwarg = CLAMP_KWARG[call.provider];
|
|
255
|
+
if (kwarg === undefined || allowance <= 0) {
|
|
256
|
+
throw new BudgetExceeded(`pre-flight clamp: cannot fit call within the remaining token budget (~${frame.capTokens - frame.spentTokens} left, ~${projectedInput} input; provider='${call.provider}', model=${call.model}) — use on_exceed='block' to reject, or raise the cap`);
|
|
257
|
+
}
|
|
258
|
+
const existingRaw = call.metadata.request_kwargs?.[kwarg];
|
|
259
|
+
const existing = existingRaw == null ? null : Math.trunc(Number(existingRaw));
|
|
260
|
+
if (existing !== null && existing <= allowance)
|
|
261
|
+
return null; // caller's own cap already fits
|
|
262
|
+
const target = existing === null ? allowance : Math.min(existing, allowance);
|
|
263
|
+
clampRows.push({ model: call.model, kwarg, limit: target, tags: { ...currentTags() } });
|
|
264
|
+
return new Reroute({ [kwarg]: target });
|
|
265
|
+
}
|
|
266
|
+
// --------------------------------------------------------------------------- post-flight subscriber
|
|
267
|
+
/** Bus subscriber: record spend by active tags and enforce active budgets (post-flight). */
|
|
268
|
+
function onCall(call) {
|
|
269
|
+
if (!(call instanceof LLMCall))
|
|
270
|
+
return; // tokenguard only accounts for model calls
|
|
271
|
+
const unpriced = call.cost === null; // no cost -> unknown/unpriced model, a USD blind spot
|
|
272
|
+
const usd = call.cost !== null ? call.cost.amount : new Dec(0);
|
|
273
|
+
const inp = call.usage !== null ? call.usage.inputTokens : 0;
|
|
274
|
+
const out = call.usage !== null ? call.usage.outputTokens : 0;
|
|
275
|
+
const rsn = call.usage !== null ? call.usage.reasoningTokens : 0;
|
|
276
|
+
const frames = currentFrames();
|
|
277
|
+
if (unpriced) {
|
|
278
|
+
// A USD-cap budget can't enforce against a $0-recorded call. Warn once per model, naming the
|
|
279
|
+
// innermost USD-cap frame's mode. (block/downgrade already warned pre-flight; this covers the
|
|
280
|
+
// post-flight modes: raise/truncate/callable.)
|
|
281
|
+
let usdFrame = null;
|
|
282
|
+
for (let i = frames.length - 1; i >= 0; i--) {
|
|
283
|
+
if (frames[i].capUsd !== null) {
|
|
284
|
+
usdFrame = frames[i];
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (usdFrame !== null) {
|
|
289
|
+
const mode = usdFrame.onExceed;
|
|
290
|
+
warnUnpriced(call.model, typeof mode === 'string' ? mode : 'callable');
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const tags = { ...currentTags() };
|
|
294
|
+
records.push({
|
|
295
|
+
tags,
|
|
296
|
+
usd,
|
|
297
|
+
inputTokens: inp,
|
|
298
|
+
outputTokens: out,
|
|
299
|
+
reasoningTokens: rsn,
|
|
300
|
+
model: call.model,
|
|
301
|
+
calls: 1,
|
|
302
|
+
unpriced,
|
|
303
|
+
});
|
|
304
|
+
// append + FIFO eviction — a read-modify-write on shared state. JS is single-threaded so no lock
|
|
305
|
+
// is needed; append/evict is atomic within a single emit.
|
|
306
|
+
if (maxRecords !== null && records.length > maxRecords) {
|
|
307
|
+
const overflow = records.length - maxRecords;
|
|
308
|
+
records.splice(0, overflow); // evict oldest (FIFO); counted, never silently
|
|
309
|
+
droppedCount += overflow;
|
|
310
|
+
}
|
|
311
|
+
if (sink !== null) {
|
|
312
|
+
sink.write({
|
|
313
|
+
tags,
|
|
314
|
+
usd: usd.toString(),
|
|
315
|
+
input_tokens: inp,
|
|
316
|
+
output_tokens: out,
|
|
317
|
+
reasoning_tokens: rsn,
|
|
318
|
+
model: call.model,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
for (const frame of frames) {
|
|
322
|
+
frame.spentUsd = frame.spentUsd.plus(usd);
|
|
323
|
+
frame.spentTokens += inp + out;
|
|
324
|
+
frame.calls += 1;
|
|
325
|
+
}
|
|
326
|
+
for (let i = frames.length - 1; i >= 0; i--) {
|
|
327
|
+
const frame = frames[i]; // enforce the tightest (innermost) breached cap first
|
|
328
|
+
if (over(frame)) {
|
|
329
|
+
if (frame.onExceed === 'downgrade' || frame.onExceed === 'clamp') {
|
|
330
|
+
continue; // handled pre-flight; a no-op here must not mask an outer cap's action
|
|
331
|
+
}
|
|
332
|
+
enforce(frame, call);
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function over(frame) {
|
|
338
|
+
if (frame.capUsd !== null && frame.spentUsd.greaterThan(frame.capUsd))
|
|
339
|
+
return true;
|
|
340
|
+
if (frame.capTokens !== null && frame.spentTokens > frame.capTokens)
|
|
341
|
+
return true;
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
function enforce(frame, call) {
|
|
345
|
+
const mode = frame.onExceed;
|
|
346
|
+
if (typeof mode === 'function') {
|
|
347
|
+
mode({ frame, call, spentUsd: frame.spentUsd, capUsd: frame.capUsd });
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (mode === 'truncate')
|
|
351
|
+
throw new Truncated();
|
|
352
|
+
if (mode === 'downgrade' || mode === 'clamp')
|
|
353
|
+
return; // already handled pre-flight
|
|
354
|
+
throw new BudgetExceeded(`budget exceeded: spent $${frame.spentUsd} > cap $${frame.capUsd} after ${frame.calls} call(s); last model=${call.model}. on_exceed='raise' is post-flight, so the cap is crossed by this one in-flight call — use on_exceed='block' for a pre-flight hard cap that never overspends.`);
|
|
355
|
+
}
|
|
356
|
+
function validateBudgetConfig(cfg) {
|
|
357
|
+
const onExceedValue = cfg.onExceed ?? 'raise';
|
|
358
|
+
if (typeof onExceedValue !== 'function' &&
|
|
359
|
+
!ON_EXCEED.includes(onExceedValue)) {
|
|
360
|
+
throw new ValueError(`on_exceed must be a callable or one of ${ON_EXCEED.join(',')}, got '${String(onExceedValue)}'`);
|
|
361
|
+
}
|
|
362
|
+
if (cfg.usd == null && cfg.tokens == null) {
|
|
363
|
+
throw new ValueError('budget requires a cap: pass usd= and/or tokens=');
|
|
364
|
+
}
|
|
365
|
+
if (onExceedValue === 'downgrade') {
|
|
366
|
+
if (!cfg.downgrade || Object.keys(cfg.downgrade).length === 0) {
|
|
367
|
+
throw new ValueError("on_exceed='downgrade' requires a downgrade={model: cheaper} map");
|
|
368
|
+
}
|
|
369
|
+
if (cfg.usd == null) {
|
|
370
|
+
throw new ValueError("on_exceed='downgrade' requires a usd= cap (the projection is USD-based)");
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (onExceedValue === 'clamp' && cfg.tokens == null) {
|
|
374
|
+
throw new ValueError("on_exceed='clamp' requires a tokens= cap (it injects a provider token ceiling)");
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function makeFrame(cfg) {
|
|
378
|
+
return new Frame({
|
|
379
|
+
capUsd: cfg.usd == null ? null : new Dec(String(cfg.usd)),
|
|
380
|
+
capTokens: cfg.tokens ?? null,
|
|
381
|
+
onExceed: cfg.onExceed ?? 'raise',
|
|
382
|
+
scope: cfg.scope ?? null,
|
|
383
|
+
downgrade: cfg.downgrade ?? null,
|
|
384
|
+
outputReserve: cfg.outputReserve ?? DEFAULT_OUTPUT_RESERVE,
|
|
385
|
+
reasoningReserve: cfg.reasoningReserve ?? 0,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
/** A handle to an open budget scope, passed to the {@link withBudget} callback. */
|
|
389
|
+
export class BudgetHandle {
|
|
390
|
+
frame;
|
|
391
|
+
constructor(frame) {
|
|
392
|
+
this.frame = frame;
|
|
393
|
+
}
|
|
394
|
+
/** Spend recorded against this budget so far. Meaningful inside the `withBudget` callback. */
|
|
395
|
+
get spent() {
|
|
396
|
+
return new Money(this.frame.spentUsd);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Cap spend on a decorated function (the parity of Python's `@budget(...)`). Validates its
|
|
401
|
+
* configuration eagerly (throws on a missing cap / unknown `onExceed` / bad `downgrade` or
|
|
402
|
+
* `clamp`), then returns a wrapper that opens a fresh budget frame per invocation.
|
|
403
|
+
*
|
|
404
|
+
* The TS core is async-first, so the returned wrapper is always async (model calls are async);
|
|
405
|
+
* on `onExceed: 'truncate'` it resolves to `undefined` (graceful degradation).
|
|
406
|
+
*/
|
|
407
|
+
export function budget(cfg) {
|
|
408
|
+
validateBudgetConfig(cfg);
|
|
409
|
+
return (fn) => async (...args) => {
|
|
410
|
+
ensureSubscribed();
|
|
411
|
+
const frame = makeFrame(cfg);
|
|
412
|
+
const frames = [...currentFrames(), frame];
|
|
413
|
+
try {
|
|
414
|
+
return await budgetsStore.run(frames, () => fn(...args));
|
|
415
|
+
}
|
|
416
|
+
catch (err) {
|
|
417
|
+
if (err instanceof Truncated)
|
|
418
|
+
return undefined; // degraded gracefully instead of crashing
|
|
419
|
+
throw err;
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Cap spend within an async-callback scope (the parity of Python's `with budget(...) as b:`).
|
|
425
|
+
* Validates eagerly, opens a fresh frame, runs `cb` inside the budget's `AsyncLocalStorage` scope so
|
|
426
|
+
* enforcement applies to every instrumented call made inside (including across awaits). On
|
|
427
|
+
* `onExceed: 'truncate'` it resolves to `undefined`; all other errors (including `BudgetExceeded`)
|
|
428
|
+
* propagate.
|
|
429
|
+
*/
|
|
430
|
+
export async function withBudget(cfg, cb) {
|
|
431
|
+
validateBudgetConfig(cfg);
|
|
432
|
+
ensureSubscribed();
|
|
433
|
+
const frame = makeFrame(cfg);
|
|
434
|
+
const frames = [...currentFrames(), frame];
|
|
435
|
+
const handle = new BudgetHandle(frame);
|
|
436
|
+
try {
|
|
437
|
+
return await budgetsStore.run(frames, () => cb(handle));
|
|
438
|
+
}
|
|
439
|
+
catch (err) {
|
|
440
|
+
if (err instanceof Truncated)
|
|
441
|
+
return undefined;
|
|
442
|
+
throw err;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function trackImpl(tags, cb) {
|
|
446
|
+
ensureSubscribed();
|
|
447
|
+
const merged = { ...currentTags(), ...tags };
|
|
448
|
+
return Promise.resolve(tagsStore.run(merged, cb));
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Attribute spend by ambient tags within an async-callback scope (the parity of Python's
|
|
452
|
+
* `with track(**tags):`). Tags merge with any enclosing `track(...)` and apply to every
|
|
453
|
+
* instrumented call made inside — including across nested and async calls. `track.report` is the
|
|
454
|
+
* documented alias for {@link report}.
|
|
455
|
+
*/
|
|
456
|
+
export const track = Object.assign(trackImpl, { report });
|
|
457
|
+
// --------------------------------------------------------------------------- estimate + report
|
|
458
|
+
/**
|
|
459
|
+
* Pre-flight cost projection without making a call (budget "linting"). Prices the input via
|
|
460
|
+
* `core.tokens` × `core.prices`, plus `maxOutputTokens` of output (defaults to 0 — input-only).
|
|
461
|
+
* Throws `UnknownModelError` (the KeyError-equivalent) for an unknown model.
|
|
462
|
+
*/
|
|
463
|
+
export function estimate(model, messages, maxOutputTokens = 0) {
|
|
464
|
+
const inputTokens = tokens.count(messages, model);
|
|
465
|
+
return prices.estimate(model, inputTokens, { outputTokens: maxOutputTokens });
|
|
466
|
+
}
|
|
467
|
+
/** Aggregated spend rows. Iterable; cost-as-a-test-assertion via {@link assertUnder}. */
|
|
468
|
+
export class Report {
|
|
469
|
+
rows;
|
|
470
|
+
constructor(rows = []) {
|
|
471
|
+
this.rows = rows;
|
|
472
|
+
}
|
|
473
|
+
[Symbol.iterator]() {
|
|
474
|
+
return this.rows[Symbol.iterator]();
|
|
475
|
+
}
|
|
476
|
+
get length() {
|
|
477
|
+
return this.rows.length;
|
|
478
|
+
}
|
|
479
|
+
total() {
|
|
480
|
+
let sum = new Dec(0);
|
|
481
|
+
for (const row of this.rows)
|
|
482
|
+
sum = sum.plus(row.usd.amount);
|
|
483
|
+
return new Money(sum);
|
|
484
|
+
}
|
|
485
|
+
/** Assert spend (optionally filtered by tags) is under `usd`, else throw an AssertionError. */
|
|
486
|
+
assertUnder(usd, tagFilter = {}) {
|
|
487
|
+
const cap = new Dec(String(usd));
|
|
488
|
+
let spent = new Dec(0);
|
|
489
|
+
const filters = Object.entries(tagFilter);
|
|
490
|
+
for (const row of this.rows) {
|
|
491
|
+
if (filters.every(([k, v]) => row.tags[k] === v))
|
|
492
|
+
spent = spent.plus(row.usd.amount);
|
|
493
|
+
}
|
|
494
|
+
if (spent.greaterThan(cap)) {
|
|
495
|
+
const where = filters.length > 0 ? JSON.stringify(tagFilter) : 'all spend';
|
|
496
|
+
throw new AssertionError(`$${spent} exceeds cap $${cap} for ${where}`);
|
|
497
|
+
}
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Aggregate recorded spend, grouped by the given tag keys. Rows carry `usd` as `Money` and
|
|
503
|
+
* `tokens` = `input_tokens + output_tokens` (reasoning is a subset of output, NOT double-counted).
|
|
504
|
+
* Aggregates only the retained window (see {@link dropped}).
|
|
505
|
+
*/
|
|
506
|
+
export function report(groupBy) {
|
|
507
|
+
const keys = groupBy ?? [];
|
|
508
|
+
const groups = new Map();
|
|
509
|
+
const snapshot = [...records]; // snapshot so a concurrent emit can't resize mid-iteration
|
|
510
|
+
for (const rec of snapshot) {
|
|
511
|
+
const keyVals = keys.map((k) => (rec.tags[k] === undefined ? null : rec.tags[k]));
|
|
512
|
+
const gk = JSON.stringify(keyVals);
|
|
513
|
+
let group = groups.get(gk);
|
|
514
|
+
if (group === undefined) {
|
|
515
|
+
const tags = {};
|
|
516
|
+
for (const k of keys)
|
|
517
|
+
tags[k] = rec.tags[k] === undefined ? null : rec.tags[k];
|
|
518
|
+
group = {
|
|
519
|
+
tags,
|
|
520
|
+
usd: new Dec(0),
|
|
521
|
+
inputTokens: 0,
|
|
522
|
+
outputTokens: 0,
|
|
523
|
+
reasoningTokens: 0,
|
|
524
|
+
calls: 0,
|
|
525
|
+
unpricedCalls: 0,
|
|
526
|
+
};
|
|
527
|
+
groups.set(gk, group);
|
|
528
|
+
}
|
|
529
|
+
group.usd = group.usd.plus(rec.usd);
|
|
530
|
+
group.inputTokens += rec.inputTokens;
|
|
531
|
+
group.outputTokens += rec.outputTokens;
|
|
532
|
+
group.reasoningTokens += rec.reasoningTokens;
|
|
533
|
+
group.calls += rec.calls;
|
|
534
|
+
if (rec.unpriced)
|
|
535
|
+
group.unpricedCalls += rec.calls;
|
|
536
|
+
}
|
|
537
|
+
const rows = [];
|
|
538
|
+
for (const g of groups.values()) {
|
|
539
|
+
rows.push({
|
|
540
|
+
tags: g.tags,
|
|
541
|
+
usd: new Money(g.usd),
|
|
542
|
+
tokens: g.inputTokens + g.outputTokens,
|
|
543
|
+
input_tokens: g.inputTokens,
|
|
544
|
+
output_tokens: g.outputTokens,
|
|
545
|
+
reasoning_tokens: g.reasoningTokens,
|
|
546
|
+
calls: g.calls,
|
|
547
|
+
unpriced_calls: g.unpricedCalls,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
return new Report(rows);
|
|
551
|
+
}
|
|
552
|
+
// --------------------------------------------------------------------------- introspection + config
|
|
553
|
+
/** The pre-flight model downgrades performed so far (`{ from, to, tags }` rows). Returns a copy. */
|
|
554
|
+
export function downgrades() {
|
|
555
|
+
return [...downgradeRows];
|
|
556
|
+
}
|
|
557
|
+
/** The pre-flight token clamps applied so far (`{ model, kwarg, limit, tags }` rows). Returns a copy. */
|
|
558
|
+
export function clamps() {
|
|
559
|
+
return [...clampRows];
|
|
560
|
+
}
|
|
561
|
+
/** Attach a spend sink (e.g. `SQLiteSink`/`OTelSink`); returns the previous one. Pass `null` to
|
|
562
|
+
* detach. The in-memory aggregation (`report()`) always runs regardless. */
|
|
563
|
+
export function useSink(next) {
|
|
564
|
+
const previous = sink;
|
|
565
|
+
sink = next;
|
|
566
|
+
return previous;
|
|
567
|
+
}
|
|
568
|
+
/** Tune tokenguard's runtime behavior. Each argument is independent — omit one to leave it as is. */
|
|
569
|
+
export function configure(opts = {}) {
|
|
570
|
+
if (opts.maxRecords !== undefined)
|
|
571
|
+
maxRecords = opts.maxRecords;
|
|
572
|
+
if (opts.onUnpriced !== undefined) {
|
|
573
|
+
if (opts.onUnpriced !== 'warn' && opts.onUnpriced !== 'raise') {
|
|
574
|
+
throw new ValueError(`on_unpriced must be 'warn' or 'raise', got '${opts.onUnpriced}'`);
|
|
575
|
+
}
|
|
576
|
+
onUnpriced = opts.onUnpriced;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
/** Spend rows evicted by the {@link configure} cap since the last {@link reset} (0 if none). */
|
|
580
|
+
export function dropped() {
|
|
581
|
+
return droppedCount;
|
|
582
|
+
}
|
|
583
|
+
/** Count of recorded calls whose cost was `null` (unpriced/unknown model) in the retained buffer. */
|
|
584
|
+
export function unpricedCalls() {
|
|
585
|
+
let total = 0;
|
|
586
|
+
for (const rec of records)
|
|
587
|
+
if (rec.unpriced)
|
|
588
|
+
total += rec.calls;
|
|
589
|
+
return total;
|
|
590
|
+
}
|
|
591
|
+
/** Clear recorded spend and config (tags/budgets are `AsyncLocalStorage`-scoped), and re-arm the
|
|
592
|
+
* bus subscription. Useful between tests so spend doesn't leak across cases. */
|
|
593
|
+
export function reset() {
|
|
594
|
+
records.length = 0;
|
|
595
|
+
droppedCount = 0;
|
|
596
|
+
downgradeRows.length = 0;
|
|
597
|
+
clampRows.length = 0;
|
|
598
|
+
warnedUnpriced.clear();
|
|
599
|
+
sink = null;
|
|
600
|
+
maxRecords = DEFAULT_MAX_RECORDS;
|
|
601
|
+
onUnpriced = DEFAULT_ON_UNPRICED;
|
|
602
|
+
ensureSubscribed();
|
|
603
|
+
}
|
|
604
|
+
// Subscribe at import so even a bare instrumented call (no budget/track) is aggregated, and arm the
|
|
605
|
+
// pre-flight interceptor. Idempotent, and re-armed by reset().
|
|
606
|
+
ensureSubscribed();
|
|
607
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EACL,GAAG,EACH,OAAO,EACP,IAAI,EACJ,KAAK,EACL,OAAO,EACP,iBAAiB,EACjB,cAAc,EACd,GAAG,EACH,MAAM,EACN,MAAM,GACP,MAAM,cAAc,CAAC;AAGtB,wFAAwF;AAExF;iEACiE;AACjE,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAEnC,oFAAoF;AACpF,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,CAAU,CAAC;AAEhF;;uBAEuB;AACvB,MAAM,WAAW,GAA2B;IAC1C,MAAM,EAAE,uBAAuB;IAC/B,SAAS,EAAE,YAAY;CACxB,CAAC;AAEF,MAAM,mBAAmB,GAAG,OAAO,CAAC;AACpC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEnC,gGAAgG;AAEhG;kCACkC;AAClC,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;+FAC+F;AAC/F,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,+FAA+F;AAC/F,MAAM,SAAU,SAAQ,KAAK;IAC3B;QACE,KAAK,CAAC,WAAW,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,sGAAsG;AACtG,MAAM,UAAW,SAAQ,KAAK;IAC5B,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED,mFAAmF;AACnF,MAAM,cAAe,SAAQ,KAAK;IAChC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAGD,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA2B,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAiC;IACjE,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/B,OAAO,GAAG,EAAE;QACV,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC,CAAC;AACJ,CAAC;AAkBD,0FAA0F;AAC1F,MAAM,OAAO,KAAK;IAChB,MAAM,CAAiB;IACvB,SAAS,CAAgB;IACzB,QAAQ,CAAW;IACnB,KAAK,CAAgB;IACrB,SAAS,CAAgC;IACzC,aAAa,CAAS;IACtB,gBAAgB,CAAS;IACzB,QAAQ,GAAY,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/B,WAAW,GAAG,CAAC,CAAC;IAChB,KAAK,GAAG,CAAC,CAAC;IAEV,YAAY,IAQX;QACC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACxC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;IAChD,CAAC;CACF;AAyCD,2FAA2F;AAE3F,MAAM,SAAS,GAAG,IAAI,iBAAiB,EAA2B,CAAC;AACnE,MAAM,YAAY,GAAG,IAAI,iBAAiB,EAAW,CAAC;AACtD,MAAM,OAAO,GAAkB,EAAE,CAAC;AAClC,MAAM,aAAa,GAAmB,EAAE,CAAC;AACzC,MAAM,SAAS,GAAe,EAAE,CAAC;AACjC,IAAI,IAAI,GAAgB,IAAI,CAAC;AAC7B,IAAI,UAAU,GAAkB,mBAAmB,CAAC;AACpD,IAAI,YAAY,GAAG,CAAC,CAAC;AACrB,IAAI,UAAU,GAAG,mBAAmB,CAAC;AACrC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;AAEzC,SAAS,WAAW;IAClB,OAAO,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;AACpC,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,YAAY,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;AACvC,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,EAAE,IAAY;IAC/C,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO;IACtC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1B,MAAM,OAAO,GAAG,IAAI,oBAAoB,CACtC,mCAAmC,KAAK,2CAA2C,IAAI,+MAA+M,CACvS,CAAC;IACF,IAAI,gBAAgB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,KAAK,MAAM,QAAQ,IAAI,gBAAgB;QAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,gBAAgB;IACvB,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,6BAA6B;IACpD,cAAc,CAAC,qBAAqB,CAAC,CAAC,CAAC,uDAAuD;AAChG,CAAC;AAED,iGAAiG;AAEjG;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAa,EAAE,OAAe,EAAE,gBAAgB,GAAG,CAAC;IACnF,MAAM,MAAM,GAAI,IAAI,CAAC,QAAQ,CAAC,cAAsD,IAAI,EAAE,CAAC;IAC3F,IAAI,QAAQ,GAAG,MAAM,CAAC,qBAAqB,CAAC;IAC5C,IAAI,QAAQ,IAAI,IAAI;QAAE,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC;IACnD,IAAI,QAAQ,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1D,OAAO,OAAO,GAAG,gBAAgB,CAAC;AACpC,CAAC;AAED;0EAC0E;AAC1E,SAAS,aAAa,CAAC,IAAa,EAAE,OAAe,EAAE,gBAAgB,GAAG,CAAC;IACzE,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;IACpE,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;AACtF,CAAC;AAED,8FAA8F;AAC9F,SAAS,aAAa,CAAC,IAAa,EAAE,OAAe,EAAE,gBAAgB,GAAG,CAAC;IACzE,OAAO,CACL,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAC5F,CAAC;AACJ,CAAC;AAED,qGAAqG;AAErG;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,IAAI,CAAC,CAAC,IAAI,YAAY,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QACzB,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC/E,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5C,IAAI,CAAC,OAAO;gBAAE,SAAS;YACvB,IAAI,SAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,SAAS,GAAG,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;YAC/E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;oBACrC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,mCAAmC;oBAC1E,SAAS,CAAC,6CAA6C;gBACzD,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC7D,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;gBAClF,OAAO,IAAI,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACnC,IAAI,OAAO,KAAK,IAAI;gBAAE,OAAO,OAAO,CAAC;QACvC,CAAC;aAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACtC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACpF,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,WAAW,GAAG,UAAU,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;gBACjF,MAAM,IAAI,cAAc,CACtB,sBAAsB,KAAK,CAAC,WAAW,GAAG,UAAU,4BAA4B,KAAK,CAAC,SAAS,WAAW,IAAI,CAAC,KAAK,GAAG,CACxH,CAAC;YACJ,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;gBAC1B,IAAI,SAAkB,CAAC;gBACvB,IAAI,CAAC;oBACH,SAAS,GAAG,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;gBAC/E,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;wBACrC,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;4BAC3B,MAAM,IAAI,cAAc,CACtB,2BAA2B,IAAI,CAAC,KAAK,4JAA4J,CAClM,CAAC;wBACJ,CAAC;wBACD,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;wBAClC,SAAS;oBACX,CAAC;oBACD,MAAM,GAAG,CAAC;gBACZ,CAAC;gBACD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC7D,MAAM,IAAI,cAAc,CACtB,gCAAgC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,sBAAsB,KAAK,CAAC,MAAM,WAAW,IAAI,CAAC,KAAK,GAAG,CACzH,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAS,KAAK,CAAC,IAAa,EAAE,KAAY;IACxC,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACvF,IAAI,KAAK,CAAC,WAAW,GAAG,cAAc,GAAG,UAAU,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IACpF,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,WAAW,GAAG,cAAc,CAAC;IACvE,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,KAAK,KAAK,SAAS,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,cAAc,CACtB,yEAAyE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,WAAW,WAAW,cAAc,qBAAqB,IAAI,CAAC,QAAQ,YAAY,IAAI,CAAC,KAAK,uDAAuD,CACrP,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAI,IAAI,CAAC,QAAQ,CAAC,cAAsD,EAAE,CACzF,KAAK,CACN,CAAC;IACF,MAAM,QAAQ,GAAG,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IAC9E,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC,CAAC,gCAAgC;IAC7F,MAAM,MAAM,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC7E,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IACxF,OAAO,IAAI,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,qGAAqG;AAErG,4FAA4F;AAC5F,SAAS,MAAM,CAAC,IAAa;IAC3B,IAAI,CAAC,CAAC,IAAI,YAAY,OAAO,CAAC;QAAE,OAAO,CAAC,2CAA2C;IACnF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,sDAAsD;IAC3F,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjE,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,QAAQ,EAAE,CAAC;QACb,6FAA6F;QAC7F,8FAA8F;QAC9F,+CAA+C;QAC/C,IAAI,QAAQ,GAAiB,IAAI,CAAC;QAClC,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,IAAI,MAAM,CAAC,CAAC,CAAE,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;gBAC/B,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;gBACtB,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC;YAC/B,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,GAAG,WAAW,EAAE,EAAE,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC;QACX,IAAI;QACJ,GAAG;QACH,WAAW,EAAE,GAAG;QAChB,YAAY,EAAE,GAAG;QACjB,eAAe,EAAE,GAAG;QACpB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,KAAK,EAAE,CAAC;QACR,QAAQ;KACT,CAAC,CAAC;IACH,iGAAiG;IACjG,0DAA0D;IAC1D,IAAI,UAAU,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC;QAC7C,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,+CAA+C;QAC5E,YAAY,IAAI,QAAQ,CAAC;IAC3B,CAAC;IACD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,CAAC;YACT,IAAI;YACJ,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;YACnB,YAAY,EAAE,GAAG;YACjB,aAAa,EAAE,GAAG;YAClB,gBAAgB,EAAE,GAAG;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,KAAK,CAAC,WAAW,IAAI,GAAG,GAAG,GAAG,CAAC;QAC/B,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,sDAAsD;QAChF,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAChB,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBACjE,SAAS,CAAC,uEAAuE;YACnF,CAAC;YACD,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACrB,MAAM;QACR,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,KAAY;IACxB,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACnF,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IACjF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,OAAO,CAAC,KAAY,EAAE,IAAa;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC5B,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IACD,IAAI,IAAI,KAAK,UAAU;QAAE,MAAM,IAAI,SAAS,EAAE,CAAC;IAC/C,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,CAAC,6BAA6B;IACnF,MAAM,IAAI,cAAc,CACtB,2BAA2B,KAAK,CAAC,QAAQ,WAAW,KAAK,CAAC,MAAM,UAAU,KAAK,CAAC,KAAK,wBAAwB,IAAI,CAAC,KAAK,+JAA+J,CACvR,CAAC;AACJ,CAAC;AAeD,SAAS,oBAAoB,CAAC,GAAiB;IAC7C,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC;IAC9C,IACE,OAAO,aAAa,KAAK,UAAU;QACnC,CAAE,SAA+B,CAAC,QAAQ,CAAC,aAAa,CAAC,EACzD,CAAC;QACD,MAAM,IAAI,UAAU,CAClB,0CAA0C,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,aAAa,CAAC,GAAG,CAChG,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1C,MAAM,IAAI,UAAU,CAAC,iDAAiD,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,aAAa,KAAK,WAAW,EAAE,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,UAAU,CAAC,iEAAiE,CAAC,CAAC;QAC1F,CAAC;QACD,IAAI,GAAG,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;YACpB,MAAM,IAAI,UAAU,CAClB,yEAAyE,CAC1E,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,aAAa,KAAK,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QACpD,MAAM,IAAI,UAAU,CAClB,gFAAgF,CACjF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,GAAiB;IAClC,OAAO,IAAI,KAAK,CAAC;QACf,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzD,SAAS,EAAE,GAAG,CAAC,MAAM,IAAI,IAAI;QAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,OAAO;QACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,IAAI;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,IAAI;QAChC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,sBAAsB;QAC1D,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,IAAI,CAAC;KAC5C,CAAC,CAAC;AACL,CAAC;AAED,mFAAmF;AACnF,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,KAAY;QAAZ,UAAK,GAAL,KAAK,CAAO;IAAG,CAAC;IAE7C,8FAA8F;IAC9F,IAAI,KAAK;QACP,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,MAAM,CAAC,GAAiB;IACtC,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,CAAyB,EAAkC,EAAE,EAAE,CACpE,KAAK,EAAE,GAAG,IAAO,EAA0B,EAAE;QAC3C,gBAAgB,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,CAAC,GAAG,aAAa,EAAE,EAAE,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,OAAO,MAAM,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,SAAS;gBAAE,OAAO,SAAS,CAAC,CAAC,0CAA0C;YAC1F,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACN,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAAiB,EACjB,EAAuC;IAEvC,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1B,gBAAgB,EAAE,CAAC;IACnB,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,CAAC,GAAG,aAAa,EAAE,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,SAAS;YAAE,OAAO,SAAS,CAAC;QAC/C,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAUD,SAAS,SAAS,CAAI,IAA6B,EAAE,EAAwB;IAC3E,gBAAgB,EAAE,CAAC;IACnB,MAAM,MAAM,GAAG,EAAE,GAAG,WAAW,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC7C,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,KAAK,GAAkB,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAkB,CAAC;AAE1F,gGAAgG;AAEhG;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,QAAmB,EAAE,eAAe,GAAG,CAAC;IAC9E,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,yFAAyF;AACzF,MAAM,OAAO,MAAM;IACE;IAAnB,YAAmB,OAAoB,EAAE;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAE7C,CAAC,MAAM,CAAC,QAAQ,CAAC;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtC,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED,KAAK;QACH,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI;YAAE,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5D,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,+FAA+F;IAC/F,WAAW,CAAC,GAAoB,EAAE,YAAqC,EAAE;QACvE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;gBAAE,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvF,CAAC;QACD,IAAI,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;YAC3E,MAAM,IAAI,cAAc,CAAC,IAAI,KAAK,iBAAiB,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAYD;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,OAAkB;IACvC,MAAM,IAAI,GAAG,OAAO,IAAI,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;IACxC,MAAM,QAAQ,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,2DAA2D;IAC1F,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClF,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,GAA4B,EAAE,CAAC;YACzC,KAAK,MAAM,CAAC,IAAI,IAAI;gBAAE,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/E,KAAK,GAAG;gBACN,IAAI;gBACJ,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;gBACf,WAAW,EAAE,CAAC;gBACd,YAAY,EAAE,CAAC;gBACf,eAAe,EAAE,CAAC;gBAClB,KAAK,EAAE,CAAC;gBACR,aAAa,EAAE,CAAC;aACjB,CAAC;YACF,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,KAAK,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,CAAC;QACrC,KAAK,CAAC,YAAY,IAAI,GAAG,CAAC,YAAY,CAAC;QACvC,KAAK,CAAC,eAAe,IAAI,GAAG,CAAC,eAAe,CAAC;QAC7C,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC;QACzB,IAAI,GAAG,CAAC,QAAQ;YAAE,KAAK,CAAC,aAAa,IAAI,GAAG,CAAC,KAAK,CAAC;IACrD,CAAC;IACD,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;YACrB,MAAM,EAAE,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,YAAY;YACtC,YAAY,EAAE,CAAC,CAAC,WAAW;YAC3B,aAAa,EAAE,CAAC,CAAC,YAAY;YAC7B,gBAAgB,EAAE,CAAC,CAAC,eAAe;YACnC,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,cAAc,EAAE,CAAC,CAAC,aAAa;SAChC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,qGAAqG;AAErG,oGAAoG;AACpG,MAAM,UAAU,UAAU;IACxB,OAAO,CAAC,GAAG,aAAa,CAAC,CAAC;AAC5B,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,MAAM;IACpB,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC;AACxB,CAAC;AAED;4EAC4E;AAC5E,MAAM,UAAU,OAAO,CAAC,IAAiB;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC;IACtB,IAAI,GAAG,IAAI,CAAC;IACZ,OAAO,QAAQ,CAAC;AAClB,CAAC;AAQD,qGAAqG;AACrG,MAAM,UAAU,SAAS,CAAC,OAAyB,EAAE;IACnD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;QAAE,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IAChE,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,UAAU,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;YAC9D,MAAM,IAAI,UAAU,CAAC,+CAA+C,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QAC1F,CAAC;QACD,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,OAAO;IACrB,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,aAAa;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,GAAG,IAAI,OAAO;QAAE,IAAI,GAAG,CAAC,QAAQ;YAAE,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC;IAChE,OAAO,KAAK,CAAC;AACf,CAAC;AAED;gFACgF;AAChF,MAAM,UAAU,KAAK;IACnB,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IACnB,YAAY,GAAG,CAAC,CAAC;IACjB,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IACrB,cAAc,CAAC,KAAK,EAAE,CAAC;IACvB,IAAI,GAAG,IAAI,CAAC;IACZ,UAAU,GAAG,mBAAmB,CAAC;IACjC,UAAU,GAAG,mBAAmB,CAAC;IACjC,gBAAgB,EAAE,CAAC;AACrB,CAAC;AAED,oGAAoG;AACpG,+DAA+D;AAC/D,gBAAgB,EAAE,CAAC"}
|