@compilr-dev/agents-coding-python 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/LICENSE +21 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/parser/index.d.ts +6 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +5 -0
- package/dist/parser/node-types.d.ts +119 -0
- package/dist/parser/node-types.d.ts.map +1 -0
- package/dist/parser/node-types.js +4 -0
- package/dist/parser/python-parser.d.ts +85 -0
- package/dist/parser/python-parser.d.ts.map +1 -0
- package/dist/parser/python-parser.js +477 -0
- package/dist/skills/index.d.ts +26 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +36 -0
- package/dist/skills/python-best-practices.d.ts +7 -0
- package/dist/skills/python-best-practices.d.ts.map +1 -0
- package/dist/skills/python-best-practices.js +78 -0
- package/dist/skills/python-code-health.d.ts +7 -0
- package/dist/skills/python-code-health.d.ts.map +1 -0
- package/dist/skills/python-code-health.js +209 -0
- package/dist/skills/python-code-structure.d.ts +7 -0
- package/dist/skills/python-code-structure.d.ts.map +1 -0
- package/dist/skills/python-code-structure.js +155 -0
- package/dist/skills/python-dependency-audit.d.ts +7 -0
- package/dist/skills/python-dependency-audit.d.ts.map +1 -0
- package/dist/skills/python-dependency-audit.js +246 -0
- package/dist/skills/python-refactor-impact.d.ts +7 -0
- package/dist/skills/python-refactor-impact.d.ts.map +1 -0
- package/dist/skills/python-refactor-impact.js +232 -0
- package/dist/tools/extract-docstrings.d.ts +70 -0
- package/dist/tools/extract-docstrings.d.ts.map +1 -0
- package/dist/tools/extract-docstrings.js +575 -0
- package/dist/tools/find-dead-code.d.ts +62 -0
- package/dist/tools/find-dead-code.d.ts.map +1 -0
- package/dist/tools/find-dead-code.js +422 -0
- package/dist/tools/find-duplicates.d.ts +65 -0
- package/dist/tools/find-duplicates.d.ts.map +1 -0
- package/dist/tools/find-duplicates.js +289 -0
- package/dist/tools/find-implementations.d.ts +71 -0
- package/dist/tools/find-implementations.d.ts.map +1 -0
- package/dist/tools/find-implementations.js +342 -0
- package/dist/tools/find-patterns.d.ts +71 -0
- package/dist/tools/find-patterns.d.ts.map +1 -0
- package/dist/tools/find-patterns.js +477 -0
- package/dist/tools/find-references.d.ts +66 -0
- package/dist/tools/find-references.d.ts.map +1 -0
- package/dist/tools/find-references.js +306 -0
- package/dist/tools/find-symbol.d.ts +86 -0
- package/dist/tools/find-symbol.d.ts.map +1 -0
- package/dist/tools/find-symbol.js +414 -0
- package/dist/tools/get-call-graph.d.ts +89 -0
- package/dist/tools/get-call-graph.d.ts.map +1 -0
- package/dist/tools/get-call-graph.js +431 -0
- package/dist/tools/get-class-hierarchy.d.ts +38 -0
- package/dist/tools/get-class-hierarchy.d.ts.map +1 -0
- package/dist/tools/get-class-hierarchy.js +289 -0
- package/dist/tools/get-complexity.d.ts +61 -0
- package/dist/tools/get-complexity.d.ts.map +1 -0
- package/dist/tools/get-complexity.js +384 -0
- package/dist/tools/get-dependency-graph.d.ts +85 -0
- package/dist/tools/get-dependency-graph.d.ts.map +1 -0
- package/dist/tools/get-dependency-graph.js +387 -0
- package/dist/tools/get-exports.d.ts +78 -0
- package/dist/tools/get-exports.d.ts.map +1 -0
- package/dist/tools/get-exports.js +437 -0
- package/dist/tools/get-file-structure.d.ts +28 -0
- package/dist/tools/get-file-structure.d.ts.map +1 -0
- package/dist/tools/get-file-structure.js +186 -0
- package/dist/tools/get-imports.d.ts +34 -0
- package/dist/tools/get-imports.d.ts.map +1 -0
- package/dist/tools/get-imports.js +455 -0
- package/dist/tools/get-signature.d.ts +100 -0
- package/dist/tools/get-signature.d.ts.map +1 -0
- package/dist/tools/get-signature.js +800 -0
- package/dist/tools/index.d.ts +55 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +75 -0
- package/dist/tools/types.d.ts +378 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/package.json +85 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* findDuplicates Tool
|
|
3
|
+
*
|
|
4
|
+
* Detect duplicate code blocks in Python files using content hashing.
|
|
5
|
+
* Helps identify opportunities for refactoring and code reuse.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import * as crypto from "node:crypto";
|
|
10
|
+
import { defineTool, createSuccessResult, createErrorResult, } from "@compilr-dev/agents";
|
|
11
|
+
// Tool description
|
|
12
|
+
const TOOL_DESCRIPTION = `Detect duplicate code blocks in Python files.
|
|
13
|
+
Uses content hashing to find similar code patterns.
|
|
14
|
+
Useful for identifying refactoring opportunities and reducing code duplication.`;
|
|
15
|
+
// Tool input schema
|
|
16
|
+
const TOOL_INPUT_SCHEMA = {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
path: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "Directory to analyze",
|
|
22
|
+
},
|
|
23
|
+
minLines: {
|
|
24
|
+
type: "number",
|
|
25
|
+
description: "Minimum lines for a duplicate (default: 6)",
|
|
26
|
+
default: 6,
|
|
27
|
+
},
|
|
28
|
+
minTokens: {
|
|
29
|
+
type: "number",
|
|
30
|
+
description: "Minimum tokens for a duplicate (default: 50)",
|
|
31
|
+
default: 50,
|
|
32
|
+
},
|
|
33
|
+
ignoreIdenticalFiles: {
|
|
34
|
+
type: "boolean",
|
|
35
|
+
description: "Ignore identical files (default: true)",
|
|
36
|
+
default: true,
|
|
37
|
+
},
|
|
38
|
+
maxFiles: {
|
|
39
|
+
type: "number",
|
|
40
|
+
description: "Maximum files to analyze (default: 100)",
|
|
41
|
+
default: 100,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ["path"],
|
|
45
|
+
};
|
|
46
|
+
// Default exclusions
|
|
47
|
+
const DEFAULT_EXCLUDE = [
|
|
48
|
+
"node_modules",
|
|
49
|
+
"__pycache__",
|
|
50
|
+
".git",
|
|
51
|
+
"venv",
|
|
52
|
+
".venv",
|
|
53
|
+
"env",
|
|
54
|
+
"dist",
|
|
55
|
+
"build",
|
|
56
|
+
".tox",
|
|
57
|
+
".eggs",
|
|
58
|
+
];
|
|
59
|
+
/**
|
|
60
|
+
* findDuplicates tool
|
|
61
|
+
*/
|
|
62
|
+
export const findDuplicatesTool = defineTool({
|
|
63
|
+
name: "find_duplicates_python",
|
|
64
|
+
description: TOOL_DESCRIPTION,
|
|
65
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
66
|
+
execute: executeFindDuplicates,
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Execute the findDuplicates tool
|
|
70
|
+
*/
|
|
71
|
+
async function executeFindDuplicates(input) {
|
|
72
|
+
const { path: inputPath, minLines = 6, minTokens = 50, ignoreIdenticalFiles = true, maxFiles = 100, } = input;
|
|
73
|
+
try {
|
|
74
|
+
const resolvedPath = path.resolve(inputPath);
|
|
75
|
+
// Check if path exists
|
|
76
|
+
try {
|
|
77
|
+
await fs.access(resolvedPath);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return createErrorResult(`Path not found: ${resolvedPath}`);
|
|
81
|
+
}
|
|
82
|
+
const stats = await fs.stat(resolvedPath);
|
|
83
|
+
if (!stats.isDirectory()) {
|
|
84
|
+
return createErrorResult("findDuplicates requires a directory path");
|
|
85
|
+
}
|
|
86
|
+
// Collect files
|
|
87
|
+
const files = [];
|
|
88
|
+
await collectFiles(resolvedPath, files, maxFiles);
|
|
89
|
+
// Check for identical files first (if not ignoring)
|
|
90
|
+
const fileHashes = new Map();
|
|
91
|
+
if (!ignoreIdenticalFiles) {
|
|
92
|
+
for (const file of files) {
|
|
93
|
+
const content = await fs.readFile(file, "utf-8");
|
|
94
|
+
const hash = crypto.createHash("md5").update(content).digest("hex");
|
|
95
|
+
const existing = fileHashes.get(hash) ?? [];
|
|
96
|
+
existing.push(file);
|
|
97
|
+
fileHashes.set(hash, existing);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Extract code blocks from each file
|
|
101
|
+
const allBlocks = [];
|
|
102
|
+
let totalLines = 0;
|
|
103
|
+
for (const file of files) {
|
|
104
|
+
const blocks = await extractCodeBlocks(file, minLines, minTokens);
|
|
105
|
+
allBlocks.push(...blocks);
|
|
106
|
+
// Count total lines
|
|
107
|
+
const content = await fs.readFile(file, "utf-8");
|
|
108
|
+
totalLines += content.split("\n").length;
|
|
109
|
+
}
|
|
110
|
+
// Group by hash
|
|
111
|
+
const hashGroups = new Map();
|
|
112
|
+
for (const block of allBlocks) {
|
|
113
|
+
const existing = hashGroups.get(block.hash) ?? [];
|
|
114
|
+
existing.push(block);
|
|
115
|
+
hashGroups.set(block.hash, existing);
|
|
116
|
+
}
|
|
117
|
+
// Filter to only groups with duplicates
|
|
118
|
+
const duplicateGroups = [];
|
|
119
|
+
let groupId = 1;
|
|
120
|
+
let totalDuplicateLines = 0;
|
|
121
|
+
for (const [_hash, blocks] of hashGroups) {
|
|
122
|
+
if (blocks.length < 2)
|
|
123
|
+
continue;
|
|
124
|
+
// Skip if all from same file
|
|
125
|
+
const uniqueFiles = new Set(blocks.map((b) => b.path));
|
|
126
|
+
if (uniqueFiles.size < 2)
|
|
127
|
+
continue;
|
|
128
|
+
const locations = blocks.map((b) => ({
|
|
129
|
+
path: b.path,
|
|
130
|
+
startLine: b.startLine,
|
|
131
|
+
endLine: b.endLine,
|
|
132
|
+
}));
|
|
133
|
+
const lines = blocks[0].endLine - blocks[0].startLine + 1;
|
|
134
|
+
totalDuplicateLines += lines * (blocks.length - 1); // Count extra copies
|
|
135
|
+
duplicateGroups.push({
|
|
136
|
+
id: `DUP-${String(groupId++)}`,
|
|
137
|
+
lines,
|
|
138
|
+
tokens: blocks[0].tokens,
|
|
139
|
+
locations,
|
|
140
|
+
sample: truncateSample(blocks[0].content, 5), // First 5 lines
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Sort by lines (largest first)
|
|
144
|
+
duplicateGroups.sort((a, b) => b.lines - a.lines);
|
|
145
|
+
// Limit results
|
|
146
|
+
const limitedGroups = duplicateGroups.slice(0, 20);
|
|
147
|
+
const percentageDuplicate = totalLines > 0
|
|
148
|
+
? Math.round((totalDuplicateLines / totalLines) * 10000) / 100
|
|
149
|
+
: 0;
|
|
150
|
+
const result = {
|
|
151
|
+
path: resolvedPath,
|
|
152
|
+
duplicates: limitedGroups,
|
|
153
|
+
stats: {
|
|
154
|
+
filesAnalyzed: files.length,
|
|
155
|
+
duplicateGroups: duplicateGroups.length,
|
|
156
|
+
totalDuplicateLines,
|
|
157
|
+
percentageDuplicate,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
return createSuccessResult(result);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
return createErrorResult(`Failed to find duplicates: ${error instanceof Error ? error.message : String(error)}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Collect files to analyze
|
|
168
|
+
*/
|
|
169
|
+
async function collectFiles(dirPath, files, maxFiles, currentDepth = 0) {
|
|
170
|
+
if (currentDepth > 10 || files.length >= maxFiles)
|
|
171
|
+
return;
|
|
172
|
+
try {
|
|
173
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
if (files.length >= maxFiles)
|
|
176
|
+
break;
|
|
177
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
178
|
+
if (entry.isDirectory()) {
|
|
179
|
+
if (DEFAULT_EXCLUDE.includes(entry.name))
|
|
180
|
+
continue;
|
|
181
|
+
await collectFiles(fullPath, files, maxFiles, currentDepth + 1);
|
|
182
|
+
}
|
|
183
|
+
else if (entry.isFile()) {
|
|
184
|
+
// Only include Python files
|
|
185
|
+
if (fullPath.endsWith(".py") && !fullPath.endsWith(".pyi")) {
|
|
186
|
+
files.push(fullPath);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// Ignore permission errors
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Extract code blocks from a file using sliding window
|
|
197
|
+
*/
|
|
198
|
+
async function extractCodeBlocks(filePath, minLines, minTokens) {
|
|
199
|
+
try {
|
|
200
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
201
|
+
const lines = content.split("\n");
|
|
202
|
+
const blocks = [];
|
|
203
|
+
// Use sliding window approach
|
|
204
|
+
for (let start = 0; start <= lines.length - minLines; start++) {
|
|
205
|
+
// Try different block sizes
|
|
206
|
+
for (let size = minLines; size <= Math.min(minLines * 3, lines.length - start); size++) {
|
|
207
|
+
const blockLines = lines.slice(start, start + size);
|
|
208
|
+
const blockContent = blockLines.join("\n");
|
|
209
|
+
// Normalize content for comparison
|
|
210
|
+
const normalized = normalizeCode(blockContent);
|
|
211
|
+
// Count tokens (simplified: split on whitespace and punctuation)
|
|
212
|
+
const tokens = countTokens(normalized);
|
|
213
|
+
if (tokens < minTokens)
|
|
214
|
+
continue;
|
|
215
|
+
// Skip if mostly empty/comments
|
|
216
|
+
const significantLines = blockLines.filter((l) => l.trim() && !l.trim().startsWith("#"));
|
|
217
|
+
if (significantLines.length < minLines / 2)
|
|
218
|
+
continue;
|
|
219
|
+
const hash = crypto.createHash("md5").update(normalized).digest("hex");
|
|
220
|
+
blocks.push({
|
|
221
|
+
hash,
|
|
222
|
+
path: filePath,
|
|
223
|
+
startLine: start + 1,
|
|
224
|
+
endLine: start + size,
|
|
225
|
+
content: blockContent,
|
|
226
|
+
tokens,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return blocks;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Normalize code for comparison (remove variable names, whitespace differences)
|
|
238
|
+
*/
|
|
239
|
+
function normalizeCode(code) {
|
|
240
|
+
return (code
|
|
241
|
+
// Remove comments
|
|
242
|
+
.replace(/#.*$/gm, "")
|
|
243
|
+
// Remove docstrings (simplified)
|
|
244
|
+
.replace(/"""[\s\S]*?"""/g, '""')
|
|
245
|
+
.replace(/'''[\s\S]*?'''/g, "''")
|
|
246
|
+
// Normalize whitespace
|
|
247
|
+
.replace(/\s+/g, " ")
|
|
248
|
+
// Remove string literals (replace with placeholder)
|
|
249
|
+
.replace(/"[^"]*"/g, '""')
|
|
250
|
+
.replace(/'[^']*'/g, "''")
|
|
251
|
+
// Normalize numbers
|
|
252
|
+
.replace(/\b\d+\b/g, "0")
|
|
253
|
+
.trim());
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Count tokens in code
|
|
257
|
+
*/
|
|
258
|
+
function countTokens(code) {
|
|
259
|
+
// Split on whitespace and common punctuation
|
|
260
|
+
return code.split(/[\s{}()[\];,.:=+\-*/<>]+/).filter((t) => t.length > 0)
|
|
261
|
+
.length;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Truncate sample to first N lines
|
|
265
|
+
*/
|
|
266
|
+
function truncateSample(content, maxLines) {
|
|
267
|
+
const lines = content.split("\n");
|
|
268
|
+
if (lines.length <= maxLines)
|
|
269
|
+
return content;
|
|
270
|
+
return lines.slice(0, maxLines).join("\n") + "\n...";
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Factory function to create a customized findDuplicates tool
|
|
274
|
+
*/
|
|
275
|
+
export function createFindDuplicatesTool(options) {
|
|
276
|
+
return defineTool({
|
|
277
|
+
name: "find_duplicates_python",
|
|
278
|
+
description: TOOL_DESCRIPTION,
|
|
279
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
280
|
+
execute: async (input) => {
|
|
281
|
+
const modifiedInput = {
|
|
282
|
+
...input,
|
|
283
|
+
minLines: input.minLines ?? options?.defaultMinLines,
|
|
284
|
+
maxFiles: input.maxFiles ?? options?.defaultMaxFiles,
|
|
285
|
+
};
|
|
286
|
+
return executeFindDuplicates(modifiedInput);
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* findImplementations Tool
|
|
3
|
+
*
|
|
4
|
+
* Find classes that inherit from a base class, ABC, or implement a Protocol.
|
|
5
|
+
* Useful for understanding inheritance hierarchies and finding concrete implementations.
|
|
6
|
+
*/
|
|
7
|
+
import type { Tool } from "@compilr-dev/agents";
|
|
8
|
+
/**
|
|
9
|
+
* Input for findImplementations tool
|
|
10
|
+
*/
|
|
11
|
+
export interface FindImplementationsInput {
|
|
12
|
+
/** Base class, ABC, or Protocol name to find implementations of */
|
|
13
|
+
name: string;
|
|
14
|
+
/** Directory or file to search in (defaults to current directory) */
|
|
15
|
+
scope?: string;
|
|
16
|
+
/** Include abstract classes that partially implement (default: false) */
|
|
17
|
+
includeAbstract?: boolean;
|
|
18
|
+
/** Maximum files to search (default: 100) */
|
|
19
|
+
maxFiles?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Implementation info
|
|
23
|
+
*/
|
|
24
|
+
export interface ImplementationInfo {
|
|
25
|
+
/** Class name */
|
|
26
|
+
name: string;
|
|
27
|
+
/** File path */
|
|
28
|
+
path: string;
|
|
29
|
+
/** Line number */
|
|
30
|
+
line: number;
|
|
31
|
+
/** Kind of implementation */
|
|
32
|
+
kind: "class" | "dataclass";
|
|
33
|
+
/** Is abstract */
|
|
34
|
+
isAbstract?: boolean;
|
|
35
|
+
/** List of implemented methods */
|
|
36
|
+
implementedMethods?: string[];
|
|
37
|
+
/** List of missing abstract methods */
|
|
38
|
+
missingMethods?: string[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Result of findImplementations
|
|
42
|
+
*/
|
|
43
|
+
export interface FindImplementationsResult {
|
|
44
|
+
/** Target base class/protocol name */
|
|
45
|
+
target: string;
|
|
46
|
+
/** Location of target definition */
|
|
47
|
+
targetLocation?: {
|
|
48
|
+
path: string;
|
|
49
|
+
line: number;
|
|
50
|
+
};
|
|
51
|
+
/** Found implementations */
|
|
52
|
+
implementations: ImplementationInfo[];
|
|
53
|
+
/** Statistics */
|
|
54
|
+
stats: {
|
|
55
|
+
filesSearched: number;
|
|
56
|
+
implementationsFound: number;
|
|
57
|
+
timeMs: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* findImplementations tool
|
|
62
|
+
*/
|
|
63
|
+
export declare const findImplementationsTool: Tool<FindImplementationsInput>;
|
|
64
|
+
/**
|
|
65
|
+
* Factory function to create a customized findImplementations tool
|
|
66
|
+
*/
|
|
67
|
+
export declare function createFindImplementationsTool(options?: {
|
|
68
|
+
defaultScope?: string;
|
|
69
|
+
defaultMaxFiles?: number;
|
|
70
|
+
}): Tool<FindImplementationsInput>;
|
|
71
|
+
//# sourceMappingURL=find-implementations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-implementations.d.ts","sourceRoot":"","sources":["../../src/tools/find-implementations.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,IAAI,EAAuB,MAAM,qBAAqB,CAAC;AAOrE;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,IAAI,EAAE,OAAO,GAAG,WAAW,CAAC;IAC5B,kBAAkB;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kCAAkC;IAClC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,cAAc,CAAC,EAAE;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,4BAA4B;IAC5B,eAAe,EAAE,kBAAkB,EAAE,CAAC;IACtC,iBAAiB;IACjB,KAAK,EAAE;QACL,aAAa,EAAE,MAAM,CAAC;QACtB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAgDD;;GAEG;AACH,eAAO,MAAM,uBAAuB,gCAKlC,CAAC;AAwYH;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,CAAC,EAAE;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,IAAI,CAAC,wBAAwB,CAAC,CAcjC"}
|