@kevinrabun/judges 3.23.6 → 3.23.7

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.
@@ -0,0 +1,408 @@
1
+ /**
2
+ * `judges tune` — Analyze your project and suggest optimal .judgesrc.json configuration.
3
+ *
4
+ * Runs an initial evaluation on a sample of project files, then recommends:
5
+ * - Which preset best fits your project
6
+ * - Rules to disable based on consistent FP patterns
7
+ * - Severity overrides for noisy rules
8
+ * - Framework-specific settings
9
+ *
10
+ * Usage:
11
+ * judges tune # Analyze current directory
12
+ * judges tune --dir ./src # Analyze specific directory
13
+ * judges tune --apply # Write .judgesrc.json automatically
14
+ * judges tune --max-files 20 # Limit sample size
15
+ */
16
+ import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
17
+ import { resolve, extname, join } from "path";
18
+ import { evaluateWithTribunal } from "../evaluators/index.js";
19
+ import { PRESETS } from "../presets.js";
20
+ // ─── Language Detection ─────────────────────────────────────────────────────
21
+ const EXT_TO_LANG = {
22
+ ".ts": "typescript",
23
+ ".tsx": "typescript",
24
+ ".js": "javascript",
25
+ ".jsx": "javascript",
26
+ ".mjs": "javascript",
27
+ ".cjs": "javascript",
28
+ ".py": "python",
29
+ ".rs": "rust",
30
+ ".go": "go",
31
+ ".java": "java",
32
+ ".cs": "csharp",
33
+ ".rb": "ruby",
34
+ ".php": "php",
35
+ ".swift": "swift",
36
+ ".kt": "kotlin",
37
+ ".tf": "terraform",
38
+ ".hcl": "terraform",
39
+ ".bicep": "bicep",
40
+ ".sh": "bash",
41
+ };
42
+ function detectLanguage(filePath) {
43
+ const ext = extname(filePath.toLowerCase());
44
+ if (filePath.toLowerCase().includes("dockerfile"))
45
+ return "dockerfile";
46
+ return EXT_TO_LANG[ext];
47
+ }
48
+ // ─── Framework Detection ────────────────────────────────────────────────────
49
+ function detectFramework(dir) {
50
+ const signals = [];
51
+ // Check package.json for JS/TS frameworks
52
+ const pkgPath = join(dir, "package.json");
53
+ if (existsSync(pkgPath)) {
54
+ try {
55
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
56
+ const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
57
+ if (deps["next"])
58
+ signals.push({ framework: "Next.js", preset: "nextjs", confidence: 0.95 });
59
+ if (deps["react"] && !deps["next"])
60
+ signals.push({ framework: "React", preset: "react", confidence: 0.9 });
61
+ if (deps["express"])
62
+ signals.push({ framework: "Express", preset: "express", confidence: 0.9 });
63
+ if (deps["fastify"])
64
+ signals.push({ framework: "Express", preset: "express", confidence: 0.8 });
65
+ if (deps["koa"])
66
+ signals.push({ framework: "Express", preset: "express", confidence: 0.7 });
67
+ }
68
+ catch {
69
+ // Invalid package.json
70
+ }
71
+ }
72
+ // Check for Python frameworks
73
+ const reqPath = join(dir, "requirements.txt");
74
+ const pyprojectPath = join(dir, "pyproject.toml");
75
+ const pipfilePath = join(dir, "Pipfile");
76
+ const pythonManifests = [reqPath, pyprojectPath, pipfilePath].filter(existsSync);
77
+ for (const manifest of pythonManifests) {
78
+ try {
79
+ const content = readFileSync(manifest, "utf-8").toLowerCase();
80
+ if (content.includes("fastapi"))
81
+ signals.push({ framework: "FastAPI", preset: "fastapi", confidence: 0.9 });
82
+ if (content.includes("django"))
83
+ signals.push({ framework: "Django", preset: "django", confidence: 0.9 });
84
+ if (content.includes("flask"))
85
+ signals.push({ framework: "FastAPI", preset: "fastapi", confidence: 0.7 });
86
+ }
87
+ catch {
88
+ // ignore
89
+ }
90
+ }
91
+ // Check for Java frameworks
92
+ const pomPath = join(dir, "pom.xml");
93
+ const gradlePath = join(dir, "build.gradle");
94
+ const gradleKtsPath = join(dir, "build.gradle.kts");
95
+ for (const manifest of [pomPath, gradlePath, gradleKtsPath].filter(existsSync)) {
96
+ try {
97
+ const content = readFileSync(manifest, "utf-8").toLowerCase();
98
+ if (content.includes("spring-boot") || content.includes("spring.boot"))
99
+ signals.push({ framework: "Spring Boot", preset: "spring-boot", confidence: 0.9 });
100
+ }
101
+ catch {
102
+ // ignore
103
+ }
104
+ }
105
+ // Check for Ruby frameworks
106
+ const gemfilePath = join(dir, "Gemfile");
107
+ if (existsSync(gemfilePath)) {
108
+ try {
109
+ const content = readFileSync(gemfilePath, "utf-8").toLowerCase();
110
+ if (content.includes("rails"))
111
+ signals.push({ framework: "Rails", preset: "rails", confidence: 0.9 });
112
+ }
113
+ catch {
114
+ // ignore
115
+ }
116
+ }
117
+ // Check for Terraform
118
+ const hasTfFiles = existsSync(dir) && readdirSync(dir).some((f) => f.endsWith(".tf"));
119
+ if (hasTfFiles)
120
+ signals.push({ framework: "Terraform", preset: "terraform", confidence: 0.85 });
121
+ // Check for Kubernetes
122
+ const hasK8sFiles = existsSync(dir) &&
123
+ readdirSync(dir).some((f) => {
124
+ if (!f.endsWith(".yaml") && !f.endsWith(".yml"))
125
+ return false;
126
+ try {
127
+ const content = readFileSync(join(dir, f), "utf-8");
128
+ return /apiVersion:\s/.test(content) && /kind:\s/.test(content);
129
+ }
130
+ catch {
131
+ return false;
132
+ }
133
+ });
134
+ if (hasK8sFiles)
135
+ signals.push({ framework: "Kubernetes", preset: "kubernetes", confidence: 0.8 });
136
+ // Return highest confidence signal
137
+ signals.sort((a, b) => b.confidence - a.confidence);
138
+ return signals[0];
139
+ }
140
+ // ─── File Collection ────────────────────────────────────────────────────────
141
+ function collectSampleFiles(dir, maxFiles) {
142
+ const files = [];
143
+ const skipDirs = new Set([
144
+ "node_modules",
145
+ ".git",
146
+ "dist",
147
+ "build",
148
+ ".next",
149
+ "__pycache__",
150
+ ".venv",
151
+ "venv",
152
+ "target",
153
+ "bin",
154
+ "obj",
155
+ "vendor",
156
+ ".terraform",
157
+ ]);
158
+ function walk(dirPath, depth) {
159
+ if (depth > 5 || files.length >= maxFiles)
160
+ return;
161
+ try {
162
+ const entries = readdirSync(dirPath);
163
+ for (const entry of entries) {
164
+ if (files.length >= maxFiles)
165
+ break;
166
+ if (entry.startsWith("."))
167
+ continue;
168
+ if (skipDirs.has(entry))
169
+ continue;
170
+ const fullPath = join(dirPath, entry);
171
+ try {
172
+ const stat = statSync(fullPath);
173
+ if (stat.isDirectory()) {
174
+ walk(fullPath, depth + 1);
175
+ }
176
+ else if (stat.isFile() && stat.size < 100_000) {
177
+ const lang = detectLanguage(fullPath);
178
+ if (lang) {
179
+ try {
180
+ const content = readFileSync(fullPath, "utf-8");
181
+ if (content.trim().length > 10) {
182
+ files.push({ path: fullPath, content, lang });
183
+ }
184
+ }
185
+ catch {
186
+ // Binary file or read error
187
+ }
188
+ }
189
+ }
190
+ }
191
+ catch {
192
+ // Permission error
193
+ }
194
+ }
195
+ }
196
+ catch {
197
+ // Can't read directory
198
+ }
199
+ }
200
+ walk(dir, 0);
201
+ return files;
202
+ }
203
+ // ─── Analysis & Recommendation ──────────────────────────────────────────────
204
+ function analyzeFindings(allFindings, totalFiles) {
205
+ const ruleCount = {};
206
+ const judgeCount = {};
207
+ const ruleSeverity = {};
208
+ for (const { finding } of allFindings) {
209
+ ruleCount[finding.ruleId] = (ruleCount[finding.ruleId] || 0) + 1;
210
+ ruleSeverity[finding.ruleId] = ruleSeverity[finding.ruleId] || [];
211
+ ruleSeverity[finding.ruleId].push(finding.severity);
212
+ // Extract judge name from ruleId (e.g., "SEC-001" → "security")
213
+ const parts = finding.ruleId.split("-");
214
+ if (parts.length > 1) {
215
+ const judgePrefix = parts[0];
216
+ judgeCount[judgePrefix] = (judgeCount[judgePrefix] || 0) + 1;
217
+ }
218
+ }
219
+ // Identify rules that fire on >50% of files (likely FP or style preference)
220
+ const disabledRules = [];
221
+ const severityOverrides = {};
222
+ const threshold = Math.max(totalFiles * 0.5, 3);
223
+ for (const [ruleId, count] of Object.entries(ruleCount)) {
224
+ if (count >= threshold) {
225
+ // If it fires on >80% of files, disable it entirely
226
+ if (count >= totalFiles * 0.8) {
227
+ disabledRules.push(ruleId);
228
+ }
229
+ else {
230
+ // Downgrade to info
231
+ severityOverrides[ruleId] = { severity: "info" };
232
+ }
233
+ }
234
+ }
235
+ // Identify judges with very low signal (many findings but all low/info)
236
+ const disabledJudges = [];
237
+ const statsMessage = `Analyzed ${totalFiles} files, found ${allFindings.length} findings across ${Object.keys(ruleCount).length} rules`;
238
+ const config = {};
239
+ if (disabledRules.length > 0)
240
+ config.disabledRules = disabledRules;
241
+ if (Object.keys(severityOverrides).length > 0)
242
+ config.ruleOverrides = severityOverrides;
243
+ if (disabledJudges.length > 0)
244
+ config.disabledJudges = disabledJudges;
245
+ return {
246
+ preset: undefined,
247
+ detectedFramework: undefined,
248
+ disabledRules,
249
+ severityOverrides,
250
+ disabledJudges,
251
+ statsMessage,
252
+ config,
253
+ };
254
+ }
255
+ // ─── CLI Entry Point ────────────────────────────────────────────────────────
256
+ export function parseTuneArgs(argv) {
257
+ const args = {
258
+ dir: process.cwd(),
259
+ apply: false,
260
+ maxFiles: 15,
261
+ verbose: false,
262
+ };
263
+ for (let i = 3; i < argv.length; i++) {
264
+ const arg = argv[i];
265
+ switch (arg) {
266
+ case "--dir":
267
+ case "-d":
268
+ args.dir = resolve(argv[++i]);
269
+ break;
270
+ case "--apply":
271
+ args.apply = true;
272
+ break;
273
+ case "--max-files":
274
+ args.maxFiles = parseInt(argv[++i], 10);
275
+ break;
276
+ case "--verbose":
277
+ case "-v":
278
+ args.verbose = true;
279
+ break;
280
+ default:
281
+ if (!arg.startsWith("-")) {
282
+ args.dir = resolve(arg);
283
+ }
284
+ break;
285
+ }
286
+ }
287
+ return args;
288
+ }
289
+ export function runTune(argv) {
290
+ const args = parseTuneArgs(argv);
291
+ console.log("");
292
+ console.log("╔══════════════════════════════════════════════════════════════╗");
293
+ console.log("║ Judges Panel — Tune ║");
294
+ console.log("╚══════════════════════════════════════════════════════════════╝");
295
+ console.log("");
296
+ console.log(` Analyzing: ${args.dir}`);
297
+ console.log(` Sample size: up to ${args.maxFiles} files`);
298
+ console.log("");
299
+ // 1. Detect framework
300
+ const framework = detectFramework(args.dir);
301
+ if (framework) {
302
+ console.log(` 🔍 Detected framework: ${framework.framework} (confidence: ${Math.round(framework.confidence * 100)}%)`);
303
+ console.log(` Recommended preset: ${framework.preset}`);
304
+ }
305
+ else {
306
+ console.log(" 🔍 No specific framework detected");
307
+ }
308
+ console.log("");
309
+ // 2. Collect sample files
310
+ const files = collectSampleFiles(args.dir, args.maxFiles);
311
+ if (files.length === 0) {
312
+ console.log(" ⚠️ No source files found to analyze.");
313
+ process.exit(0);
314
+ }
315
+ console.log(` 📂 Found ${files.length} files to analyze`);
316
+ // 3. Run evaluation on sample
317
+ console.log(" ⏳ Running evaluation...");
318
+ const allFindings = [];
319
+ for (const file of files) {
320
+ try {
321
+ const result = evaluateWithTribunal(file.content, file.lang);
322
+ for (const finding of result.findings) {
323
+ allFindings.push({ file: file.path, finding });
324
+ }
325
+ }
326
+ catch {
327
+ // Skip files that fail evaluation
328
+ }
329
+ }
330
+ console.log(` ✅ Found ${allFindings.length} findings`);
331
+ console.log("");
332
+ // 4. Generate recommendations
333
+ const rec = analyzeFindings(allFindings, files.length);
334
+ rec.detectedFramework = framework?.framework;
335
+ rec.preset = framework?.preset;
336
+ // Merge framework preset config
337
+ if (rec.preset && PRESETS[rec.preset]) {
338
+ const presetConfig = PRESETS[rec.preset].config;
339
+ rec.config = {
340
+ preset: rec.preset,
341
+ ...rec.config,
342
+ disabledJudges: [...new Set([...(presetConfig.disabledJudges || []), ...(rec.config.disabledJudges || [])])],
343
+ };
344
+ }
345
+ // 5. Display recommendations
346
+ console.log(" ─── Recommendations ───────────────────────────────────────");
347
+ console.log("");
348
+ console.log(` ${rec.statsMessage}`);
349
+ console.log("");
350
+ if (rec.preset) {
351
+ console.log(` 📋 Preset: "${rec.preset}"`);
352
+ }
353
+ if (rec.disabledRules.length > 0) {
354
+ console.log(` 🔇 Disable noisy rules (fire on >80% of files):`);
355
+ for (const rule of rec.disabledRules) {
356
+ console.log(` - ${rule}`);
357
+ }
358
+ }
359
+ if (Object.keys(rec.severityOverrides).length > 0) {
360
+ console.log(` 📉 Downgrade rules to info (fire on >50% of files):`);
361
+ for (const [rule, override] of Object.entries(rec.severityOverrides)) {
362
+ console.log(` - ${rule} → ${override.severity ?? "info"}`);
363
+ }
364
+ }
365
+ if ((rec.config.disabledJudges || []).length > 0) {
366
+ console.log(` ⏭️ Disabled judges (from preset + analysis):`);
367
+ for (const judge of rec.config.disabledJudges || []) {
368
+ console.log(` - ${judge}`);
369
+ }
370
+ }
371
+ console.log("");
372
+ // 6. Build final .judgesrc.json
373
+ const judgesrc = {};
374
+ if (rec.config.preset)
375
+ judgesrc.preset = rec.config.preset;
376
+ if ((rec.config.disabledRules || []).length > 0)
377
+ judgesrc.disabledRules = rec.config.disabledRules;
378
+ if (Object.keys(rec.config.ruleOverrides || {}).length > 0)
379
+ judgesrc.ruleOverrides = rec.config.ruleOverrides;
380
+ if ((rec.config.disabledJudges || []).length > 0)
381
+ judgesrc.disabledJudges = rec.config.disabledJudges;
382
+ if ((rec.config.languages || []).length > 0)
383
+ judgesrc.languages = rec.config.languages;
384
+ const configJson = JSON.stringify(judgesrc, null, 2);
385
+ console.log(" 📄 Recommended .judgesrc.json:");
386
+ console.log("");
387
+ for (const line of configJson.split("\n")) {
388
+ console.log(` ${line}`);
389
+ }
390
+ console.log("");
391
+ if (args.apply) {
392
+ const outputPath = join(args.dir, ".judgesrc.json");
393
+ if (existsSync(outputPath)) {
394
+ console.log(` ⚠️ ${outputPath} already exists — writing to .judgesrc.tuned.json instead`);
395
+ writeFileSync(join(args.dir, ".judgesrc.tuned.json"), configJson + "\n", "utf-8");
396
+ console.log(` ✅ Written to ${join(args.dir, ".judgesrc.tuned.json")}`);
397
+ }
398
+ else {
399
+ writeFileSync(outputPath, configJson + "\n", "utf-8");
400
+ console.log(` ✅ Written to ${outputPath}`);
401
+ }
402
+ }
403
+ else {
404
+ console.log(" 💡 Run `judges tune --apply` to write this config automatically.");
405
+ }
406
+ console.log("");
407
+ }
408
+ //# sourceMappingURL=tune.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tune.js","sourceRoot":"","sources":["../../src/commands/tune.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Finding Lifecycle Tracking
3
+ *
4
+ * Tracks individual findings across multiple evaluation runs, enabling:
5
+ * - New vs. recurring finding classification
6
+ * - "Fixed" detection when a finding disappears
7
+ * - Finding trend statistics (are things getting better or worse?)
8
+ * - Age tracking (how long has a finding been open?)
9
+ *
10
+ * Data stored in .judges-findings.json
11
+ */
12
+ import type { Finding, Severity } from "./types.js";
13
+ export interface TrackedFinding {
14
+ /** Stable fingerprint based on ruleId + file + code context */
15
+ fingerprint: string;
16
+ /** Rule that generated this finding */
17
+ ruleId: string;
18
+ /** Finding severity */
19
+ severity: Severity;
20
+ /** File where the finding was detected */
21
+ filePath: string;
22
+ /** Finding title for display */
23
+ title: string;
24
+ /** First seen timestamp */
25
+ firstSeen: string;
26
+ /** Last seen timestamp */
27
+ lastSeen: string;
28
+ /** Number of consecutive runs this finding has appeared */
29
+ runCount: number;
30
+ /** Whether this finding is currently active */
31
+ status: "open" | "fixed";
32
+ /** When the finding was resolved */
33
+ fixedAt?: string;
34
+ }
35
+ export interface FindingStore {
36
+ version: string;
37
+ lastRunAt: string;
38
+ runNumber: number;
39
+ findings: TrackedFinding[];
40
+ }
41
+ export interface FindingDelta {
42
+ /** Findings that appeared for the first time in this run */
43
+ introduced: TrackedFinding[];
44
+ /** Findings that are still present from previous runs */
45
+ recurring: TrackedFinding[];
46
+ /** Findings from previous runs that are no longer present */
47
+ fixed: TrackedFinding[];
48
+ /** Summary statistics */
49
+ stats: {
50
+ totalOpen: number;
51
+ totalFixed: number;
52
+ introduced: number;
53
+ recurring: number;
54
+ fixed: number;
55
+ trend: "improving" | "stable" | "degrading";
56
+ };
57
+ }
58
+ /**
59
+ * Generate a stable fingerprint for a finding that survives minor code edits.
60
+ * Based on ruleId + file path + approximate code location.
61
+ */
62
+ export declare function generateFindingFingerprint(finding: Finding, filePath: string): string;
63
+ export declare function loadFindingStore(dir?: string): FindingStore;
64
+ export declare function saveFindingStore(store: FindingStore, dir?: string): void;
65
+ /**
66
+ * Update the finding store with results from a new evaluation run.
67
+ * Returns a delta describing what changed since the last run.
68
+ *
69
+ * When `dirOrStore` is a string, reads/writes `.judges-findings.json` in that
70
+ * directory. When a `FindingStore` object is passed directly, operates
71
+ * in-memory (useful for testing) and does NOT persist to disk.
72
+ */
73
+ export declare function updateFindings(currentFindings: Array<{
74
+ finding: Finding;
75
+ filePath: string;
76
+ }>, dirOrStore?: string | FindingStore): FindingDelta;
77
+ /**
78
+ * Get summary statistics from the finding store.
79
+ */
80
+ export declare function getFindingStats(dirOrStore?: string | FindingStore): {
81
+ totalOpen: number;
82
+ totalFixed: number;
83
+ oldestOpen: string | undefined;
84
+ bySeverity: Record<string, number>;
85
+ byRule: Record<string, number>;
86
+ avgAge: number;
87
+ runCount: number;
88
+ };
89
+ /**
90
+ * Format finding delta as a human-readable summary for CLI output.
91
+ */
92
+ export declare function formatDelta(delta: FindingDelta): string;
93
+ //# sourceMappingURL=finding-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-lifecycle.d.ts","sourceRoot":"","sources":["../src/finding-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIpD,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,yDAAyD;IACzD,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,6DAA6D;IAC7D,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,yBAAyB;IACzB,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;KAC7C,CAAC;CACH;AAID;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOrF;AAMD,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAY,GAAG,YAAY,CAoBhE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,GAAE,MAAY,GAAG,IAAI,CAG7E;AAID;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,eAAe,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9D,UAAU,GAAE,MAAM,GAAG,YAAkB,GACtC,YAAY,CAmGd;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,GAAE,MAAM,GAAG,YAAkB,GAAG;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CA6BA;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAgCvD"}