@tokenbuddy/tokenbuddy 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/buyer-store.d.ts +13 -0
- package/dist/src/buyer-store.d.ts.map +1 -1
- package/dist/src/buyer-store.js +21 -2
- package/dist/src/buyer-store.js.map +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +54 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/credit-tracker.d.ts +118 -0
- package/dist/src/credit-tracker.d.ts.map +1 -0
- package/dist/src/credit-tracker.js +220 -0
- package/dist/src/credit-tracker.js.map +1 -0
- package/dist/src/daemon.d.ts +49 -4
- package/dist/src/daemon.d.ts.map +1 -1
- package/dist/src/daemon.js +541 -405
- package/dist/src/daemon.js.map +1 -1
- package/dist/src/model-index.d.ts +86 -0
- package/dist/src/model-index.d.ts.map +1 -0
- package/dist/src/model-index.js +214 -0
- package/dist/src/model-index.js.map +1 -0
- package/dist/src/prewarm-cache.d.ts +149 -0
- package/dist/src/prewarm-cache.d.ts.map +1 -0
- package/dist/src/prewarm-cache.js +288 -0
- package/dist/src/prewarm-cache.js.map +1 -0
- package/dist/src/prewarm-scheduler.d.ts +150 -0
- package/dist/src/prewarm-scheduler.d.ts.map +1 -0
- package/dist/src/prewarm-scheduler.js +484 -0
- package/dist/src/prewarm-scheduler.js.map +1 -0
- package/dist/src/provider-install.d.ts.map +1 -1
- package/dist/src/provider-install.js +9 -1
- package/dist/src/provider-install.js.map +1 -1
- package/dist/src/route-failover.d.ts +96 -0
- package/dist/src/route-failover.d.ts.map +1 -0
- package/dist/src/route-failover.js +177 -0
- package/dist/src/route-failover.js.map +1 -0
- package/dist/src/seller-catalog.d.ts +26 -0
- package/dist/src/seller-catalog.d.ts.map +1 -1
- package/dist/src/seller-catalog.js +40 -0
- package/dist/src/seller-catalog.js.map +1 -1
- package/dist/src/seller-pool.d.ts +127 -0
- package/dist/src/seller-pool.d.ts.map +1 -0
- package/dist/src/seller-pool.js +243 -0
- package/dist/src/seller-pool.js.map +1 -0
- package/dist/src/stream-failover.d.ts +78 -0
- package/dist/src/stream-failover.d.ts.map +1 -0
- package/dist/src/stream-failover.js +93 -0
- package/dist/src/stream-failover.js.map +1 -0
- package/package.json +1 -1
- package/src/buyer-store.ts +32 -2
- package/src/cli.ts +61 -0
- package/src/credit-tracker.test.ts +165 -0
- package/src/credit-tracker.ts +269 -0
- package/src/daemon.ts +569 -445
- package/src/model-index.test.ts +184 -0
- package/src/model-index.ts +266 -0
- package/src/prewarm-cache.test.ts +281 -0
- package/src/prewarm-cache.ts +373 -0
- package/src/prewarm-scheduler.test.ts +367 -0
- package/src/prewarm-scheduler.ts +581 -0
- package/src/provider-install.ts +9 -1
- package/src/route-failover.test.ts +193 -0
- package/src/route-failover.ts +233 -0
- package/src/seller-catalog-413.test.ts +61 -0
- package/src/seller-catalog.ts +47 -0
- package/src/seller-pool.test.ts +231 -0
- package/src/seller-pool.ts +333 -0
- package/src/stream-failover.test.ts +52 -0
- package/src/stream-failover.ts +129 -0
- package/src/thousand-seller.test.ts +151 -0
- package/tests/daemon-413-fallback.test.ts +92 -0
- package/tests/e2e.test.ts +3 -2
- package/tests/tokenbuddy.test.ts +68 -11
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { createModuleLogger } from "@tokenbuddy/logging";
|
|
2
|
+
const logger = createModuleLogger("tb-proxyd:credit-tracker");
|
|
3
|
+
/**
|
|
4
|
+
* Default window after a successful purchase during which failover is
|
|
5
|
+
* softened (see buyer-driven-fallback-design.md §17.3). 30 seconds is the
|
|
6
|
+
* v1.1 starting point; v1.2 keeps the same value.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_FRESH_PURCHASE_WINDOW_MS = 30_000;
|
|
9
|
+
/**
|
|
10
|
+
* Default threshold of "still considered fresh": the current balance must
|
|
11
|
+
* still cover this fraction of the last purchase amount for the entry to
|
|
12
|
+
* be treated as "刚买". 0.5 means "at least half of the purchased credit is
|
|
13
|
+
* still untouched".
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_FRESH_PURCHASE_THRESHOLD = 0.5;
|
|
16
|
+
/**
|
|
17
|
+
* Maximum number of automatic purchases a single session may trigger per
|
|
18
|
+
* minute. When the budget is exhausted, route-failover must `切` rather than
|
|
19
|
+
* `重买` (see §17.5).
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_PURCHASE_BUDGET_PER_MINUTE = 3;
|
|
22
|
+
/**
|
|
23
|
+
* Tracks per-seller credit state for the buyer-driven-fallback design's
|
|
24
|
+
* "balance protection" rules. The tracker is intentionally agnostic of the
|
|
25
|
+
* actual seller HTTP layer: callers feed in `recordPurchase`,
|
|
26
|
+
* `recordSpend`, and `transferLeftover` events as they observe them, and
|
|
27
|
+
* the tracker answers "is this seller still inside its fresh-purchase
|
|
28
|
+
* window?" / "may I auto-purchase again this minute?".
|
|
29
|
+
*
|
|
30
|
+
* The tracker is process-local: a buyer restart resets the session
|
|
31
|
+
* counters. See §17.11.4 for the rationale.
|
|
32
|
+
*/
|
|
33
|
+
export class CreditTracker {
|
|
34
|
+
freshPurchaseWindowMs;
|
|
35
|
+
freshPurchaseThreshold;
|
|
36
|
+
purchaseBudgetPerMinute;
|
|
37
|
+
now;
|
|
38
|
+
entries = new Map();
|
|
39
|
+
purchaseTimestamps = [];
|
|
40
|
+
totalWastedMicros = 0;
|
|
41
|
+
wastedSinceLastDoctorRun = 0;
|
|
42
|
+
constructor(options = {}) {
|
|
43
|
+
this.freshPurchaseWindowMs = options.freshPurchaseWindowMs ?? DEFAULT_FRESH_PURCHASE_WINDOW_MS;
|
|
44
|
+
this.freshPurchaseThreshold = options.freshPurchaseThreshold ?? DEFAULT_FRESH_PURCHASE_THRESHOLD;
|
|
45
|
+
this.purchaseBudgetPerMinute = options.purchaseBudgetPerMinute ?? DEFAULT_PURCHASE_BUDGET_PER_MINUTE;
|
|
46
|
+
this.now = options.now ?? Date.now;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Register a successful purchase. Updates the seller's balance, the
|
|
50
|
+
* session-wide budget window, and the "fresh purchase" timestamps. If
|
|
51
|
+
* the seller is unknown, an entry is created.
|
|
52
|
+
*/
|
|
53
|
+
recordPurchase(sellerId, amountMicros, balanceMicros) {
|
|
54
|
+
if (!Number.isFinite(amountMicros) || amountMicros <= 0) {
|
|
55
|
+
throw new Error("recordPurchase requires a positive amountMicros");
|
|
56
|
+
}
|
|
57
|
+
const ts = this.now();
|
|
58
|
+
const previous = this.entries.get(sellerId);
|
|
59
|
+
const entry = {
|
|
60
|
+
sellerId,
|
|
61
|
+
lastPurchaseAt: ts,
|
|
62
|
+
lastPurchaseAmountMicros: amountMicros,
|
|
63
|
+
currentBalanceMicros: Math.max(0, balanceMicros),
|
|
64
|
+
leftoverCreditMicros: previous?.leftoverCreditMicros ?? 0,
|
|
65
|
+
lastUpdatedAt: ts
|
|
66
|
+
};
|
|
67
|
+
this.entries.set(sellerId, entry);
|
|
68
|
+
this.purchaseTimestamps.push(ts);
|
|
69
|
+
this.prunePurchaseTimestamps(ts);
|
|
70
|
+
logger.info("credit.purchase.recorded", "seller credit purchase recorded", {
|
|
71
|
+
sellerId,
|
|
72
|
+
amountMicros,
|
|
73
|
+
balanceMicros: entry.currentBalanceMicros,
|
|
74
|
+
purchasesInLastMinute: this.purchaseTimestamps.length
|
|
75
|
+
});
|
|
76
|
+
return entry;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Update the seller's current balance after a successful inference. The
|
|
80
|
+
* amount spent is implicit (`previous - next`) so the caller does not
|
|
81
|
+
* have to track it. A non-positive `balanceMicros` is treated as 0.
|
|
82
|
+
*/
|
|
83
|
+
recordSpend(sellerId, balanceMicros) {
|
|
84
|
+
const previous = this.entries.get(sellerId);
|
|
85
|
+
if (!previous) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const next = {
|
|
89
|
+
...previous,
|
|
90
|
+
currentBalanceMicros: Math.max(0, balanceMicros),
|
|
91
|
+
lastUpdatedAt: this.now()
|
|
92
|
+
};
|
|
93
|
+
this.entries.set(sellerId, next);
|
|
94
|
+
return next;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Move the seller's remaining balance to the `leftoverCreditMicros`
|
|
98
|
+
* bucket. Called when failover triggers while a balance is still
|
|
99
|
+
* available. The pool's pre-warm / probe logic can later attempt to
|
|
100
|
+
* consume the leftover credit (see PR-3.1). The wasted amount is also
|
|
101
|
+
* added to the session-level counters.
|
|
102
|
+
*/
|
|
103
|
+
transferLeftoverToWasted(sellerId, reason) {
|
|
104
|
+
const previous = this.entries.get(sellerId);
|
|
105
|
+
if (!previous) {
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
const wasted = previous.currentBalanceMicros;
|
|
109
|
+
if (wasted <= 0) {
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
const next = {
|
|
113
|
+
...previous,
|
|
114
|
+
currentBalanceMicros: 0,
|
|
115
|
+
leftoverCreditMicros: previous.leftoverCreditMicros + wasted,
|
|
116
|
+
lastUpdatedAt: this.now()
|
|
117
|
+
};
|
|
118
|
+
this.entries.set(sellerId, next);
|
|
119
|
+
this.totalWastedMicros += wasted;
|
|
120
|
+
this.wastedSinceLastDoctorRun += wasted;
|
|
121
|
+
logger.warn("credit.leftover.wasted", "leftover credit logged as wasted on failover", {
|
|
122
|
+
sellerId,
|
|
123
|
+
wastedMicros: wasted,
|
|
124
|
+
reason,
|
|
125
|
+
totalWastedMicros: this.totalWastedMicros
|
|
126
|
+
});
|
|
127
|
+
return wasted;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Consume leftover credit when the seller recovers and a probe
|
|
131
|
+
* successfully burns it down. Returns the amount actually consumed.
|
|
132
|
+
*/
|
|
133
|
+
consumeLeftover(sellerId, amountMicros) {
|
|
134
|
+
const previous = this.entries.get(sellerId);
|
|
135
|
+
if (!previous || previous.leftoverCreditMicros <= 0) {
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
const consume = Math.max(0, Math.min(amountMicros, previous.leftoverCreditMicros));
|
|
139
|
+
if (consume <= 0) {
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
const next = {
|
|
143
|
+
...previous,
|
|
144
|
+
leftoverCreditMicros: previous.leftoverCreditMicros - consume,
|
|
145
|
+
lastUpdatedAt: this.now()
|
|
146
|
+
};
|
|
147
|
+
this.entries.set(sellerId, next);
|
|
148
|
+
logger.info("credit.leftover.consumed", "leftover credit consumed by recovery probe", {
|
|
149
|
+
sellerId,
|
|
150
|
+
consumedMicros: consume,
|
|
151
|
+
remainingMicros: next.leftoverCreditMicros
|
|
152
|
+
});
|
|
153
|
+
return consume;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Returns `true` when the seller is still inside the fresh-purchase
|
|
157
|
+
* window: at least `freshPurchaseThreshold` of the most recent
|
|
158
|
+
* purchase is still unused, and the window has not elapsed. Sellers
|
|
159
|
+
* with no recorded purchase are never "fresh".
|
|
160
|
+
*/
|
|
161
|
+
isInFreshPurchaseWindow(sellerId, now = this.now()) {
|
|
162
|
+
const entry = this.entries.get(sellerId);
|
|
163
|
+
if (!entry || entry.lastPurchaseAmountMicros <= 0) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
if (now - entry.lastPurchaseAt > this.freshPurchaseWindowMs) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const ratio = entry.currentBalanceMicros / entry.lastPurchaseAmountMicros;
|
|
170
|
+
return ratio >= this.freshPurchaseThreshold;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Returns `true` when the per-minute auto-purchase budget is still
|
|
174
|
+
* available. Used by `route-failover` to refuse auto-repurchase and
|
|
175
|
+
* force a clean `切` once the session is at risk of over-spending.
|
|
176
|
+
*/
|
|
177
|
+
canAutoPurchase(now = this.now()) {
|
|
178
|
+
this.prunePurchaseTimestamps(now);
|
|
179
|
+
return this.purchaseTimestamps.length < this.purchaseBudgetPerMinute;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Snapshot for `tb doctor`. Mirrors the design's "Credit Usage" block.
|
|
183
|
+
*/
|
|
184
|
+
summary() {
|
|
185
|
+
return {
|
|
186
|
+
totalWastedMicros: this.totalWastedMicros,
|
|
187
|
+
wastedSinceLastDoctorRun: this.wastedSinceLastDoctorRun,
|
|
188
|
+
purchasesInLastMinute: this.purchaseTimestamps.length,
|
|
189
|
+
purchaseBudgetPerMinute: this.purchaseBudgetPerMinute,
|
|
190
|
+
freshPurchaseWindowMs: this.freshPurchaseWindowMs,
|
|
191
|
+
freshPurchaseThreshold: this.freshPurchaseThreshold,
|
|
192
|
+
perSeller: Array.from(this.entries.values()).map((entry) => ({
|
|
193
|
+
sellerId: entry.sellerId,
|
|
194
|
+
currentBalanceMicros: entry.currentBalanceMicros,
|
|
195
|
+
lastPurchaseAmountMicros: entry.lastPurchaseAmountMicros,
|
|
196
|
+
lastPurchaseAt: entry.lastPurchaseAt,
|
|
197
|
+
leftoverCreditMicros: entry.leftoverCreditMicros
|
|
198
|
+
}))
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
getEntry(sellerId) {
|
|
202
|
+
return this.entries.get(sellerId);
|
|
203
|
+
}
|
|
204
|
+
resetDoctorRunCounter() {
|
|
205
|
+
this.wastedSinceLastDoctorRun = 0;
|
|
206
|
+
}
|
|
207
|
+
clear() {
|
|
208
|
+
this.entries.clear();
|
|
209
|
+
this.purchaseTimestamps.length = 0;
|
|
210
|
+
this.totalWastedMicros = 0;
|
|
211
|
+
this.wastedSinceLastDoctorRun = 0;
|
|
212
|
+
}
|
|
213
|
+
prunePurchaseTimestamps(now) {
|
|
214
|
+
const cutoff = now - 60_000;
|
|
215
|
+
while (this.purchaseTimestamps.length > 0 && this.purchaseTimestamps[0] < cutoff) {
|
|
216
|
+
this.purchaseTimestamps.shift();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=credit-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credit-tracker.js","sourceRoot":"","sources":["../../src/credit-tracker.ts"],"names":[],"mappings":"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"}
|
package/dist/src/daemon.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ export interface DaemonConfig {
|
|
|
5
5
|
sellerRegistryUrl: string;
|
|
6
6
|
selectionMode?: "auto" | "manual";
|
|
7
7
|
selectedSellerId?: string;
|
|
8
|
+
warmupModels?: string[];
|
|
9
|
+
warmupRefreshIntervalSecs?: number;
|
|
10
|
+
warmupProbeTimeoutMs?: number;
|
|
8
11
|
}
|
|
9
12
|
export declare class TokenbuddyDaemon {
|
|
10
13
|
private config;
|
|
@@ -14,9 +17,17 @@ export declare class TokenbuddyDaemon {
|
|
|
14
17
|
private selectionMode;
|
|
15
18
|
private selectedSellerId?;
|
|
16
19
|
private activePurchases;
|
|
20
|
+
private readonly modelIndex;
|
|
21
|
+
private readonly prewarmCache;
|
|
22
|
+
private readonly creditTracker;
|
|
23
|
+
private readonly sellerPool;
|
|
24
|
+
private readonly routeFailover;
|
|
25
|
+
private readonly prewarmScheduler;
|
|
17
26
|
constructor(config: DaemonConfig);
|
|
27
|
+
private buildHealthProber;
|
|
18
28
|
private activeControlPort;
|
|
19
29
|
private activeProxyPort;
|
|
30
|
+
private lastRegistrySnapshot;
|
|
20
31
|
private fetchRegistry;
|
|
21
32
|
private runtimeSummary;
|
|
22
33
|
private endpointProtocol;
|
|
@@ -27,11 +38,23 @@ export declare class TokenbuddyDaemon {
|
|
|
27
38
|
private applyResolvedModelToBody;
|
|
28
39
|
private defaultPaymentMethod;
|
|
29
40
|
private selectSellerRoutes;
|
|
30
|
-
private logRouteSelected;
|
|
31
|
-
private shouldFailoverStatus;
|
|
32
|
-
private logFailover;
|
|
33
41
|
private failoverErrorMessage;
|
|
34
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Map an HTTP status from a failed seller call to a `FailureKind` that
|
|
44
|
+
* the route-failover controller understands. Hard 4xx (other than
|
|
45
|
+
* auth/insufficient) means the seller is wrong for the request; 5xx
|
|
46
|
+
* and 429 are treated as transient and eligible for the soft-failure
|
|
47
|
+
* retry budget. The v1.1 "insufficient funds" check stays on the
|
|
48
|
+
* caller side because it short-circuits the failure path with a
|
|
49
|
+
* re-purchase.
|
|
50
|
+
*/
|
|
51
|
+
private classifyFailureStatus;
|
|
52
|
+
/**
|
|
53
|
+
* Emit the structured failover log line. The decision itself is
|
|
54
|
+
* produced by `RouteFailover.decide`; this helper exists only to keep
|
|
55
|
+
* the controller loop readable.
|
|
56
|
+
*/
|
|
57
|
+
private handleFailoverDecision;
|
|
35
58
|
private listSellerBackedModels;
|
|
36
59
|
private readUsage;
|
|
37
60
|
private parseSellerSettlementSummary;
|
|
@@ -42,6 +65,21 @@ export declare class TokenbuddyDaemon {
|
|
|
42
65
|
private inferPromptForHash;
|
|
43
66
|
private autoPurchaseAmountUsdMicros;
|
|
44
67
|
private tokenRebuyMinBalanceMicros;
|
|
68
|
+
/**
|
|
69
|
+
* v1.2 §8: hard per-request deadline. The buyer refuses to wait longer
|
|
70
|
+
* than this for a single seller; on expiry the request is aborted and
|
|
71
|
+
* the route-failover controller can either retry the same seller with
|
|
72
|
+
* a smaller body or fail over. Configurable via
|
|
73
|
+
* `TB_PROXYD_REQUEST_DEADLINE_MS` (default 30s).
|
|
74
|
+
*/
|
|
75
|
+
private requestDeadlineMs;
|
|
76
|
+
/**
|
|
77
|
+
* Safety margin subtracted from the cached token's `expiresAt` before
|
|
78
|
+
* deciding to reuse it. Buying a new token 60s before expiry gives the
|
|
79
|
+
* upstream enough headroom to reject any in-flight calls under the old
|
|
80
|
+
* token before the buyer assumes the new one is valid.
|
|
81
|
+
*/
|
|
82
|
+
private tokenExpirySafetyMarginMs;
|
|
45
83
|
private getOrPurchaseToken;
|
|
46
84
|
private resolvePaymentProof;
|
|
47
85
|
private runClawtipProofCommand;
|
|
@@ -49,6 +87,13 @@ export declare class TokenbuddyDaemon {
|
|
|
49
87
|
private copyUpstreamHeaders;
|
|
50
88
|
private forwardProxyRequest;
|
|
51
89
|
start(): void;
|
|
90
|
+
/**
|
|
91
|
+
* v1.2 §18.4: build the focus set from the explicit config, the env
|
|
92
|
+
* override, and the historical usage in the buyer store. The order of
|
|
93
|
+
* precedence: explicit config > env > historical > empty.
|
|
94
|
+
*/
|
|
95
|
+
private resolveFocusSet;
|
|
96
|
+
private runStartupPrewarmSweep;
|
|
52
97
|
stop(): void;
|
|
53
98
|
}
|
|
54
99
|
//# sourceMappingURL=daemon.d.ts.map
|
package/dist/src/daemon.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/daemon.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/daemon.ts"],"names":[],"mappings":"AAsCA,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAI1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAkJD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,aAAa,CAAC,CAAM;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAM;IAC1B,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAElC,OAAO,CAAC,eAAe,CAAsC;IAK7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;IACrD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAIxB;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAG3B;IAIH,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;gBAEzC,MAAM,EAAE,YAAY;IAwBhC,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,oBAAoB,CAAuC;YAErD,aAAa;IAgC3B,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,sBAAsB;IAoB9B,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,wBAAwB;IAehC,OAAO,CAAC,oBAAoB;YAKd,kBAAkB;IAyDhC,OAAO,CAAC,oBAAoB;IAI5B;;;;;;;;OAQG;IACH,OAAO,CAAC,qBAAqB;IAa7B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;YAqBhB,sBAAsB;IAWpC,OAAO,CAAC,SAAS;IA8BjB,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,yBAAyB;YAkDnB,oBAAoB;IA0ClC,OAAO,CAAC,2BAA2B;YAcrB,4BAA4B;IAkB1C,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,2BAA2B;IASnC,OAAO,CAAC,0BAA0B;IASlC;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAYzB;;;;;OAKG;IACH,OAAO,CAAC,yBAAyB;YAYnB,kBAAkB;YA4KlB,mBAAmB;IA2BjC,OAAO,CAAC,sBAAsB;IAkF9B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,mBAAmB;YAUb,mBAAmB;IAwU1B,KAAK;IA8TZ;;;;OAIG;IACH,OAAO,CAAC,eAAe;YAaT,sBAAsB;IAmB7B,IAAI;CAMZ"}
|