@economicagents/graph 0.1.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/dist/index.js ADDED
@@ -0,0 +1,398 @@
1
+ /**
2
+ * Economic graph sync - indexes on-chain events to build transaction graph.
3
+ */
4
+ import { createPublicClient, http, parseAbiItem } from "viem";
5
+ import { base, baseSepolia } from "viem/chains";
6
+ import { getDatabase, insertAccount, insertPayment, insertUserOp, insertFacility, insertEscrow, insertSplitter, insertSLA, insertSLAEvent, getSyncState, setSyncState, getAccountAddresses, getFacilityAddresses, getEscrowAddresses, getSplitterAddresses, getSLAAddresses, } from "./store.js";
7
+ const CHUNK_SIZE = 9999n;
8
+ const ADDRESS_BATCH_SIZE = 50;
9
+ export async function syncGraph(config) {
10
+ const chain = config.chainId === base.id ? base : baseSepolia;
11
+ const client = createPublicClient({
12
+ chain,
13
+ transport: http(config.rpcUrl),
14
+ });
15
+ const db = getDatabase(config.graphPath);
16
+ const result = {
17
+ accountsAdded: 0,
18
+ paymentsAdded: 0,
19
+ userOpsAdded: 0,
20
+ creditEventsAdded: 0,
21
+ escrowEventsAdded: 0,
22
+ splitterEventsAdded: 0,
23
+ slaEventsAdded: 0,
24
+ };
25
+ const toBlock = await client.getBlockNumber();
26
+ // 1. Sync AccountDeployed from AEPAccountFactory
27
+ const accountFrom = BigInt(getSyncState(db, "account_factory") ?? 0) + 1n;
28
+ if (accountFrom <= toBlock) {
29
+ for (let start = accountFrom; start <= toBlock; start += CHUNK_SIZE) {
30
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
31
+ const logs = await client.getLogs({
32
+ address: config.aepAccountFactoryAddress,
33
+ event: parseAbiItem("event AccountDeployed(address indexed account, address indexed owner, bytes32 indexed salt)"),
34
+ fromBlock: start,
35
+ toBlock: end,
36
+ });
37
+ for (const log of logs) {
38
+ const args = log
39
+ .args;
40
+ if (args?.account && args?.owner) {
41
+ insertAccount(db, args.account, args.owner, Number(log.blockNumber ?? 0));
42
+ result.accountsAdded++;
43
+ }
44
+ }
45
+ setSyncState(db, "account_factory", Number(end));
46
+ }
47
+ }
48
+ // 2. Sync factory events to get child addresses
49
+ if (config.creditFacilityFactoryAddress) {
50
+ const cfFrom = BigInt(getSyncState(db, "credit_factory") ?? 0) + 1n;
51
+ if (cfFrom <= toBlock) {
52
+ for (let start = cfFrom; start <= toBlock; start += CHUNK_SIZE) {
53
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
54
+ const logs = await client.getLogs({
55
+ address: config.creditFacilityFactoryAddress,
56
+ event: parseAbiItem("event FacilityCreated(address indexed facility, address indexed lender, address indexed borrower)"),
57
+ fromBlock: start,
58
+ toBlock: end,
59
+ });
60
+ for (const log of logs) {
61
+ const args = log.args;
62
+ if (args?.facility && args?.lender && args?.borrower) {
63
+ insertFacility(db, args.facility, args.lender, args.borrower, Number(log.blockNumber ?? 0));
64
+ }
65
+ }
66
+ setSyncState(db, "credit_factory", Number(end));
67
+ }
68
+ }
69
+ }
70
+ if (config.escrowFactoryAddress) {
71
+ const escFrom = BigInt(getSyncState(db, "escrow_factory") ?? 0) + 1n;
72
+ if (escFrom <= toBlock) {
73
+ for (let start = escFrom; start <= toBlock; start += CHUNK_SIZE) {
74
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
75
+ const logs = await client.getLogs({
76
+ address: config.escrowFactoryAddress,
77
+ event: parseAbiItem("event EscrowCreated(address indexed escrow, address indexed consumer, address indexed provider)"),
78
+ fromBlock: start,
79
+ toBlock: end,
80
+ });
81
+ for (const log of logs) {
82
+ const args = log.args;
83
+ if (args?.escrow && args?.consumer && args?.provider) {
84
+ insertEscrow(db, args.escrow, args.consumer, args.provider, Number(log.blockNumber ?? 0));
85
+ }
86
+ }
87
+ setSyncState(db, "escrow_factory", Number(end));
88
+ }
89
+ }
90
+ }
91
+ if (config.revenueSplitterFactoryAddress) {
92
+ const splitFrom = BigInt(getSyncState(db, "splitter_factory") ?? 0) + 1n;
93
+ if (splitFrom <= toBlock) {
94
+ for (let start = splitFrom; start <= toBlock; start += CHUNK_SIZE) {
95
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
96
+ const logs = await client.getLogs({
97
+ address: config.revenueSplitterFactoryAddress,
98
+ event: parseAbiItem("event SplitterCreated(address indexed splitter, address indexed token)"),
99
+ fromBlock: start,
100
+ toBlock: end,
101
+ });
102
+ for (const log of logs) {
103
+ const args = log.args;
104
+ if (args?.splitter && args?.token) {
105
+ insertSplitter(db, args.splitter, args.token, Number(log.blockNumber ?? 0));
106
+ }
107
+ }
108
+ setSyncState(db, "splitter_factory", Number(end));
109
+ }
110
+ }
111
+ }
112
+ if (config.slaFactoryAddress) {
113
+ const slaFrom = BigInt(getSyncState(db, "sla_factory") ?? 0) + 1n;
114
+ if (slaFrom <= toBlock) {
115
+ for (let start = slaFrom; start <= toBlock; start += CHUNK_SIZE) {
116
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
117
+ const logs = await client.getLogs({
118
+ address: config.slaFactoryAddress,
119
+ event: parseAbiItem("event SLACreated(address indexed sla, address indexed provider, address indexed consumer)"),
120
+ fromBlock: start,
121
+ toBlock: end,
122
+ });
123
+ for (const log of logs) {
124
+ const args = log.args;
125
+ if (args?.sla && args?.provider && args?.consumer) {
126
+ insertSLA(db, args.sla, args.provider, args.consumer, Number(log.blockNumber ?? 0));
127
+ }
128
+ }
129
+ setSyncState(db, "sla_factory", Number(end));
130
+ }
131
+ }
132
+ }
133
+ // 3. Sync UserOperationEvent from EntryPoint
134
+ const epFrom = BigInt(getSyncState(db, "entry_point") ?? 0) + 1n;
135
+ if (epFrom <= toBlock) {
136
+ for (let start = epFrom; start <= toBlock; start += CHUNK_SIZE) {
137
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
138
+ const logs = await client.getLogs({
139
+ address: config.entryPointAddress,
140
+ event: parseAbiItem("event UserOperationEvent(bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed)"),
141
+ fromBlock: start,
142
+ toBlock: end,
143
+ });
144
+ for (const log of logs) {
145
+ const args = log.args;
146
+ if (args?.userOpHash && args?.sender) {
147
+ insertUserOp(db, args.userOpHash, args.sender, args.success ?? false, args.actualGasCost?.toString() ?? null, Number(log.blockNumber ?? 0), log.transactionHash ?? null);
148
+ result.userOpsAdded++;
149
+ }
150
+ }
151
+ setSyncState(db, "entry_point", Number(end));
152
+ }
153
+ }
154
+ // 4. Sync ERC-20 Transfer from USDC (filter by accounts)
155
+ const usdcFrom = BigInt(getSyncState(db, "usdc") ?? 0) + 1n;
156
+ if (usdcFrom <= toBlock) {
157
+ const accounts = new Set(getAccountAddresses(db).map((a) => a.toLowerCase()));
158
+ for (let start = usdcFrom; start <= toBlock; start += CHUNK_SIZE) {
159
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
160
+ const logs = await client.getLogs({
161
+ address: config.usdcAddress,
162
+ event: parseAbiItem("event Transfer(address indexed from, address indexed to, uint256 value)"),
163
+ fromBlock: start,
164
+ toBlock: end,
165
+ });
166
+ for (const log of logs) {
167
+ const args = log.args;
168
+ if (args?.from && args?.to && args?.value !== undefined) {
169
+ const from = args.from.toLowerCase();
170
+ const to = args.to.toLowerCase();
171
+ if (accounts.has(from) || accounts.has(to)) {
172
+ insertPayment(db, args.from, args.to, args.value.toString(), config.usdcAddress, Number(log.blockNumber ?? 0), log.transactionHash ?? "", log.logIndex ?? null, "transfer");
173
+ result.paymentsAdded++;
174
+ }
175
+ }
176
+ }
177
+ setSyncState(db, "usdc", Number(end));
178
+ }
179
+ }
180
+ // 5. Sync CreditFacility events (Drawn, Repaid, DefaultDeclared)
181
+ const facilities = getFacilityAddresses(db);
182
+ if (facilities.length > 0) {
183
+ const cfEvFrom = BigInt(getSyncState(db, "credit_events") ?? 0) + 1n;
184
+ if (cfEvFrom <= toBlock) {
185
+ for (let start = cfEvFrom; start <= toBlock; start += CHUNK_SIZE) {
186
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
187
+ const drawnLogs = [];
188
+ const repaidLogs = [];
189
+ for (let i = 0; i < facilities.length; i += ADDRESS_BATCH_SIZE) {
190
+ const batch = facilities.slice(i, i + ADDRESS_BATCH_SIZE);
191
+ const [d, r] = await Promise.all([
192
+ client.getLogs({
193
+ address: batch,
194
+ event: parseAbiItem("event Drawn(address indexed borrower, uint256 amount)"),
195
+ fromBlock: start,
196
+ toBlock: end,
197
+ }),
198
+ client.getLogs({
199
+ address: batch,
200
+ event: parseAbiItem("event Repaid(address indexed borrower, uint256 amount)"),
201
+ fromBlock: start,
202
+ toBlock: end,
203
+ }),
204
+ ]);
205
+ drawnLogs.push(...d);
206
+ repaidLogs.push(...r);
207
+ }
208
+ const facilityByAddress = new Map();
209
+ for (const addr of facilities) {
210
+ const row = db
211
+ .prepare("SELECT lender, borrower FROM facilities WHERE address = ?")
212
+ .get(addr.toLowerCase());
213
+ if (row)
214
+ facilityByAddress.set(addr.toLowerCase(), row);
215
+ }
216
+ for (const log of drawnLogs) {
217
+ const args = log.args;
218
+ const fac = facilityByAddress.get((log.address ?? "").toLowerCase());
219
+ if (args?.borrower && args?.amount !== undefined && fac) {
220
+ insertPayment(db, log.address, args.borrower, args.amount.toString(), config.usdcAddress, Number(log.blockNumber ?? 0), log.transactionHash ?? "", log.logIndex ?? null, "credit_draw");
221
+ result.creditEventsAdded++;
222
+ }
223
+ }
224
+ for (const log of repaidLogs) {
225
+ const args = log.args;
226
+ const fac = facilityByAddress.get((log.address ?? "").toLowerCase());
227
+ if (args?.borrower && args?.amount !== undefined && fac) {
228
+ insertPayment(db, args.borrower, log.address, args.amount.toString(), config.usdcAddress, Number(log.blockNumber ?? 0), log.transactionHash ?? "", log.logIndex ?? null, "credit_repay");
229
+ result.creditEventsAdded++;
230
+ }
231
+ }
232
+ setSyncState(db, "credit_events", Number(end));
233
+ }
234
+ }
235
+ }
236
+ // 6. Sync ConditionalEscrow events (Funded, Released)
237
+ const escrows = getEscrowAddresses(db);
238
+ if (escrows.length > 0) {
239
+ const escEvFrom = BigInt(getSyncState(db, "escrow_events") ?? 0) + 1n;
240
+ if (escEvFrom <= toBlock) {
241
+ for (let start = escEvFrom; start <= toBlock; start += CHUNK_SIZE) {
242
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
243
+ const fundedLogs = [];
244
+ const releasedLogs = [];
245
+ for (let i = 0; i < escrows.length; i += ADDRESS_BATCH_SIZE) {
246
+ const batch = escrows.slice(i, i + ADDRESS_BATCH_SIZE);
247
+ const [f, r] = await Promise.all([
248
+ client.getLogs({
249
+ address: batch,
250
+ event: parseAbiItem("event Funded(address indexed consumer, uint256 amount)"),
251
+ fromBlock: start,
252
+ toBlock: end,
253
+ }),
254
+ client.getLogs({
255
+ address: batch,
256
+ event: parseAbiItem("event Released(address indexed provider, uint256 amount)"),
257
+ fromBlock: start,
258
+ toBlock: end,
259
+ }),
260
+ ]);
261
+ fundedLogs.push(...f);
262
+ releasedLogs.push(...r);
263
+ }
264
+ const escrowByAddress = new Map();
265
+ for (const addr of escrows) {
266
+ const row = db
267
+ .prepare("SELECT consumer, provider FROM escrows WHERE address = ?")
268
+ .get(addr.toLowerCase());
269
+ if (row)
270
+ escrowByAddress.set(addr.toLowerCase(), row);
271
+ }
272
+ for (const log of fundedLogs) {
273
+ const args = log.args;
274
+ const esc = escrowByAddress.get((log.address ?? "").toLowerCase());
275
+ if (args?.consumer && args?.amount !== undefined && esc) {
276
+ insertPayment(db, args.consumer, log.address, args.amount.toString(), config.usdcAddress, Number(log.blockNumber ?? 0), log.transactionHash ?? "", log.logIndex ?? null, "escrow_fund");
277
+ result.escrowEventsAdded++;
278
+ }
279
+ }
280
+ for (const log of releasedLogs) {
281
+ const args = log.args;
282
+ const esc = escrowByAddress.get((log.address ?? "").toLowerCase());
283
+ if (args?.provider && args?.amount !== undefined && esc) {
284
+ insertPayment(db, log.address, args.provider, args.amount.toString(), config.usdcAddress, Number(log.blockNumber ?? 0), log.transactionHash ?? "", log.logIndex ?? null, "escrow_release");
285
+ result.escrowEventsAdded++;
286
+ }
287
+ }
288
+ setSyncState(db, "escrow_events", Number(end));
289
+ }
290
+ }
291
+ }
292
+ // 7. Sync RevenueSplitter Distributed
293
+ const splitters = getSplitterAddresses(db);
294
+ if (splitters.length > 0) {
295
+ const splitEvFrom = BigInt(getSyncState(db, "splitter_events") ?? 0) + 1n;
296
+ if (splitEvFrom <= toBlock) {
297
+ for (let start = splitEvFrom; start <= toBlock; start += CHUNK_SIZE) {
298
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
299
+ let splitterLogs = [];
300
+ for (let i = 0; i < splitters.length; i += ADDRESS_BATCH_SIZE) {
301
+ const batch = splitters.slice(i, i + ADDRESS_BATCH_SIZE);
302
+ const batchLogs = await client.getLogs({
303
+ address: batch,
304
+ event: parseAbiItem("event Distributed(address indexed token, uint256 totalAmount)"),
305
+ fromBlock: start,
306
+ toBlock: end,
307
+ });
308
+ splitterLogs = splitterLogs.concat(batchLogs);
309
+ }
310
+ for (const log of splitterLogs) {
311
+ const args = log.args;
312
+ if (args?.token && args?.totalAmount !== undefined) {
313
+ insertPayment(db, log.address, log.address, args.totalAmount.toString(), args.token, Number(log.blockNumber ?? 0), log.transactionHash ?? "", log.logIndex ?? null, "splitter_distribute");
314
+ result.splitterEventsAdded++;
315
+ }
316
+ }
317
+ setSyncState(db, "splitter_events", Number(end));
318
+ }
319
+ }
320
+ }
321
+ // 8. Sync SLAContract Staked, BreachDeclared, Unstaked
322
+ const slas = getSLAAddresses(db);
323
+ if (slas.length > 0) {
324
+ const slaEvFrom = BigInt(getSyncState(db, "sla_events") ?? 0) + 1n;
325
+ if (slaEvFrom <= toBlock) {
326
+ for (let start = slaEvFrom; start <= toBlock; start += CHUNK_SIZE) {
327
+ const end = start + CHUNK_SIZE > toBlock ? toBlock : start + CHUNK_SIZE;
328
+ const stakedLogs = [];
329
+ const breachLogs = [];
330
+ const unstakedLogs = [];
331
+ for (let i = 0; i < slas.length; i += ADDRESS_BATCH_SIZE) {
332
+ const batch = slas.slice(i, i + ADDRESS_BATCH_SIZE);
333
+ const [s, b, u] = await Promise.all([
334
+ client.getLogs({
335
+ address: batch,
336
+ event: parseAbiItem("event Staked(address indexed provider, uint256 amount)"),
337
+ fromBlock: start,
338
+ toBlock: end,
339
+ }),
340
+ client.getLogs({
341
+ address: batch,
342
+ event: parseAbiItem("event BreachDeclared(address indexed consumer, bytes32 indexed requestHash, uint256 amount)"),
343
+ fromBlock: start,
344
+ toBlock: end,
345
+ }),
346
+ client.getLogs({
347
+ address: batch,
348
+ event: parseAbiItem("event Unstaked(address indexed provider, uint256 amount)"),
349
+ fromBlock: start,
350
+ toBlock: end,
351
+ }),
352
+ ]);
353
+ stakedLogs.push(...s);
354
+ breachLogs.push(...b);
355
+ unstakedLogs.push(...u);
356
+ }
357
+ const slaByAddress = new Map();
358
+ for (const addr of slas) {
359
+ const row = db
360
+ .prepare("SELECT provider, consumer FROM slas WHERE address = ?")
361
+ .get(addr.toLowerCase());
362
+ if (row)
363
+ slaByAddress.set(addr.toLowerCase(), row);
364
+ }
365
+ for (const log of stakedLogs) {
366
+ const args = log.args;
367
+ const sla = slaByAddress.get((log.address ?? "").toLowerCase());
368
+ if (args?.provider && args?.amount !== undefined && sla) {
369
+ insertSLAEvent(db, log.address, "staked", args.provider, sla.consumer, args.amount.toString(), null, Number(log.blockNumber ?? 0), log.transactionHash ?? "");
370
+ result.slaEventsAdded++;
371
+ }
372
+ }
373
+ for (const log of breachLogs) {
374
+ const args = log.args;
375
+ const sla = slaByAddress.get((log.address ?? "").toLowerCase());
376
+ if (args?.consumer && args?.amount !== undefined && sla) {
377
+ insertSLAEvent(db, log.address, "breach_declared", sla.provider, args.consumer, args.amount.toString(), args.requestHash ?? null, Number(log.blockNumber ?? 0), log.transactionHash ?? "");
378
+ result.slaEventsAdded++;
379
+ }
380
+ }
381
+ for (const log of unstakedLogs) {
382
+ const args = log.args;
383
+ const sla = slaByAddress.get((log.address ?? "").toLowerCase());
384
+ if (args?.provider && args?.amount !== undefined && sla) {
385
+ insertSLAEvent(db, log.address, "unstaked", args.provider, sla.consumer, args.amount.toString(), null, Number(log.blockNumber ?? 0), log.transactionHash ?? "");
386
+ result.slaEventsAdded++;
387
+ }
388
+ }
389
+ setSyncState(db, "sla_events", Number(end));
390
+ }
391
+ }
392
+ }
393
+ return result;
394
+ }
395
+ export { getDatabase, closeDatabase, getAccountAddresses, getFacilityAddresses, getEscrowAddresses, getSplitterAddresses, getSLAAddresses, } from "./store.js";
396
+ export { getPaymentsFrom, getPaymentsTo, getAccountAnalytics, getAccountAnalyticsInRange, computeCreditScore, computeCreditScoreInRange, getPaymentTrends, exportPaymentsCsv, getBlockRangeForPeriod, getFleetSummary, } from "./queries.js";
397
+ export { getFleetAlerts } from "./fleet-alerts.js";
398
+ export { getRecommendations } from "./recommendations.js";
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Query helpers for analytics, credit scoring, and recommendations.
3
+ */
4
+ import type { SqliteDb } from "./store.js";
5
+ export interface PaymentRow {
6
+ fromAddr: string;
7
+ toAddr: string;
8
+ amount: string;
9
+ token: string;
10
+ blockNumber: number;
11
+ source: string;
12
+ }
13
+ export interface AccountAnalytics {
14
+ address: string;
15
+ totalOutflow: string;
16
+ totalInflow: string;
17
+ netPnl: string;
18
+ paymentCount: number;
19
+ uniqueCounterparties: number;
20
+ creditDraws: number;
21
+ creditRepays: number;
22
+ defaults: number;
23
+ slaBreaches: number;
24
+ successRate: number;
25
+ }
26
+ export interface CreditScoreResult {
27
+ score: number;
28
+ factors: {
29
+ paymentConsistency: number;
30
+ revenueStability: number;
31
+ relationshipStability: number;
32
+ defaultHistory: number;
33
+ slaBreachHistory: number;
34
+ };
35
+ }
36
+ export declare function getBlockRangeForPeriod(graphPath: string, period: string): {
37
+ fromBlock: number;
38
+ toBlock: number;
39
+ } | null;
40
+ export declare function getPaymentsFrom(db: SqliteDb, address: string): PaymentRow[];
41
+ export declare function getPaymentsTo(db: SqliteDb, address: string): PaymentRow[];
42
+ export declare function getAccountAnalytics(graphPath: string, address: string): AccountAnalytics | null;
43
+ export declare function computeCreditScore(graphPath: string, address: string): CreditScoreResult;
44
+ export declare function computeCreditScoreInRange(graphPath: string, address: string, fromBlock: number, toBlock: number): CreditScoreResult;
45
+ export declare function getAccountAnalyticsInRange(graphPath: string, address: string, fromBlock: number, toBlock: number): AccountAnalytics | null;
46
+ export interface PaymentTrend {
47
+ blockBucket: number;
48
+ outflow: string;
49
+ inflow: string;
50
+ net: string;
51
+ paymentCount: number;
52
+ }
53
+ /** Rolling spend/revenue trends. Groups by block bucket (~1 day = 43200 blocks on Base). */
54
+ export declare function getPaymentTrends(graphPath: string, address: string, period: "7d" | "30d" | "90d"): PaymentTrend[];
55
+ export declare function exportPaymentsCsv(graphPath: string, address: string, fromBlock?: number, toBlock?: number): string;
56
+ export interface FleetSummary {
57
+ accountCount: number;
58
+ totalOutflow: string;
59
+ totalInflow: string;
60
+ netPnl: string;
61
+ paymentCount: number;
62
+ uniqueCounterparties: number;
63
+ accounts: Array<{
64
+ address: string;
65
+ totalOutflow: string;
66
+ totalInflow: string;
67
+ netPnl: string;
68
+ paymentCount: number;
69
+ }>;
70
+ }
71
+ export declare function getFleetSummary(graphPath: string, accountAddresses: string[]): FleetSummary;
72
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QACP,kBAAkB,EAAE,MAAM,CAAC;QAC3B,gBAAgB,EAAE,MAAM,CAAC;QACzB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAgBD,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM/C;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,MAAM,GACd,UAAU,EAAE,CAOd;AAED,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,MAAM,GACd,UAAU,EAAE,CAOd;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,gBAAgB,GAAG,IAAI,CAqEzB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,iBAAiB,CAkDnB;AAED,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,iBAAiB,CA2DnB;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,gBAAgB,GAAG,IAAI,CAkEzB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,GAC3B,YAAY,EAAE,CAgDhB;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAqCR;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EAAE,GACzB,YAAY,CAkDd"}