vibetracking 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.
Files changed (46) hide show
  1. package/README.md +77 -0
  2. package/dist/auth.d.ts +17 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +162 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/cli.d.ts +8 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +440 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/credentials.d.ts +36 -0
  11. package/dist/credentials.d.ts.map +1 -0
  12. package/dist/credentials.js +82 -0
  13. package/dist/credentials.js.map +1 -0
  14. package/dist/cursor.d.ts +136 -0
  15. package/dist/cursor.d.ts.map +1 -0
  16. package/dist/cursor.js +400 -0
  17. package/dist/cursor.js.map +1 -0
  18. package/dist/graph-types.d.ts +152 -0
  19. package/dist/graph-types.d.ts.map +1 -0
  20. package/dist/graph-types.js +6 -0
  21. package/dist/graph-types.js.map +1 -0
  22. package/dist/native-runner.d.ts +11 -0
  23. package/dist/native-runner.d.ts.map +1 -0
  24. package/dist/native-runner.js +61 -0
  25. package/dist/native-runner.js.map +1 -0
  26. package/dist/native.d.ts +98 -0
  27. package/dist/native.d.ts.map +1 -0
  28. package/dist/native.js +309 -0
  29. package/dist/native.js.map +1 -0
  30. package/dist/sessions/types.d.ts +28 -0
  31. package/dist/sessions/types.d.ts.map +1 -0
  32. package/dist/sessions/types.js +27 -0
  33. package/dist/sessions/types.js.map +1 -0
  34. package/dist/spinner.d.ts +75 -0
  35. package/dist/spinner.d.ts.map +1 -0
  36. package/dist/spinner.js +203 -0
  37. package/dist/spinner.js.map +1 -0
  38. package/dist/submit.d.ts +23 -0
  39. package/dist/submit.d.ts.map +1 -0
  40. package/dist/submit.js +144 -0
  41. package/dist/submit.js.map +1 -0
  42. package/dist/table.d.ts +6 -0
  43. package/dist/table.d.ts.map +1 -0
  44. package/dist/table.js +10 -0
  45. package/dist/table.js.map +1 -0
  46. package/package.json +61 -0
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Cursor IDE API Client
3
+ * Fetches usage data from Cursor's dashboard API via CSV export
4
+ *
5
+ * API Endpoint: https://cursor.com/api/dashboard/export-usage-events-csv?strategy=tokens
6
+ * Authentication: WorkosCursorSessionToken cookie
7
+ *
8
+ * CSV Format:
9
+ * Date,Model,Input (w/ Cache Write),Input (w/o Cache Write),Cache Read,Output Tokens,Total Tokens,Cost,Cost to you
10
+ */
11
+ export interface CursorCredentials {
12
+ sessionToken: string;
13
+ userId?: string;
14
+ createdAt: string;
15
+ expiresAt?: string;
16
+ }
17
+ export interface CursorUsageRow {
18
+ date: string;
19
+ timestamp: number;
20
+ model: string;
21
+ inputWithCacheWrite: number;
22
+ inputWithoutCacheWrite: number;
23
+ cacheRead: number;
24
+ outputTokens: number;
25
+ totalTokens: number;
26
+ apiCost: number;
27
+ costToYou: number;
28
+ }
29
+ export interface CursorUsageData {
30
+ source: "cursor";
31
+ model: string;
32
+ providerId: string;
33
+ messageCount: number;
34
+ input: number;
35
+ output: number;
36
+ cacheRead: number;
37
+ cacheWrite: number;
38
+ reasoning: number;
39
+ cost: number;
40
+ }
41
+ export interface CursorMessageWithTimestamp {
42
+ source: "cursor";
43
+ model: string;
44
+ providerId: string;
45
+ timestamp: number;
46
+ input: number;
47
+ output: number;
48
+ cacheRead: number;
49
+ cacheWrite: number;
50
+ reasoning: number;
51
+ cost: number;
52
+ }
53
+ export declare function saveCursorCredentials(credentials: CursorCredentials): void;
54
+ export declare function loadCursorCredentials(): CursorCredentials | null;
55
+ export declare function clearCursorCredentials(): boolean;
56
+ export declare function isCursorLoggedIn(): boolean;
57
+ /**
58
+ * Check if Cursor IDE is installed on this system
59
+ */
60
+ export declare function isCursorInstalled(): boolean;
61
+ /**
62
+ * Validate Cursor session token by hitting the usage-summary endpoint
63
+ */
64
+ export declare function validateCursorSession(sessionToken: string): Promise<{
65
+ valid: boolean;
66
+ membershipType?: string;
67
+ error?: string;
68
+ }>;
69
+ /**
70
+ * Fetch usage CSV from Cursor API
71
+ */
72
+ export declare function fetchCursorUsageCsv(sessionToken: string): Promise<string>;
73
+ /**
74
+ * Parse Cursor usage CSV into structured rows
75
+ */
76
+ export declare function parseCursorCsv(csvText: string): CursorUsageRow[];
77
+ /**
78
+ * Aggregate Cursor usage by model
79
+ */
80
+ export declare function aggregateCursorByModel(rows: CursorUsageRow[]): CursorUsageData[];
81
+ /**
82
+ * Convert Cursor CSV rows to timestamped messages for graph generation
83
+ */
84
+ export declare function cursorRowsToMessages(rows: CursorUsageRow[]): CursorMessageWithTimestamp[];
85
+ /**
86
+ * Fetch and parse Cursor usage data
87
+ * Requires valid credentials to be stored
88
+ */
89
+ export declare function readCursorUsage(): Promise<{
90
+ rows: CursorUsageRow[];
91
+ byModel: CursorUsageData[];
92
+ messages: CursorMessageWithTimestamp[];
93
+ }>;
94
+ /**
95
+ * Get Cursor credentials file path (for debugging)
96
+ */
97
+ export declare function getCursorCredentialsPath(): string;
98
+ /**
99
+ * Sync Cursor usage data from API to local cache
100
+ * This downloads the CSV and saves it for the Rust module to parse
101
+ */
102
+ export declare function syncCursorCache(): Promise<{
103
+ synced: boolean;
104
+ rows: number;
105
+ error?: string;
106
+ }>;
107
+ /**
108
+ * Get the cache file path
109
+ */
110
+ export declare function getCursorCachePath(): string;
111
+ /**
112
+ * Check if cache exists and when it was last updated
113
+ */
114
+ export declare function getCursorCacheStatus(): {
115
+ exists: boolean;
116
+ lastModified?: Date;
117
+ path: string;
118
+ };
119
+ export interface CursorUnifiedMessage {
120
+ source: "cursor";
121
+ modelId: string;
122
+ providerId: string;
123
+ sessionId: string;
124
+ timestamp: number;
125
+ date: string;
126
+ tokens: {
127
+ input: number;
128
+ output: number;
129
+ cacheRead: number;
130
+ cacheWrite: number;
131
+ reasoning: number;
132
+ };
133
+ cost: number;
134
+ }
135
+ export declare function readCursorMessagesFromCache(): CursorUnifiedMessage[];
136
+ //# sourceMappingURL=cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../src/cursor.ts"],"names":[],"mappings":"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"}
package/dist/cursor.js ADDED
@@ -0,0 +1,400 @@
1
+ /**
2
+ * Cursor IDE API Client
3
+ * Fetches usage data from Cursor's dashboard API via CSV export
4
+ *
5
+ * API Endpoint: https://cursor.com/api/dashboard/export-usage-events-csv?strategy=tokens
6
+ * Authentication: WorkosCursorSessionToken cookie
7
+ *
8
+ * CSV Format:
9
+ * Date,Model,Input (w/ Cache Write),Input (w/o Cache Write),Cache Read,Output Tokens,Total Tokens,Cost,Cost to you
10
+ */
11
+ import * as fs from "node:fs";
12
+ import * as path from "node:path";
13
+ import * as os from "node:os";
14
+ import { parse as parseCsv } from "csv-parse/sync";
15
+ // ============================================================================
16
+ // Credential Management
17
+ // ============================================================================
18
+ const CONFIG_DIR = path.join(os.homedir(), ".vibetracking");
19
+ const CURSOR_CREDENTIALS_FILE = path.join(CONFIG_DIR, "cursor-credentials.json");
20
+ function ensureConfigDir() {
21
+ if (!fs.existsSync(CONFIG_DIR)) {
22
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
23
+ }
24
+ }
25
+ export function saveCursorCredentials(credentials) {
26
+ ensureConfigDir();
27
+ fs.writeFileSync(CURSOR_CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), {
28
+ encoding: "utf-8",
29
+ mode: 0o600,
30
+ });
31
+ }
32
+ export function loadCursorCredentials() {
33
+ try {
34
+ if (!fs.existsSync(CURSOR_CREDENTIALS_FILE)) {
35
+ return null;
36
+ }
37
+ const data = fs.readFileSync(CURSOR_CREDENTIALS_FILE, "utf-8");
38
+ const parsed = JSON.parse(data);
39
+ if (!parsed.sessionToken) {
40
+ return null;
41
+ }
42
+ return parsed;
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ export function clearCursorCredentials() {
49
+ try {
50
+ if (fs.existsSync(CURSOR_CREDENTIALS_FILE)) {
51
+ fs.unlinkSync(CURSOR_CREDENTIALS_FILE);
52
+ return true;
53
+ }
54
+ return false;
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
60
+ export function isCursorLoggedIn() {
61
+ return loadCursorCredentials() !== null;
62
+ }
63
+ /**
64
+ * Check if Cursor IDE is installed on this system
65
+ */
66
+ export function isCursorInstalled() {
67
+ const paths = [];
68
+ if (process.platform === "darwin") {
69
+ // macOS
70
+ paths.push("/Applications/Cursor.app");
71
+ paths.push(path.join(os.homedir(), "Applications", "Cursor.app"));
72
+ }
73
+ else if (process.platform === "linux") {
74
+ // Linux - check desktop file
75
+ paths.push(path.join(os.homedir(), ".local/share/applications/cursor.desktop"));
76
+ }
77
+ else if (process.platform === "win32") {
78
+ // Windows - common install locations
79
+ paths.push(path.join(process.env.LOCALAPPDATA || "", "Programs", "cursor", "Cursor.exe"));
80
+ paths.push(path.join(process.env.PROGRAMFILES || "", "Cursor", "Cursor.exe"));
81
+ }
82
+ return paths.some((p) => fs.existsSync(p));
83
+ }
84
+ // ============================================================================
85
+ // API Client
86
+ // ============================================================================
87
+ const CURSOR_API_BASE = "https://cursor.com";
88
+ const USAGE_CSV_ENDPOINT = `${CURSOR_API_BASE}/api/dashboard/export-usage-events-csv?strategy=tokens`;
89
+ const USAGE_SUMMARY_ENDPOINT = `${CURSOR_API_BASE}/api/usage-summary`;
90
+ /**
91
+ * Build HTTP headers for Cursor API requests
92
+ */
93
+ function buildCursorHeaders(sessionToken) {
94
+ return {
95
+ Accept: "*/*",
96
+ "Accept-Language": "en-US,en;q=0.9",
97
+ Cookie: `WorkosCursorSessionToken=${sessionToken}`,
98
+ Referer: "https://www.cursor.com/settings",
99
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
100
+ };
101
+ }
102
+ /**
103
+ * Validate Cursor session token by hitting the usage-summary endpoint
104
+ */
105
+ export async function validateCursorSession(sessionToken) {
106
+ try {
107
+ const response = await fetch(USAGE_SUMMARY_ENDPOINT, {
108
+ method: "GET",
109
+ headers: buildCursorHeaders(sessionToken),
110
+ });
111
+ if (response.status === 401 || response.status === 403) {
112
+ return { valid: false, error: "Session token expired or invalid" };
113
+ }
114
+ if (!response.ok) {
115
+ return { valid: false, error: `API returned status ${response.status}` };
116
+ }
117
+ const data = await response.json();
118
+ // Check for required fields that indicate valid auth
119
+ if (data.billingCycleStart && data.billingCycleEnd) {
120
+ return { valid: true, membershipType: data.membershipType };
121
+ }
122
+ return { valid: false, error: "Invalid response format" };
123
+ }
124
+ catch (error) {
125
+ return { valid: false, error: error.message };
126
+ }
127
+ }
128
+ /**
129
+ * Fetch usage CSV from Cursor API
130
+ */
131
+ export async function fetchCursorUsageCsv(sessionToken) {
132
+ const response = await fetch(USAGE_CSV_ENDPOINT, {
133
+ method: "GET",
134
+ headers: buildCursorHeaders(sessionToken),
135
+ });
136
+ if (response.status === 401 || response.status === 403) {
137
+ throw new Error("Cursor session expired. Please run 'vibetracking cursor login' to re-authenticate.");
138
+ }
139
+ if (!response.ok) {
140
+ throw new Error(`Cursor API returned status ${response.status}`);
141
+ }
142
+ const text = await response.text();
143
+ // Validate it's actually CSV (handle both old and new formats)
144
+ // Old: "Date,Model,..."
145
+ // New: "Date,Kind,Model,..."
146
+ if (!text.startsWith("Date,")) {
147
+ throw new Error("Invalid response from Cursor API - expected CSV format");
148
+ }
149
+ return text;
150
+ }
151
+ // ============================================================================
152
+ // CSV Parsing
153
+ // ============================================================================
154
+ /**
155
+ * Parse cost string (e.g., "$0.50" or "0.50") to number
156
+ */
157
+ function parseCost(costStr) {
158
+ if (!costStr)
159
+ return 0;
160
+ const cleaned = costStr.replace(/[$,]/g, "").trim();
161
+ const value = parseFloat(cleaned);
162
+ return isNaN(value) ? 0 : value;
163
+ }
164
+ /**
165
+ * Infer provider from model name
166
+ */
167
+ function inferProvider(model) {
168
+ const lowerModel = model.toLowerCase();
169
+ if (lowerModel.includes("claude") || lowerModel.includes("sonnet") || lowerModel.includes("opus") || lowerModel.includes("haiku")) {
170
+ return "anthropic";
171
+ }
172
+ if (lowerModel.includes("gpt") || lowerModel.includes("o1") || lowerModel.includes("o3")) {
173
+ return "openai";
174
+ }
175
+ if (lowerModel.includes("gemini")) {
176
+ return "google";
177
+ }
178
+ if (lowerModel.includes("deepseek")) {
179
+ return "deepseek";
180
+ }
181
+ if (lowerModel.includes("llama") || lowerModel.includes("mixtral")) {
182
+ return "meta";
183
+ }
184
+ return "cursor"; // Default provider
185
+ }
186
+ /**
187
+ * Parse Cursor usage CSV into structured rows
188
+ */
189
+ export function parseCursorCsv(csvText) {
190
+ try {
191
+ const records = parseCsv(csvText, {
192
+ columns: true,
193
+ skip_empty_lines: true,
194
+ trim: true,
195
+ relax_column_count: true,
196
+ });
197
+ return records
198
+ .filter((record) => record["Date"] && record["Model"])
199
+ .map((record) => {
200
+ const dateStr = record["Date"] || "";
201
+ const date = new Date(dateStr);
202
+ const isValidDate = !isNaN(date.getTime());
203
+ const dateOnly = isValidDate
204
+ ? date.toISOString().slice(0, 10)
205
+ : dateStr.length >= 10
206
+ ? dateStr.slice(0, 10)
207
+ : dateStr;
208
+ return {
209
+ date: dateOnly,
210
+ timestamp: isValidDate ? date.getTime() : 0,
211
+ model: (record["Model"] || "").trim(),
212
+ inputWithCacheWrite: parseInt(record["Input (w/ Cache Write)"] || "0", 10),
213
+ inputWithoutCacheWrite: parseInt(record["Input (w/o Cache Write)"] || "0", 10),
214
+ cacheRead: parseInt(record["Cache Read"] || "0", 10),
215
+ outputTokens: parseInt(record["Output Tokens"] || "0", 10),
216
+ totalTokens: parseInt(record["Total Tokens"] || "0", 10),
217
+ apiCost: parseCost(record["Cost"] || record["API Cost"] || "0"),
218
+ costToYou: parseCost(record["Cost to you"] || "0"),
219
+ };
220
+ });
221
+ }
222
+ catch (error) {
223
+ throw new Error(`Failed to parse Cursor CSV: ${error.message}`);
224
+ }
225
+ }
226
+ // ============================================================================
227
+ // Data Aggregation (for table display)
228
+ // ============================================================================
229
+ /**
230
+ * Aggregate Cursor usage by model
231
+ */
232
+ export function aggregateCursorByModel(rows) {
233
+ const modelMap = new Map();
234
+ for (const row of rows) {
235
+ const key = row.model;
236
+ const existing = modelMap.get(key);
237
+ // Cache write = inputWithCacheWrite - inputWithoutCacheWrite (tokens written to cache)
238
+ const cacheWrite = Math.max(0, row.inputWithCacheWrite - row.inputWithoutCacheWrite);
239
+ // Input tokens (without cache) = inputWithoutCacheWrite
240
+ const input = row.inputWithoutCacheWrite;
241
+ if (existing) {
242
+ existing.messageCount += 1;
243
+ existing.input += input;
244
+ existing.output += row.outputTokens;
245
+ existing.cacheRead += row.cacheRead;
246
+ existing.cacheWrite += cacheWrite;
247
+ existing.cost += row.costToYou || row.apiCost;
248
+ }
249
+ else {
250
+ modelMap.set(key, {
251
+ source: "cursor",
252
+ model: row.model,
253
+ providerId: inferProvider(row.model),
254
+ messageCount: 1,
255
+ input,
256
+ output: row.outputTokens,
257
+ cacheRead: row.cacheRead,
258
+ cacheWrite,
259
+ reasoning: 0, // Cursor doesn't expose reasoning tokens
260
+ cost: row.costToYou || row.apiCost,
261
+ });
262
+ }
263
+ }
264
+ return Array.from(modelMap.values()).sort((a, b) => b.cost - a.cost);
265
+ }
266
+ // ============================================================================
267
+ // Data Conversion (for graph/native module)
268
+ // ============================================================================
269
+ /**
270
+ * Convert Cursor CSV rows to timestamped messages for graph generation
271
+ */
272
+ export function cursorRowsToMessages(rows) {
273
+ return rows.map((row) => {
274
+ const cacheWrite = Math.max(0, row.inputWithCacheWrite - row.inputWithoutCacheWrite);
275
+ const input = row.inputWithoutCacheWrite;
276
+ return {
277
+ source: "cursor",
278
+ model: row.model,
279
+ providerId: inferProvider(row.model),
280
+ timestamp: row.timestamp,
281
+ input,
282
+ output: row.outputTokens,
283
+ cacheRead: row.cacheRead,
284
+ cacheWrite,
285
+ reasoning: 0,
286
+ cost: row.costToYou || row.apiCost,
287
+ };
288
+ });
289
+ }
290
+ // ============================================================================
291
+ // High-Level API
292
+ // ============================================================================
293
+ /**
294
+ * Fetch and parse Cursor usage data
295
+ * Requires valid credentials to be stored
296
+ */
297
+ export async function readCursorUsage() {
298
+ const credentials = loadCursorCredentials();
299
+ if (!credentials) {
300
+ throw new Error("Cursor not authenticated. Run 'vibetracking cursor login' first.");
301
+ }
302
+ const csvText = await fetchCursorUsageCsv(credentials.sessionToken);
303
+ const rows = parseCursorCsv(csvText);
304
+ const byModel = aggregateCursorByModel(rows);
305
+ const messages = cursorRowsToMessages(rows);
306
+ return { rows, byModel, messages };
307
+ }
308
+ /**
309
+ * Get Cursor credentials file path (for debugging)
310
+ */
311
+ export function getCursorCredentialsPath() {
312
+ return CURSOR_CREDENTIALS_FILE;
313
+ }
314
+ // ============================================================================
315
+ // Cache Management (for Rust integration)
316
+ // ============================================================================
317
+ const CURSOR_CACHE_DIR = path.join(CONFIG_DIR, "cursor-cache");
318
+ const CURSOR_CACHE_FILE = path.join(CURSOR_CACHE_DIR, "usage.csv");
319
+ function ensureCacheDir() {
320
+ if (!fs.existsSync(CURSOR_CACHE_DIR)) {
321
+ fs.mkdirSync(CURSOR_CACHE_DIR, { recursive: true, mode: 0o700 });
322
+ }
323
+ }
324
+ /**
325
+ * Sync Cursor usage data from API to local cache
326
+ * This downloads the CSV and saves it for the Rust module to parse
327
+ */
328
+ export async function syncCursorCache() {
329
+ const credentials = loadCursorCredentials();
330
+ if (!credentials) {
331
+ return { synced: false, rows: 0, error: "Not authenticated" };
332
+ }
333
+ try {
334
+ const csvText = await fetchCursorUsageCsv(credentials.sessionToken);
335
+ ensureCacheDir();
336
+ fs.writeFileSync(CURSOR_CACHE_FILE, csvText, { encoding: "utf-8", mode: 0o600 });
337
+ // Count rows for feedback
338
+ const rows = parseCursorCsv(csvText);
339
+ return { synced: true, rows: rows.length };
340
+ }
341
+ catch (error) {
342
+ return { synced: false, rows: 0, error: error.message };
343
+ }
344
+ }
345
+ /**
346
+ * Get the cache file path
347
+ */
348
+ export function getCursorCachePath() {
349
+ return CURSOR_CACHE_FILE;
350
+ }
351
+ /**
352
+ * Check if cache exists and when it was last updated
353
+ */
354
+ export function getCursorCacheStatus() {
355
+ const exists = fs.existsSync(CURSOR_CACHE_FILE);
356
+ let lastModified;
357
+ if (exists) {
358
+ try {
359
+ const stats = fs.statSync(CURSOR_CACHE_FILE);
360
+ lastModified = stats.mtime;
361
+ }
362
+ catch {
363
+ // Ignore stat errors
364
+ }
365
+ }
366
+ return { exists, lastModified, path: CURSOR_CACHE_FILE };
367
+ }
368
+ export function readCursorMessagesFromCache() {
369
+ if (!fs.existsSync(CURSOR_CACHE_FILE)) {
370
+ return [];
371
+ }
372
+ try {
373
+ const csvText = fs.readFileSync(CURSOR_CACHE_FILE, "utf-8");
374
+ const rows = parseCursorCsv(csvText);
375
+ return rows.map((row) => {
376
+ const cacheWrite = Math.max(0, row.inputWithCacheWrite - row.inputWithoutCacheWrite);
377
+ const input = row.inputWithoutCacheWrite;
378
+ return {
379
+ source: "cursor",
380
+ modelId: row.model,
381
+ providerId: inferProvider(row.model),
382
+ sessionId: `cursor-${row.date}-${row.model}`,
383
+ timestamp: row.timestamp,
384
+ date: row.date,
385
+ tokens: {
386
+ input,
387
+ output: row.outputTokens,
388
+ cacheRead: row.cacheRead,
389
+ cacheWrite,
390
+ reasoning: 0,
391
+ },
392
+ cost: row.costToYou || row.apiCost,
393
+ };
394
+ });
395
+ }
396
+ catch {
397
+ return [];
398
+ }
399
+ }
400
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../src/cursor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAoDnD,+EAA+E;AAC/E,wBAAwB;AACxB,+EAA+E;AAE/E,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAC5D,MAAM,uBAAuB,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,yBAAyB,CAAC,CAAC;AAEjF,SAAS,eAAe;IACtB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAGD,MAAM,UAAU,qBAAqB,CAAC,WAA8B;IAClE,eAAe,EAAE,CAAC;IAClB,EAAE,CAAC,aAAa,CAAC,uBAAuB,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC9E,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,uBAAuB,CAAC,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEhC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,MAA2B,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,uBAAuB,CAAC,EAAE,CAAC;YAC3C,EAAE,CAAC,UAAU,CAAC,uBAAuB,CAAC,CAAC;YACvC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,qBAAqB,EAAE,KAAK,IAAI,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,QAAQ;QACR,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC,CAAC;IACpE,CAAC;SAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACxC,6BAA6B;QAC7B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,0CAA0C,CAAC,CAAC,CAAC;IAClF,CAAC;SAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACxC,qCAAqC;QACrC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;QAC1F,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAC7C,MAAM,kBAAkB,GAAG,GAAG,eAAe,wDAAwD,CAAC;AACtG,MAAM,sBAAsB,GAAG,GAAG,eAAe,oBAAoB,CAAC;AAEtE;;GAEG;AACH,SAAS,kBAAkB,CAAC,YAAoB;IAC9C,OAAO;QACL,MAAM,EAAE,KAAK;QACb,iBAAiB,EAAE,gBAAgB;QACnC,MAAM,EAAE,4BAA4B,YAAY,EAAE;QAClD,OAAO,EAAE,iCAAiC;QAC1C,YAAY,EACV,uHAAuH;KAC1H,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,YAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,sBAAsB,EAAE;YACnD,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,kBAAkB,CAAC,YAAY,CAAC;SAC1C,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC;QACrE,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3E,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEnC,qDAAqD;QACrD,IAAI,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACnD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;QAC9D,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,YAAoB;IAC5D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kBAAkB,EAAE;QAC/C,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,kBAAkB,CAAC,YAAY,CAAC;KAC1C,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAC;IACxG,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEnC,+DAA+D;IAC/D,wBAAwB;IACxB,6BAA6B;IAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E;;GAEG;AACH,SAAS,SAAS,CAAC,OAAe;IAChC,IAAI,CAAC,OAAO;QAAE,OAAO,CAAC,CAAC;IACvB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAEvC,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAClI,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACzF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACpC,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACnE,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,QAAQ,CAAC,CAAC,mBAAmB;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,IAAI,CAAC;QACH,MAAM,OAAO,GAAkC,QAAQ,CAAC,OAAO,EAAE;YAC/D,OAAO,EAAE,IAAI;YACb,gBAAgB,EAAE,IAAI;YACtB,IAAI,EAAE,IAAI;YACV,kBAAkB,EAAE,IAAI;SACzB,CAAC,CAAC;QAEH,OAAO,OAAO;aACX,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;aACrD,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YACd,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/B,MAAM,WAAW,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3C,MAAM,QAAQ,GAAG,WAAW;gBAC1B,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;gBACjC,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE;oBACpB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;oBACtB,CAAC,CAAC,OAAO,CAAC;YAEd,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC3C,KAAK,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;gBACrC,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,wBAAwB,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;gBAC1E,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,yBAAyB,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;gBAC9E,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;gBACpD,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;gBAC1D,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC;gBACxD,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC;gBAC/D,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC;aACnD,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,+BAAgC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,uCAAuC;AACvC,+EAA+E;AAE/E;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAsB;IAC3D,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEpD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC;QACtB,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEnC,uFAAuF;QACvF,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,mBAAmB,GAAG,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACrF,wDAAwD;QACxD,MAAM,KAAK,GAAG,GAAG,CAAC,sBAAsB,CAAC;QAEzC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,YAAY,IAAI,CAAC,CAAC;YAC3B,QAAQ,CAAC,KAAK,IAAI,KAAK,CAAC;YACxB,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC,YAAY,CAAC;YACpC,QAAQ,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,CAAC;YACpC,QAAQ,CAAC,UAAU,IAAI,UAAU,CAAC;YAClC,QAAQ,CAAC,IAAI,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE;gBAChB,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;gBACpC,YAAY,EAAE,CAAC;gBACf,KAAK;gBACL,MAAM,EAAE,GAAG,CAAC,YAAY;gBACxB,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,UAAU;gBACV,SAAS,EAAE,CAAC,EAAE,yCAAyC;gBACvD,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO;aACnC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACvE,CAAC;AAED,+EAA+E;AAC/E,4CAA4C;AAC5C,+EAA+E;AAE/E;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAsB;IACzD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACtB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,mBAAmB,GAAG,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACrF,MAAM,KAAK,GAAG,GAAG,CAAC,sBAAsB,CAAC;QAEzC,OAAO;YACL,MAAM,EAAE,QAAiB;YACzB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;YACpC,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,KAAK;YACL,MAAM,EAAE,GAAG,CAAC,YAAY;YACxB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,UAAU;YACV,SAAS,EAAE,CAAC;YACZ,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO;SACnC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IAKnC,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;IAC5C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAE5C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,uBAAuB,CAAC;AACjC,CAAC;AAED,+EAA+E;AAC/E,0CAA0C;AAC1C,+EAA+E;AAE/E,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;AAC/D,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;AAEnE,SAAS,cAAc;IACrB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACrC,EAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAGD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;IAC5C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAChE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;QACpE,cAAc,EAAE,CAAC;QACjB,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAEjF,0BAA0B;QAC1B,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACrC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC;IACrE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAChD,IAAI,YAA8B,CAAC;IAEnC,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;YAC7C,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;AAC3D,CAAC;AAmBD,MAAM,UAAU,2BAA2B;IACzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QAErC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACtB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,mBAAmB,GAAG,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACrF,MAAM,KAAK,GAAG,GAAG,CAAC,sBAAsB,CAAC;YAEzC,OAAO;gBACL,MAAM,EAAE,QAAiB;gBACzB,OAAO,EAAE,GAAG,CAAC,KAAK;gBAClB,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;gBACpC,SAAS,EAAE,UAAU,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE;gBAC5C,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE;oBACN,KAAK;oBACL,MAAM,EAAE,GAAG,CAAC,YAAY;oBACxB,SAAS,EAAE,GAAG,CAAC,SAAS;oBACxB,UAAU;oBACV,SAAS,EAAE,CAAC;iBACb;gBACD,IAAI,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO;aACnC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}