@appium/mcp-documentation 1.0.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/CHANGELOG.md +0 -0
- package/LICENSE +201 -0
- package/README.md +126 -0
- package/dist/answer-appium.d.ts +8 -0
- package/dist/answer-appium.d.ts.map +1 -0
- package/dist/answer-appium.js +38 -0
- package/dist/answer-appium.js.map +1 -0
- package/dist/appium-skills.d.ts +5 -0
- package/dist/appium-skills.d.ts.map +1 -0
- package/dist/appium-skills.js +168 -0
- package/dist/appium-skills.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +5 -0
- package/dist/logger.js.map +1 -0
- package/dist/markdown-header-splitter.d.ts +32 -0
- package/dist/markdown-header-splitter.d.ts.map +1 -0
- package/dist/markdown-header-splitter.js +180 -0
- package/dist/markdown-header-splitter.js.map +1 -0
- package/dist/paths.d.ts +2 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +22 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugin.d.ts +19 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +18 -0
- package/dist/plugin.js.map +1 -0
- package/dist/reasoning-rag.d.ts +89 -0
- package/dist/reasoning-rag.d.ts.map +1 -0
- package/dist/reasoning-rag.js +282 -0
- package/dist/reasoning-rag.js.map +1 -0
- package/dist/scripts/eval-documentation-rag.d.ts +50 -0
- package/dist/scripts/eval-documentation-rag.d.ts.map +1 -0
- package/dist/scripts/eval-documentation-rag.js +287 -0
- package/dist/scripts/eval-documentation-rag.js.map +1 -0
- package/dist/scripts/generate-embeddings-cache.d.ts +13 -0
- package/dist/scripts/generate-embeddings-cache.d.ts.map +1 -0
- package/dist/scripts/generate-embeddings-cache.js +24 -0
- package/dist/scripts/generate-embeddings-cache.js.map +1 -0
- package/dist/scripts/rag-eval-dataset.json +516 -0
- package/dist/scripts/simple-index-documentation.d.ts +21 -0
- package/dist/scripts/simple-index-documentation.d.ts.map +1 -0
- package/dist/scripts/simple-index-documentation.js +77 -0
- package/dist/scripts/simple-index-documentation.js.map +1 -0
- package/dist/scripts/simple-query-documentation.d.ts +13 -0
- package/dist/scripts/simple-query-documentation.d.ts.map +1 -0
- package/dist/scripts/simple-query-documentation.js +52 -0
- package/dist/scripts/simple-query-documentation.js.map +1 -0
- package/dist/sentence-transformers-embeddings.d.ts +40 -0
- package/dist/sentence-transformers-embeddings.d.ts.map +1 -0
- package/dist/sentence-transformers-embeddings.js +119 -0
- package/dist/sentence-transformers-embeddings.js.map +1 -0
- package/dist/simple-pdf-indexer.d.ts +47 -0
- package/dist/simple-pdf-indexer.d.ts.map +1 -0
- package/dist/simple-pdf-indexer.js +572 -0
- package/dist/simple-pdf-indexer.js.map +1 -0
- package/dist/tests/__mocks__/@appium/support.d.ts +92 -0
- package/dist/tests/__mocks__/@appium/support.d.ts.map +1 -0
- package/dist/tests/__mocks__/@appium/support.js +66 -0
- package/dist/tests/__mocks__/@appium/support.js.map +1 -0
- package/dist/tests/appium-skills.test.d.ts +2 -0
- package/dist/tests/appium-skills.test.d.ts.map +1 -0
- package/dist/tests/appium-skills.test.js +26 -0
- package/dist/tests/appium-skills.test.js.map +1 -0
- package/dist/tests/plugin.test.d.ts +2 -0
- package/dist/tests/plugin.test.d.ts.map +1 -0
- package/dist/tests/plugin.test.js +18 -0
- package/dist/tests/plugin.test.js.map +1 -0
- package/dist/tests/simple-pdf-indexer.test.d.ts +2 -0
- package/dist/tests/simple-pdf-indexer.test.d.ts.map +1 -0
- package/dist/tests/simple-pdf-indexer.test.js +37 -0
- package/dist/tests/simple-pdf-indexer.test.js.map +1 -0
- package/dist/tool-response.d.ts +4 -0
- package/dist/tool-response.d.ts.map +1 -0
- package/dist/tool-response.js +12 -0
- package/dist/tool-response.js.map +1 -0
- package/dist/tools.d.ts +3 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +3 -0
- package/dist/tools.js.map +1 -0
- package/dist/uploads/documents.json +1 -0
- package/package.json +84 -0
- package/scripts/zip-assets.mjs +75 -0
- package/src/resources/submodules.zip +0 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple Markdown Indexer
|
|
3
|
+
*
|
|
4
|
+
* Indexes Markdown documents into an in-memory vector store using a
|
|
5
|
+
* header-aware hybrid splitter and LangChain's MemoryVectorStore. The
|
|
6
|
+
* vector store is persisted to a file for use across different script
|
|
7
|
+
* executions.
|
|
8
|
+
*/
|
|
9
|
+
import { Document } from '@langchain/core/documents';
|
|
10
|
+
import { MemoryVectorStore } from '@langchain/classic/vectorstores/memory';
|
|
11
|
+
import { fs } from '@appium/support';
|
|
12
|
+
import * as crypto from 'node:crypto';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { splitMarkdownByHeaders } from './markdown-header-splitter.js';
|
|
16
|
+
// Initialize embeddings using sentence-transformers (no API key required)
|
|
17
|
+
import { SentenceTransformersEmbeddings } from './sentence-transformers-embeddings.js';
|
|
18
|
+
import log from './logger.js';
|
|
19
|
+
let embeddings = null;
|
|
20
|
+
/**
|
|
21
|
+
* Initialize embeddings lazily when needed
|
|
22
|
+
* Uses sentence-transformers exclusively (no API key required)
|
|
23
|
+
*/
|
|
24
|
+
function getEmbeddings() {
|
|
25
|
+
if (embeddings) {
|
|
26
|
+
return embeddings;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
// Use local sentence-transformers (no API key required)
|
|
30
|
+
log.info('Using local sentence-transformers embeddings');
|
|
31
|
+
const modelName = process.env.SENTENCE_TRANSFORMERS_MODEL || 'Xenova/bge-small-en-v1.5';
|
|
32
|
+
// BGE models benefit from a query instruction prefix to align the
|
|
33
|
+
// embedding space between short questions and longer document passages.
|
|
34
|
+
// Applied to embedQuery() only; embedDocuments() is unchanged.
|
|
35
|
+
const queryInstruction = modelName.includes('bge')
|
|
36
|
+
? 'Represent this sentence for searching relevant passages: '
|
|
37
|
+
: '';
|
|
38
|
+
embeddings = new SentenceTransformersEmbeddings({
|
|
39
|
+
modelName,
|
|
40
|
+
queryInstruction,
|
|
41
|
+
});
|
|
42
|
+
log.info(`Using sentence-transformers model: ${modelName}`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw new Error(`Failed to initialize embeddings: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
46
|
+
}
|
|
47
|
+
return embeddings;
|
|
48
|
+
}
|
|
49
|
+
// Path to store the documents
|
|
50
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
51
|
+
const __dirname = path.dirname(__filename);
|
|
52
|
+
const DOCUMENTS_PATH = path.join(__dirname, './uploads/documents.json');
|
|
53
|
+
// Global variable to store the in-memory vector store
|
|
54
|
+
let memoryVectorStore = null;
|
|
55
|
+
/**
|
|
56
|
+
* Exclude certain directories from being indexed to avoid irrelevant content and reduce noise in the vector store.
|
|
57
|
+
*/
|
|
58
|
+
const EXCLUDED_MARKDOWN_DIRECTORIES = new Set([
|
|
59
|
+
'appium-skills',
|
|
60
|
+
'ja',
|
|
61
|
+
'zh',
|
|
62
|
+
'.github',
|
|
63
|
+
'blog',
|
|
64
|
+
]);
|
|
65
|
+
/**
|
|
66
|
+
* Exclude specific filenames regardless of where they appear in the tree.
|
|
67
|
+
*
|
|
68
|
+
* CHANGELOG.md files are semantic-release templates dominated by version
|
|
69
|
+
* headers, commit hashes, and PR numbers. They have negligible instructional
|
|
70
|
+
* value.
|
|
71
|
+
*/
|
|
72
|
+
const EXCLUDED_MARKDOWN_FILENAMES = new Set(['CHANGELOG.md']);
|
|
73
|
+
/**
|
|
74
|
+
* Embeddings cache: vectors persisted alongside documents.json so the
|
|
75
|
+
* server doesn't re-embed all chunks on every cold start.
|
|
76
|
+
*
|
|
77
|
+
* Invariants:
|
|
78
|
+
* - One cache file per model, so multiple models can coexist on disk.
|
|
79
|
+
* - Fingerprint embeds (modelName, chunkCount, contentHash of documents).
|
|
80
|
+
* Any drift in the corpus or model means the cache invalidates and gets
|
|
81
|
+
* re-embedded automatically.
|
|
82
|
+
*/
|
|
83
|
+
const CACHE_VERSION = 1;
|
|
84
|
+
/**
|
|
85
|
+
* Initialize the vector store with Markdown content
|
|
86
|
+
* @param markdownPath Path to the Markdown file
|
|
87
|
+
* @param chunkSize Size of each chunk in characters
|
|
88
|
+
* @param chunkOverlap Number of characters to overlap between chunks
|
|
89
|
+
* @returns The initialized MemoryVectorStore
|
|
90
|
+
*/
|
|
91
|
+
export async function initializeVectorStore(markdownPath, chunkSize = 2500, chunkOverlap = 200) {
|
|
92
|
+
try {
|
|
93
|
+
log.info(`Initializing vector store for Markdown: ${markdownPath}`);
|
|
94
|
+
log.info(`Using chunk size: ${chunkSize}, overlap: ${chunkOverlap}`);
|
|
95
|
+
// Extract text from Markdown
|
|
96
|
+
log.info('Extracting text from Markdown...');
|
|
97
|
+
const markdownText = await extractTextFromMarkdown(markdownPath);
|
|
98
|
+
log.info(`Extracted ${markdownText.length} characters from Markdown`);
|
|
99
|
+
// Header-aware hybrid splitter: parses ATX headers to find topical
|
|
100
|
+
// boundaries, coalesces short sibling sections to avoid tiny embeddings,
|
|
101
|
+
// recursive-splits oversized sections, and prepends a header breadcrumb
|
|
102
|
+
// (`# Page > ## Section`) so each chunk's embedding carries its context.
|
|
103
|
+
log.info('Splitting text into chunks...');
|
|
104
|
+
const documents = await splitMarkdownByHeaders(markdownText, {
|
|
105
|
+
chunkSize,
|
|
106
|
+
chunkOverlap,
|
|
107
|
+
});
|
|
108
|
+
log.info(`Created ${documents.length} document chunks`);
|
|
109
|
+
// Embed once; reuse the vectors for both the in-memory store and the cache.
|
|
110
|
+
log.info('Embedding chunks...');
|
|
111
|
+
const embeddingsProvider = getEmbeddings();
|
|
112
|
+
const vectors = await embeddingsProvider.embedDocuments(documents.map((d) => d.pageContent));
|
|
113
|
+
log.info('Storing documents in memory vector store...');
|
|
114
|
+
const vectorStore = new MemoryVectorStore(embeddingsProvider);
|
|
115
|
+
await vectorStore.addVectors(vectors, documents);
|
|
116
|
+
// Save the vector store in the global variable for later use
|
|
117
|
+
memoryVectorStore = vectorStore;
|
|
118
|
+
// Save documents to file for persistence
|
|
119
|
+
await saveDocuments(documents, false); // Don't append for single file indexing
|
|
120
|
+
// Persist the embeddings cache so the next cold start can skip embedding.
|
|
121
|
+
await saveEmbeddingsCache(documents, vectors, embeddingsProvider.getModelName());
|
|
122
|
+
log.info('Successfully stored documents in memory vector store');
|
|
123
|
+
return vectorStore;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
log.error('Error initializing vector store:', error);
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get all Markdown files in a directory recursively
|
|
132
|
+
* @param dirPath Path to the directory
|
|
133
|
+
* @returns Array of Markdown file paths
|
|
134
|
+
*/
|
|
135
|
+
export async function getMarkdownFilesInDirectory(dirPath) {
|
|
136
|
+
try {
|
|
137
|
+
// Check if directory exists
|
|
138
|
+
if (!(await fs.exists(dirPath))) {
|
|
139
|
+
log.error(`Directory does not exist: ${dirPath}`);
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
const markdownFiles = [];
|
|
143
|
+
async function scanDirectory(currentPath) {
|
|
144
|
+
const files = await fs.readdir(currentPath);
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
const filePath = path.join(currentPath, file);
|
|
147
|
+
const stats = await fs.stat(filePath);
|
|
148
|
+
if (stats.isDirectory()) {
|
|
149
|
+
if (EXCLUDED_MARKDOWN_DIRECTORIES.has(file)) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
// Recursively scan subdirectories
|
|
153
|
+
await scanDirectory(filePath);
|
|
154
|
+
}
|
|
155
|
+
else if (stats.isFile() &&
|
|
156
|
+
path.extname(file).toLowerCase() === '.md' &&
|
|
157
|
+
!EXCLUDED_MARKDOWN_FILENAMES.has(file)) {
|
|
158
|
+
markdownFiles.push(filePath);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
await scanDirectory(dirPath);
|
|
163
|
+
log.info(`Found ${markdownFiles.length} Markdown files in ${dirPath}`);
|
|
164
|
+
return markdownFiles;
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
log.error('Error getting Markdown files:', error);
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Index a Markdown file into the memory vector store
|
|
173
|
+
* @param markdownPath Path to the Markdown file
|
|
174
|
+
* @param chunkSize Size of each chunk in characters
|
|
175
|
+
* @param chunkOverlap Number of characters to overlap between chunks
|
|
176
|
+
*/
|
|
177
|
+
export async function indexMarkdown(markdownPath, chunkSize = 2500, chunkOverlap = 200) {
|
|
178
|
+
try {
|
|
179
|
+
log.info('Starting Markdown indexing process...');
|
|
180
|
+
// Initialize vector store
|
|
181
|
+
await initializeVectorStore(markdownPath, chunkSize, chunkOverlap);
|
|
182
|
+
log.info('Markdown indexing completed successfully');
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
log.error('Markdown indexing failed:', error);
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Index all Markdown files in a directory
|
|
191
|
+
* @param dirPath Path to the directory containing Markdown files
|
|
192
|
+
* @param chunkSize Size of each chunk in characters
|
|
193
|
+
* @param chunkOverlap Number of characters to overlap between chunks
|
|
194
|
+
* @returns Array of indexed Markdown file paths
|
|
195
|
+
*/
|
|
196
|
+
export async function indexAllMarkdownFiles(dirPath, chunkSize = 2500, chunkOverlap = 200) {
|
|
197
|
+
try {
|
|
198
|
+
log.info(`Starting indexing of all Markdown files in directory: ${dirPath}`);
|
|
199
|
+
// Get all Markdown files in the directory
|
|
200
|
+
const markdownFiles = await getMarkdownFilesInDirectory(dirPath);
|
|
201
|
+
if (markdownFiles.length === 0) {
|
|
202
|
+
log.info('No Markdown files found in the directory');
|
|
203
|
+
return [];
|
|
204
|
+
}
|
|
205
|
+
// Clear the documents file before starting
|
|
206
|
+
await clearDocumentsFile();
|
|
207
|
+
// Accumulate vectors + documents across all files so we can write a single
|
|
208
|
+
// embeddings cache at the end, parallel-aligned with documents.json.
|
|
209
|
+
const embeddingsProvider = getEmbeddings();
|
|
210
|
+
const allVectors = [];
|
|
211
|
+
const allDocuments = [];
|
|
212
|
+
// Initialize the in-memory store up-front so a failure on the first file
|
|
213
|
+
// can't leave subsequent iterations with a null store.
|
|
214
|
+
memoryVectorStore = new MemoryVectorStore(embeddingsProvider);
|
|
215
|
+
// Index each Markdown file
|
|
216
|
+
const indexedFiles = [];
|
|
217
|
+
for (let i = 0; i < markdownFiles.length; i++) {
|
|
218
|
+
const markdownFile = markdownFiles[i];
|
|
219
|
+
try {
|
|
220
|
+
log.info(`Indexing Markdown ${i + 1}/${markdownFiles.length}: ${markdownFile}`);
|
|
221
|
+
// Extract text from Markdown
|
|
222
|
+
log.info('Extracting text from Markdown...');
|
|
223
|
+
const markdownText = await extractTextFromMarkdown(markdownFile);
|
|
224
|
+
log.info(`Extracted ${markdownText.length} characters from Markdown`);
|
|
225
|
+
// Header-aware hybrid splitter
|
|
226
|
+
log.info('Splitting text into chunks...');
|
|
227
|
+
const documents = await splitMarkdownByHeaders(markdownText, {
|
|
228
|
+
chunkSize,
|
|
229
|
+
chunkOverlap,
|
|
230
|
+
});
|
|
231
|
+
log.info(`Created ${documents.length} document chunks`);
|
|
232
|
+
// Add file metadata to each document
|
|
233
|
+
const filename = path.basename(markdownFile);
|
|
234
|
+
const relativePath = path.relative(dirPath, markdownFile);
|
|
235
|
+
documents.forEach((doc) => {
|
|
236
|
+
doc.metadata = {
|
|
237
|
+
...doc.metadata,
|
|
238
|
+
filename,
|
|
239
|
+
relativePath,
|
|
240
|
+
};
|
|
241
|
+
});
|
|
242
|
+
// Embed this file's chunks once; reuse the vectors for both the
|
|
243
|
+
// in-memory store and the on-disk cache.
|
|
244
|
+
log.info('Embedding chunks...');
|
|
245
|
+
const vectors = await embeddingsProvider.embedDocuments(documents.map((d) => d.pageContent));
|
|
246
|
+
// Persist documents.json first
|
|
247
|
+
await saveDocuments(documents, i > 0);
|
|
248
|
+
log.info('Storing documents in memory vector store...');
|
|
249
|
+
await memoryVectorStore.addVectors(vectors, documents);
|
|
250
|
+
allVectors.push(...vectors);
|
|
251
|
+
allDocuments.push(...documents);
|
|
252
|
+
indexedFiles.push(markdownFile);
|
|
253
|
+
log.info(`Successfully indexed Markdown: ${filename}`);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
log.error(`Error indexing Markdown ${markdownFile}:`, error);
|
|
257
|
+
// Continue with next file even if one fails
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Persist the embeddings cache once, after all files are indexed.
|
|
261
|
+
// The cache is keyed by model name and ordered to match documents.json.
|
|
262
|
+
await saveEmbeddingsCache(allDocuments, allVectors, embeddingsProvider.getModelName());
|
|
263
|
+
log.info(`Successfully indexed ${indexedFiles.length} out of ${markdownFiles.length} Markdown files`);
|
|
264
|
+
return indexedFiles;
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
log.error('Error indexing all Markdown files:', error);
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Query the vector store for similar documents
|
|
273
|
+
* @param query The query text
|
|
274
|
+
* @param topK Number of results to return
|
|
275
|
+
* @returns Array of documents with their content and metadata
|
|
276
|
+
*/
|
|
277
|
+
export async function queryVectorStore(query, topK = 25) {
|
|
278
|
+
try {
|
|
279
|
+
if (!memoryVectorStore) {
|
|
280
|
+
const documents = await loadDocuments();
|
|
281
|
+
if (!documents || documents.length === 0) {
|
|
282
|
+
throw new Error('Vector store has not been initialized. Please index docs first.');
|
|
283
|
+
}
|
|
284
|
+
const embeddingsProvider = getEmbeddings();
|
|
285
|
+
const modelName = embeddingsProvider.getModelName();
|
|
286
|
+
// Fast path: load pre-computed vectors and build the store via addVectors.
|
|
287
|
+
// Skips the ~30-60s document-embedding step entirely.
|
|
288
|
+
const cached = await loadEmbeddingsCache(documents, modelName);
|
|
289
|
+
if (cached) {
|
|
290
|
+
log.info('Building vector store from cached embeddings (fast path)');
|
|
291
|
+
memoryVectorStore = new MemoryVectorStore(embeddingsProvider);
|
|
292
|
+
await memoryVectorStore.addVectors(cached, documents);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// Slow path: embed all documents now, then persist a cache so the
|
|
296
|
+
// next cold start is fast. Also covers model changes (different
|
|
297
|
+
// cache filename, no hit) and corpus changes (fingerprint mismatch).
|
|
298
|
+
log.info(`Embedding ${documents.length} documents for model ${modelName} (this may take a while)...`);
|
|
299
|
+
const start = Date.now();
|
|
300
|
+
const vectors = await embeddingsProvider.embedDocuments(documents.map((d) => d.pageContent));
|
|
301
|
+
log.info(`Embedding completed in ${Date.now() - start}ms`);
|
|
302
|
+
memoryVectorStore = new MemoryVectorStore(embeddingsProvider);
|
|
303
|
+
await memoryVectorStore.addVectors(vectors, documents);
|
|
304
|
+
await saveEmbeddingsCache(documents, vectors, modelName);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return await memoryVectorStore.similaritySearch(query, topK);
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
log.error('Error querying vector store:', error);
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function sanitizeForFilename(name) {
|
|
315
|
+
return name.replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
316
|
+
}
|
|
317
|
+
function getEmbeddingsCachePath(modelName) {
|
|
318
|
+
return path.join(__dirname, 'uploads', `embeddings-${sanitizeForFilename(modelName)}.json`);
|
|
319
|
+
}
|
|
320
|
+
function computeContentHash(documents) {
|
|
321
|
+
const hash = crypto.createHash('sha256');
|
|
322
|
+
for (const doc of documents) {
|
|
323
|
+
hash.update(doc.pageContent);
|
|
324
|
+
hash.update('\x00'); // separator avoids concat collisions across chunks
|
|
325
|
+
}
|
|
326
|
+
return hash.digest('hex');
|
|
327
|
+
}
|
|
328
|
+
function makeFingerprint(documents, modelName) {
|
|
329
|
+
return {
|
|
330
|
+
modelName,
|
|
331
|
+
chunkCount: documents.length,
|
|
332
|
+
contentHash: computeContentHash(documents),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function fingerprintsMatch(a, b) {
|
|
336
|
+
return (a.modelName === b.modelName &&
|
|
337
|
+
a.chunkCount === b.chunkCount &&
|
|
338
|
+
a.contentHash === b.contentHash);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Try to load a valid embeddings cache for the given documents + model.
|
|
342
|
+
* Returns null if no cache file exists, the file is corrupt, or its
|
|
343
|
+
* fingerprint disagrees with what we'd compute now.
|
|
344
|
+
*/
|
|
345
|
+
async function loadEmbeddingsCache(documents, modelName) {
|
|
346
|
+
const cachePath = getEmbeddingsCachePath(modelName);
|
|
347
|
+
if (!(await fs.exists(cachePath))) {
|
|
348
|
+
log.info(`No embeddings cache found at ${cachePath}`);
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
const raw = await fs.readFile(cachePath, 'utf-8');
|
|
353
|
+
const cache = JSON.parse(raw);
|
|
354
|
+
if (cache.version !== CACHE_VERSION) {
|
|
355
|
+
log.warn(`Embeddings cache version mismatch (got ${cache.version}, want ${CACHE_VERSION}). Invalidating.`);
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const expected = makeFingerprint(documents, modelName);
|
|
359
|
+
if (!fingerprintsMatch(cache.fingerprint, expected)) {
|
|
360
|
+
log.info(`Embeddings cache fingerprint mismatch — will re-embed. ` +
|
|
361
|
+
`Cached: ${JSON.stringify(cache.fingerprint)}; expected: ${JSON.stringify(expected)}`);
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
if (!Array.isArray(cache.embeddings) ||
|
|
365
|
+
cache.embeddings.length !== documents.length) {
|
|
366
|
+
log.warn(`Embeddings cache length (${cache.embeddings?.length}) does not match documents length (${documents.length}). Invalidating.`);
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
log.info(`Embeddings cache hit: ${cache.embeddings.length} vectors loaded from ${cachePath}`);
|
|
370
|
+
return cache.embeddings;
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
log.warn(`Failed to read embeddings cache (${err instanceof Error ? err.message : String(err)}). Will re-embed.`);
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Persist embedding vectors for the given documents under the given model name.
|
|
379
|
+
* Writes to a .tmp file then moves into place; the finally block sweeps the
|
|
380
|
+
* tmp file if anything between writeFile and mv throws. Uses fs.mv so the
|
|
381
|
+
* overwrite works across platforms (Windows rename-over-existing can be flaky
|
|
382
|
+
* in edge cases involving file locks).
|
|
383
|
+
*/
|
|
384
|
+
async function saveEmbeddingsCache(documents, vectors, modelName) {
|
|
385
|
+
if (vectors.length === 0) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if (vectors.length !== documents.length) {
|
|
389
|
+
log.warn(`Refusing to write embeddings cache: ${vectors.length} vectors vs ${documents.length} documents`);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const cachePath = getEmbeddingsCachePath(modelName);
|
|
393
|
+
await fs.mkdirp(path.dirname(cachePath));
|
|
394
|
+
const cache = {
|
|
395
|
+
version: CACHE_VERSION,
|
|
396
|
+
fingerprint: makeFingerprint(documents, modelName),
|
|
397
|
+
embeddings: vectors,
|
|
398
|
+
};
|
|
399
|
+
const tmpPath = `${cachePath}.tmp`;
|
|
400
|
+
try {
|
|
401
|
+
await fs.writeFile(tmpPath, JSON.stringify(cache));
|
|
402
|
+
await fs.mv(tmpPath, cachePath, { clobber: true, mkdirp: true });
|
|
403
|
+
log.info(`Saved embeddings cache (${vectors.length} vectors) to ${cachePath}`);
|
|
404
|
+
}
|
|
405
|
+
finally {
|
|
406
|
+
if (await fs.exists(tmpPath)) {
|
|
407
|
+
try {
|
|
408
|
+
await fs.unlink(tmpPath);
|
|
409
|
+
}
|
|
410
|
+
catch (cleanupErr) {
|
|
411
|
+
log.warn(`Failed to clean up tmp cache file ${tmpPath}: ${cleanupErr instanceof Error
|
|
412
|
+
? cleanupErr.message
|
|
413
|
+
: String(cleanupErr)}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Save the documents to a file
|
|
420
|
+
* @param documents The documents to save
|
|
421
|
+
* @param append Whether to append to existing documents or overwrite
|
|
422
|
+
*/
|
|
423
|
+
async function saveDocuments(documents, append = false) {
|
|
424
|
+
try {
|
|
425
|
+
// Create directory if it doesn't exist
|
|
426
|
+
await fs.mkdirp(path.dirname(DOCUMENTS_PATH));
|
|
427
|
+
// Serialize the new documents
|
|
428
|
+
const serializedNew = documents.map((doc) => ({
|
|
429
|
+
pageContent: doc.pageContent,
|
|
430
|
+
metadata: doc.metadata,
|
|
431
|
+
}));
|
|
432
|
+
let allSerialized = serializedNew;
|
|
433
|
+
// If appending and file exists, read existing documents and combine
|
|
434
|
+
if (append && (await fs.exists(DOCUMENTS_PATH))) {
|
|
435
|
+
try {
|
|
436
|
+
const existingContent = (await fs.readFile(DOCUMENTS_PATH, 'utf-8'));
|
|
437
|
+
if (existingContent) {
|
|
438
|
+
const existingSerialized = JSON.parse(existingContent);
|
|
439
|
+
allSerialized = [...existingSerialized, ...serializedNew];
|
|
440
|
+
log.info(`Appending ${serializedNew.length} documents to existing ${existingSerialized.length} documents`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
catch (readError) {
|
|
444
|
+
log.warn('Error reading existing documents, overwriting instead:', readError);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// Write to file
|
|
448
|
+
await fs.writeFile(DOCUMENTS_PATH, JSON.stringify(allSerialized));
|
|
449
|
+
log.info(`${append ? 'Appended to' : 'Saved'} documents in ${DOCUMENTS_PATH} (total: ${allSerialized.length})`);
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
log.error('Error saving documents:', error);
|
|
453
|
+
throw error;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Clear the documents file
|
|
458
|
+
*/
|
|
459
|
+
async function clearDocumentsFile() {
|
|
460
|
+
try {
|
|
461
|
+
if (await fs.exists(DOCUMENTS_PATH)) {
|
|
462
|
+
await fs.writeFile(DOCUMENTS_PATH, JSON.stringify([]));
|
|
463
|
+
log.info(`Cleared documents file at ${DOCUMENTS_PATH}`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
log.error('Error clearing documents file:', error);
|
|
468
|
+
throw error;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Load the documents from a file
|
|
473
|
+
* @returns The loaded documents or null if the file doesn't exist
|
|
474
|
+
*/
|
|
475
|
+
async function loadDocuments() {
|
|
476
|
+
try {
|
|
477
|
+
if (!(await fs.exists(DOCUMENTS_PATH))) {
|
|
478
|
+
log.info('No saved documents found');
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
// Read from file
|
|
482
|
+
const raw = (await fs.readFile(DOCUMENTS_PATH, 'utf-8'));
|
|
483
|
+
const serialized = JSON.parse(raw);
|
|
484
|
+
// Convert to Document objects
|
|
485
|
+
const documents = serialized.map((doc) => new Document({
|
|
486
|
+
pageContent: doc.pageContent,
|
|
487
|
+
metadata: doc.metadata,
|
|
488
|
+
}));
|
|
489
|
+
log.info(`${documents.length} documents loaded from ${DOCUMENTS_PATH}`);
|
|
490
|
+
return documents;
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
log.error('Error loading documents:', error);
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Extract text from a Markdown file
|
|
499
|
+
* @param markdownPath Path to the Markdown file
|
|
500
|
+
* @returns Extracted text as a string
|
|
501
|
+
*/
|
|
502
|
+
async function extractTextFromMarkdown(markdownPath) {
|
|
503
|
+
try {
|
|
504
|
+
return (await fs.readFile(markdownPath, 'utf-8'));
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
log.error('Error extracting text from Markdown:', error);
|
|
508
|
+
throw new Error(`Failed to extract text from Markdown: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
// This allows the script to be run directly from the command line
|
|
512
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
513
|
+
// Parse command line arguments
|
|
514
|
+
const args = process.argv.slice(2);
|
|
515
|
+
let markdownPath;
|
|
516
|
+
let chunkSize = 2500; // Default chunk size
|
|
517
|
+
let chunkOverlap = 200; // Default overlap
|
|
518
|
+
let indexSingleFile = false;
|
|
519
|
+
// Get Markdown path or directory path
|
|
520
|
+
if (args.length > 0 && args[0]) {
|
|
521
|
+
// Use provided path
|
|
522
|
+
markdownPath = path.resolve(process.cwd(), args[0]);
|
|
523
|
+
// Check if the provided path is a file or directory
|
|
524
|
+
if ((await fs.exists(markdownPath)) &&
|
|
525
|
+
(await fs.stat(markdownPath)).isFile()) {
|
|
526
|
+
indexSingleFile = true;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
// Use default path to resources directory
|
|
531
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
532
|
+
const __dirname = path.dirname(__filename);
|
|
533
|
+
markdownPath = path.resolve(__dirname, '../../resources');
|
|
534
|
+
}
|
|
535
|
+
// Get chunk size if provided
|
|
536
|
+
if (args.length > 1 && !isNaN(Number(args[1]))) {
|
|
537
|
+
chunkSize = Number(args[1]);
|
|
538
|
+
}
|
|
539
|
+
// Get overlap if provided
|
|
540
|
+
if (args.length > 2 && !isNaN(Number(args[2]))) {
|
|
541
|
+
chunkOverlap = Number(args[2]);
|
|
542
|
+
}
|
|
543
|
+
// Log embeddings provider that will be used
|
|
544
|
+
log.info('Using sentence-transformers embeddings (no API key required)');
|
|
545
|
+
// Run the indexing process
|
|
546
|
+
if (indexSingleFile) {
|
|
547
|
+
// Index a single Markdown file
|
|
548
|
+
log.info(`Indexing single Markdown file: ${markdownPath}`);
|
|
549
|
+
try {
|
|
550
|
+
await indexMarkdown(markdownPath, chunkSize, chunkOverlap);
|
|
551
|
+
process.exit(0);
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
log.error('Indexing failed:', error);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
// Index all Markdown files in the directory
|
|
560
|
+
log.info(`Indexing all Markdown files in directory: ${markdownPath}`);
|
|
561
|
+
try {
|
|
562
|
+
const indexedFiles = await indexAllMarkdownFiles(markdownPath, chunkSize, chunkOverlap);
|
|
563
|
+
log.info(`Successfully indexed ${indexedFiles.length} Markdown files`);
|
|
564
|
+
process.exit(0);
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
log.error('Indexing failed:', error);
|
|
568
|
+
process.exit(1);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
//# sourceMappingURL=simple-pdf-indexer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simple-pdf-indexer.js","sourceRoot":"","sources":["../src/simple-pdf-indexer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AACrC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,0EAA0E;AAC1E,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,GAAG,MAAM,aAAa,CAAC;AAE9B,IAAI,UAAU,GAA0C,IAAI,CAAC;AAE7D;;;GAGG;AACH,SAAS,aAAa;IACpB,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,CAAC;QACH,wDAAwD;QACxD,GAAG,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;QACzD,MAAM,SAAS,GACb,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,0BAA0B,CAAC;QACxE,kEAAkE;QAClE,wEAAwE;QACxE,+DAA+D;QAC/D,MAAM,gBAAgB,GAAG,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;YAChD,CAAC,CAAC,2DAA2D;YAC7D,CAAC,CAAC,EAAE,CAAC;QACP,UAAU,GAAG,IAAI,8BAA8B,CAAC;YAC9C,SAAS;YACT,gBAAgB;SACjB,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,sCAAsC,SAAS,EAAE,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,oCACE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,EACF,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;IACJ,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,8BAA8B;AAC9B,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;AAExE,sDAAsD;AACtD,IAAI,iBAAiB,GAA6B,IAAI,CAAC;AACvD;;GAEG;AACH,MAAM,6BAA6B,GAAG,IAAI,GAAG,CAAC;IAC5C,eAAe;IACf,IAAI;IACJ,IAAI;IACJ,SAAS;IACT,MAAM;CACP,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;AAE9D;;;;;;;;;GASG;AACH,MAAM,aAAa,GAAG,CAAC,CAAC;AAcxB;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,YAAoB,EACpB,YAAoB,IAAI,EACxB,eAAuB,GAAG;IAE1B,IAAI,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,2CAA2C,YAAY,EAAE,CAAC,CAAC;QACpE,GAAG,CAAC,IAAI,CAAC,qBAAqB,SAAS,cAAc,YAAY,EAAE,CAAC,CAAC;QAErE,6BAA6B;QAC7B,GAAG,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAC7C,MAAM,YAAY,GAAG,MAAM,uBAAuB,CAAC,YAAY,CAAC,CAAC;QACjE,GAAG,CAAC,IAAI,CAAC,aAAa,YAAY,CAAC,MAAM,2BAA2B,CAAC,CAAC;QAEtE,mEAAmE;QACnE,yEAAyE;QACzE,wEAAwE;QACxE,yEAAyE;QACzE,GAAG,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,MAAM,sBAAsB,CAAC,YAAY,EAAE;YAC3D,SAAS;YACT,YAAY;SACb,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,WAAW,SAAS,CAAC,MAAM,kBAAkB,CAAC,CAAC;QAExD,4EAA4E;QAC5E,GAAG,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAChC,MAAM,kBAAkB,GAAG,aAAa,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,cAAc,CACrD,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CACpC,CAAC;QAEF,GAAG,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QACxD,MAAM,WAAW,GAAG,IAAI,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;QAC9D,MAAM,WAAW,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAEjD,6DAA6D;QAC7D,iBAAiB,GAAG,WAAW,CAAC;QAEhC,yCAAyC;QACzC,MAAM,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,wCAAwC;QAE/E,0EAA0E;QAC1E,MAAM,mBAAmB,CACvB,SAAS,EACT,OAAO,EACP,kBAAkB,CAAC,YAAY,EAAE,CAClC,CAAC;QAEF,GAAG,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;QACjE,OAAO,WAAW,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,OAAe;IAEf,IAAI,CAAC;QACH,4BAA4B;QAC5B,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YAChC,GAAG,CAAC,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;YAClD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,aAAa,GAAa,EAAE,CAAC;QAEnC,KAAK,UAAU,aAAa,CAAC,WAAmB;YAC9C,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAE5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;gBAC9C,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAEtC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,IAAI,6BAA6B,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC5C,SAAS;oBACX,CAAC;oBAED,kCAAkC;oBAClC,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;gBAChC,CAAC;qBAAM,IACL,KAAK,CAAC,MAAM,EAAE;oBACd,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK;oBAC1C,CAAC,2BAA2B,CAAC,GAAG,CAAC,IAAI,CAAC,EACtC,CAAC;oBACD,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,SAAS,aAAa,CAAC,MAAM,sBAAsB,OAAO,EAAE,CAAC,CAAC;QACvE,OAAO,aAAa,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;QAClD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,YAAoB,EACpB,YAAoB,IAAI,EACxB,eAAuB,GAAG;IAE1B,IAAI,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QAElD,0BAA0B;QAC1B,MAAM,qBAAqB,CAAC,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;QAEnE,GAAG,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAe,EACf,YAAoB,IAAI,EACxB,eAAuB,GAAG;IAE1B,IAAI,CAAC;QACH,GAAG,CAAC,IAAI,CACN,yDAAyD,OAAO,EAAE,CACnE,CAAC;QAEF,0CAA0C;QAC1C,MAAM,aAAa,GAAG,MAAM,2BAA2B,CAAC,OAAO,CAAC,CAAC;QAEjE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,GAAG,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;YACrD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,2CAA2C;QAC3C,MAAM,kBAAkB,EAAE,CAAC;QAE3B,2EAA2E;QAC3E,qEAAqE;QACrE,MAAM,kBAAkB,GAAG,aAAa,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAe,EAAE,CAAC;QAClC,MAAM,YAAY,GAAe,EAAE,CAAC;QAEpC,yEAAyE;QACzE,uDAAuD;QACvD,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;QAE9D,2BAA2B;QAC3B,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC;gBACH,GAAG,CAAC,IAAI,CACN,qBAAqB,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,MAAM,KAAK,YAAY,EAAE,CACtE,CAAC;gBAEF,6BAA6B;gBAC7B,GAAG,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;gBAC7C,MAAM,YAAY,GAAG,MAAM,uBAAuB,CAAC,YAAY,CAAC,CAAC;gBACjE,GAAG,CAAC,IAAI,CAAC,aAAa,YAAY,CAAC,MAAM,2BAA2B,CAAC,CAAC;gBAEtE,+BAA+B;gBAC/B,GAAG,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;gBAC1C,MAAM,SAAS,GAAG,MAAM,sBAAsB,CAAC,YAAY,EAAE;oBAC3D,SAAS;oBACT,YAAY;iBACb,CAAC,CAAC;gBACH,GAAG,CAAC,IAAI,CAAC,WAAW,SAAS,CAAC,MAAM,kBAAkB,CAAC,CAAC;gBAExD,qCAAqC;gBACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;gBAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;gBAC1D,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;oBACxB,GAAG,CAAC,QAAQ,GAAG;wBACb,GAAG,GAAG,CAAC,QAAQ;wBACf,QAAQ;wBACR,YAAY;qBACb,CAAC;gBACJ,CAAC,CAAC,CAAC;gBAEH,gEAAgE;gBAChE,yCAAyC;gBACzC,GAAG,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;gBAChC,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,cAAc,CACrD,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CACpC,CAAC;gBAEF,+BAA+B;gBAC/B,MAAM,aAAa,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;gBAEtC,GAAG,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;gBACxD,MAAM,iBAAiB,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBACvD,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;gBAC5B,YAAY,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;gBAEhC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAChC,GAAG,CAAC,IAAI,CAAC,kCAAkC,QAAQ,EAAE,CAAC,CAAC;YACzD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,GAAG,CAAC,KAAK,CAAC,2BAA2B,YAAY,GAAG,EAAE,KAAK,CAAC,CAAC;gBAC7D,4CAA4C;YAC9C,CAAC;QACH,CAAC;QAED,kEAAkE;QAClE,wEAAwE;QACxE,MAAM,mBAAmB,CACvB,YAAY,EACZ,UAAU,EACV,kBAAkB,CAAC,YAAY,EAAE,CAClC,CAAC;QAEF,GAAG,CAAC,IAAI,CACN,wBAAwB,YAAY,CAAC,MAAM,WAAW,aAAa,CAAC,MAAM,iBAAiB,CAC5F,CAAC;QACF,OAAO,YAAY,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;QACvD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,OAAe,EAAE;IAEjB,IAAI,CAAC;QACH,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,MAAM,SAAS,GAAG,MAAM,aAAa,EAAE,CAAC;YACxC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CACb,iEAAiE,CAClE,CAAC;YACJ,CAAC;YAED,MAAM,kBAAkB,GAAG,aAAa,EAAE,CAAC;YAC3C,MAAM,SAAS,GAAG,kBAAkB,CAAC,YAAY,EAAE,CAAC;YAEpD,2EAA2E;YAC3E,sDAAsD;YACtD,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YAC/D,IAAI,MAAM,EAAE,CAAC;gBACX,GAAG,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;gBACrE,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;gBAC9D,MAAM,iBAAiB,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,kEAAkE;gBAClE,gEAAgE;gBAChE,qEAAqE;gBACrE,GAAG,CAAC,IAAI,CACN,aAAa,SAAS,CAAC,MAAM,wBAAwB,SAAS,6BAA6B,CAC5F,CAAC;gBACF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACzB,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,cAAc,CACrD,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CACpC,CAAC;gBACF,GAAG,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC,CAAC;gBAE3D,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;gBAC9D,MAAM,iBAAiB,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBAEvD,MAAM,mBAAmB,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAED,OAAO,MAAM,iBAAiB,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QACjD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,sBAAsB,CAAC,SAAiB;IAC/C,OAAO,IAAI,CAAC,IAAI,CACd,SAAS,EACT,SAAS,EACT,cAAc,mBAAmB,CAAC,SAAS,CAAC,OAAO,CACpD,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,SAAqB;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,mDAAmD;IAC1E,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,eAAe,CACtB,SAAqB,EACrB,SAAiB;IAEjB,OAAO;QACL,SAAS;QACT,UAAU,EAAE,SAAS,CAAC,MAAM;QAC5B,WAAW,EAAE,kBAAkB,CAAC,SAAS,CAAC;KAC3C,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CACxB,CAA6B,EAC7B,CAA6B;IAE7B,OAAO,CACL,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS;QAC3B,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU;QAC7B,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,WAAW,CAChC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,mBAAmB,CAChC,SAAqB,EACrB,SAAiB;IAEjB,MAAM,SAAS,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IACpD,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QAClC,GAAG,CAAC,IAAI,CAAC,gCAAgC,SAAS,EAAE,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAa,CAAwB,CAAC;QAC/D,IAAI,KAAK,CAAC,OAAO,KAAK,aAAa,EAAE,CAAC;YACpC,GAAG,CAAC,IAAI,CACN,0CAA0C,KAAK,CAAC,OAAO,UAAU,aAAa,kBAAkB,CACjG,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,IAAI,CACN,yDAAyD;gBACvD,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CACxF,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;YAChC,KAAK,CAAC,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAC5C,CAAC;YACD,GAAG,CAAC,IAAI,CACN,4BAA4B,KAAK,CAAC,UAAU,EAAE,MAAM,sCAAsC,SAAS,CAAC,MAAM,kBAAkB,CAC7H,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,GAAG,CAAC,IAAI,CACN,yBAAyB,KAAK,CAAC,UAAU,CAAC,MAAM,wBAAwB,SAAS,EAAE,CACpF,CAAC;QACF,OAAO,KAAK,CAAC,UAAU,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CACN,oCAAoC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,mBAAmB,CACxG,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,mBAAmB,CAChC,SAAqB,EACrB,OAAmB,EACnB,SAAiB;IAEjB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;IACT,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QACxC,GAAG,CAAC,IAAI,CACN,uCAAuC,OAAO,CAAC,MAAM,eAAe,SAAS,CAAC,MAAM,YAAY,CACjG,CAAC;QACF,OAAO;IACT,CAAC;IACD,MAAM,SAAS,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IACpD,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IACzC,MAAM,KAAK,GAAwB;QACjC,OAAO,EAAE,aAAa;QACtB,WAAW,EAAE,eAAe,CAAC,SAAS,EAAE,SAAS,CAAC;QAClD,UAAU,EAAE,OAAO;KACpB,CAAC;IACF,MAAM,OAAO,GAAG,GAAG,SAAS,MAAM,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QACnD,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,GAAG,CAAC,IAAI,CACN,2BAA2B,OAAO,CAAC,MAAM,gBAAgB,SAAS,EAAE,CACrE,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,IAAI,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3B,CAAC;YAAC,OAAO,UAAU,EAAE,CAAC;gBACpB,GAAG,CAAC,IAAI,CACN,qCAAqC,OAAO,KAC1C,UAAU,YAAY,KAAK;oBACzB,CAAC,CAAC,UAAU,CAAC,OAAO;oBACpB,CAAC,CAAC,MAAM,CAAC,UAAU,CACvB,EAAE,CACH,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,aAAa,CAC1B,SAAqB,EACrB,SAAkB,KAAK;IAEvB,IAAI,CAAC;QACH,uCAAuC;QACvC,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;QAE9C,8BAA8B;QAC9B,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC5C,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,QAAQ,EAAE,GAAG,CAAC,QAAQ;SACvB,CAAC,CAAC,CAAC;QAEJ,IAAI,aAAa,GAAG,aAAa,CAAC;QAElC,oEAAoE;QACpE,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC;gBACH,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CACxC,cAAc,EACd,OAAO,CACR,CAAW,CAAC;gBACb,IAAI,eAAe,EAAE,CAAC;oBACpB,MAAM,kBAAkB,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;oBACvD,aAAa,GAAG,CAAC,GAAG,kBAAkB,EAAE,GAAG,aAAa,CAAC,CAAC;oBAC1D,GAAG,CAAC,IAAI,CACN,aAAa,aAAa,CAAC,MAAM,0BAA0B,kBAAkB,CAAC,MAAM,YAAY,CACjG,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,OAAO,SAAS,EAAE,CAAC;gBACnB,GAAG,CAAC,IAAI,CACN,wDAAwD,EACxD,SAAS,CACV,CAAC;YACJ,CAAC;QACH,CAAC;QAED,gBAAgB;QAChB,MAAM,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC;QAClE,GAAG,CAAC,IAAI,CACN,GACE,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAC3B,iBAAiB,cAAc,YAAY,aAAa,CAAC,MAAM,GAAG,CACnE,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB;IAC/B,IAAI,CAAC;QACH,IAAI,MAAM,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;YACpC,MAAM,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;YACvD,GAAG,CAAC,IAAI,CAAC,6BAA6B,cAAc,EAAE,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;QACnD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,aAAa;IAC1B,IAAI,CAAC;QACH,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;YACvC,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,iBAAiB;QACjB,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC,CAAW,CAAC;QACnE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEnC,8BAA8B;QAC9B,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAC9B,CAAC,GAAQ,EAAE,EAAE,CACX,IAAI,QAAQ,CAAC;YACX,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,QAAQ,EAAE,GAAG,CAAC,QAAQ;SACvB,CAAC,CACL,CAAC;QAEF,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,0BAA0B,cAAc,EAAE,CAAC,CAAC;QACxE,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,uBAAuB,CAAC,YAAoB;IACzD,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAW,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,yCACE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,EACF,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,kEAAkE;AAClE,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACpD,+BAA+B;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,YAAoB,CAAC;IACzB,IAAI,SAAS,GAAG,IAAI,CAAC,CAAC,qBAAqB;IAC3C,IAAI,YAAY,GAAG,GAAG,CAAC,CAAC,kBAAkB;IAC1C,IAAI,eAAe,GAAG,KAAK,CAAC;IAE5B,sCAAsC;IACtC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,oBAAoB;QACpB,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAEpD,oDAAoD;QACpD,IACE,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAC/B,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,EAAE,EACtC,CAAC;YACD,eAAe,GAAG,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,0CAA0C;QAC1C,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC3C,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAC5D,CAAC;IAED,6BAA6B;IAC7B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC;IAED,0BAA0B;IAC1B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,4CAA4C;IAC5C,GAAG,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;IAEzE,2BAA2B;IAC3B,IAAI,eAAe,EAAE,CAAC;QACpB,+BAA+B;QAC/B,GAAG,CAAC,IAAI,CAAC,kCAAkC,YAAY,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,4CAA4C;QAC5C,GAAG,CAAC,IAAI,CAAC,6CAA6C,YAAY,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,qBAAqB,CAC9C,YAAY,EACZ,SAAS,EACT,YAAY,CACb,CAAC;YACF,GAAG,CAAC,IAAI,CAAC,wBAAwB,YAAY,CAAC,MAAM,iBAAiB,CAAC,CAAC;YACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;AACH,CAAC"}
|